mirror of
https://github.com/langgenius/dify.git
synced 2026-01-08 07:14:14 +00:00
This commit fixes issue #26500 where the conversation opener feature doesn't preserve its enabled state and doesn't work correctly. Changes: 1. Updated feature initialization logic to check for both opening_statement and suggested_questions when determining if the feature is enabled 2. Simplified save logic to always send the actual content instead of clearing it when disabled 3. Added automatic modal opening when user toggles feature on without content 4. Added logic to automatically set enabled state based on content presence 5. Added logic to disable feature if user cancels modal without adding content This ensures that: - The feature's enabled state is correctly determined from saved content - Users must add content (opening statement or suggested questions) to enable the feature - The enabled state is automatically managed based on content presence - The feature state persists correctly across page refreshes
149 lines
4.5 KiB
TypeScript
149 lines
4.5 KiB
TypeScript
import { useCallback } from 'react'
|
|
import produce from 'immer'
|
|
import { useStoreApi } from 'reactflow'
|
|
import { useParams } from 'next/navigation'
|
|
import {
|
|
useWorkflowStore,
|
|
} from '@/app/components/workflow/store'
|
|
import { BlockEnum } from '@/app/components/workflow/types'
|
|
import {
|
|
useNodesReadOnly,
|
|
} from '@/app/components/workflow/hooks/use-workflow'
|
|
import { syncWorkflowDraft } from '@/service/workflow'
|
|
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
|
import { API_PREFIX } from '@/config'
|
|
import { useWorkflowRefreshDraft } from '.'
|
|
|
|
export const useNodesSyncDraft = () => {
|
|
const store = useStoreApi()
|
|
const workflowStore = useWorkflowStore()
|
|
const featuresStore = useFeaturesStore()
|
|
const { getNodesReadOnly } = useNodesReadOnly()
|
|
const { handleRefreshWorkflowDraft } = useWorkflowRefreshDraft()
|
|
const params = useParams()
|
|
|
|
const getPostParams = useCallback(() => {
|
|
const {
|
|
getNodes,
|
|
edges,
|
|
transform,
|
|
} = store.getState()
|
|
const nodes = getNodes()
|
|
const [x, y, zoom] = transform
|
|
const {
|
|
appId,
|
|
conversationVariables,
|
|
environmentVariables,
|
|
syncWorkflowDraftHash,
|
|
} = workflowStore.getState()
|
|
|
|
if (appId && !!nodes.length) {
|
|
const hasStartNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
|
|
|
if (!hasStartNode)
|
|
return
|
|
|
|
const features = featuresStore!.getState().features
|
|
const producedNodes = produce(nodes, (draft) => {
|
|
draft.forEach((node) => {
|
|
Object.keys(node.data).forEach((key) => {
|
|
if (key.startsWith('_'))
|
|
delete node.data[key]
|
|
})
|
|
})
|
|
})
|
|
const producedEdges = produce(edges.filter(edge => !edge.data?._isTemp), (draft) => {
|
|
draft.forEach((edge) => {
|
|
Object.keys(edge.data).forEach((key) => {
|
|
if (key.startsWith('_'))
|
|
delete edge.data[key]
|
|
})
|
|
})
|
|
})
|
|
return {
|
|
url: `/apps/${appId}/workflows/draft`,
|
|
params: {
|
|
graph: {
|
|
nodes: producedNodes,
|
|
edges: producedEdges,
|
|
viewport: {
|
|
x,
|
|
y,
|
|
zoom,
|
|
},
|
|
},
|
|
features: {
|
|
opening_statement: features.opening?.opening_statement || '',
|
|
suggested_questions: features.opening?.suggested_questions || [],
|
|
suggested_questions_after_answer: features.suggested,
|
|
text_to_speech: features.text2speech,
|
|
speech_to_text: features.speech2text,
|
|
retriever_resource: features.citation,
|
|
sensitive_word_avoidance: features.moderation,
|
|
file_upload: features.file,
|
|
},
|
|
environment_variables: environmentVariables,
|
|
conversation_variables: conversationVariables,
|
|
hash: syncWorkflowDraftHash,
|
|
},
|
|
}
|
|
}
|
|
}, [store, featuresStore, workflowStore])
|
|
|
|
const syncWorkflowDraftWhenPageClose = useCallback(() => {
|
|
if (getNodesReadOnly())
|
|
return
|
|
const postParams = getPostParams()
|
|
|
|
if (postParams) {
|
|
navigator.sendBeacon(
|
|
`${API_PREFIX}/apps/${params.appId}/workflows/draft?_token=${localStorage.getItem('console_token')}`,
|
|
JSON.stringify(postParams.params),
|
|
)
|
|
}
|
|
}, [getPostParams, params.appId, getNodesReadOnly])
|
|
|
|
const doSyncWorkflowDraft = useCallback(async (
|
|
notRefreshWhenSyncError?: boolean,
|
|
callback?: {
|
|
onSuccess?: () => void
|
|
onError?: () => void
|
|
onSettled?: () => void
|
|
},
|
|
) => {
|
|
if (getNodesReadOnly())
|
|
return
|
|
const postParams = getPostParams()
|
|
|
|
if (postParams) {
|
|
const {
|
|
setSyncWorkflowDraftHash,
|
|
setDraftUpdatedAt,
|
|
} = workflowStore.getState()
|
|
try {
|
|
const res = await syncWorkflowDraft(postParams)
|
|
setSyncWorkflowDraftHash(res.hash)
|
|
setDraftUpdatedAt(res.updated_at)
|
|
callback?.onSuccess && callback.onSuccess()
|
|
}
|
|
catch (error: any) {
|
|
if (error && error.json && !error.bodyUsed) {
|
|
error.json().then((err: any) => {
|
|
if (err.code === 'draft_workflow_not_sync' && !notRefreshWhenSyncError)
|
|
handleRefreshWorkflowDraft()
|
|
})
|
|
}
|
|
callback?.onError && callback.onError()
|
|
}
|
|
finally {
|
|
callback?.onSettled && callback.onSettled()
|
|
}
|
|
}
|
|
}, [workflowStore, getPostParams, getNodesReadOnly, handleRefreshWorkflowDraft])
|
|
|
|
return {
|
|
doSyncWorkflowDraft,
|
|
syncWorkflowDraftWhenPageClose,
|
|
}
|
|
}
|