| import { useCallback } from 'react' | |
| import produce from 'immer' | |
| import { useStoreApi } from 'reactflow' | |
| import { useParams } from 'next/navigation' | |
| import { | |
| useStore, | |
| useWorkflowStore, | |
| } from '../store' | |
| import { BlockEnum } from '../types' | |
| import { useWorkflowUpdate } from '../hooks' | |
| import { | |
| useNodesReadOnly, | |
| } from './use-workflow' | |
| import { syncWorkflowDraft } from '@/service/workflow' | |
| import { useFeaturesStore } from '@/app/components/base/features/hooks' | |
| import { API_PREFIX } from '@/config' | |
| export const useNodesSyncDraft = () => { | |
| const store = useStoreApi() | |
| const workflowStore = useWorkflowStore() | |
| const featuresStore = useFeaturesStore() | |
| const { getNodesReadOnly } = useNodesReadOnly() | |
| const { handleRefreshWorkflowDraft } = useWorkflowUpdate() | |
| const debouncedSyncWorkflowDraft = useStore(s => s.debouncedSyncWorkflowDraft) | |
| const params = useParams() | |
| const getPostParams = useCallback(() => { | |
| const { | |
| getNodes, | |
| edges, | |
| transform, | |
| } = store.getState() | |
| const [x, y, zoom] = transform | |
| const { | |
| appId, | |
| conversationVariables, | |
| environmentVariables, | |
| syncWorkflowDraftHash, | |
| } = workflowStore.getState() | |
| if (appId) { | |
| const nodes = getNodes() | |
| 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, (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?.enabled ? (features.opening?.opening_statement || '') : '', | |
| suggested_questions: features.opening?.enabled ? (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) => { | |
| 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) | |
| } | |
| catch (error: any) { | |
| if (error && error.json && !error.bodyUsed) { | |
| error.json().then((err: any) => { | |
| if (err.code === 'draft_workflow_not_sync' && !notRefreshWhenSyncError) | |
| handleRefreshWorkflowDraft() | |
| }) | |
| } | |
| } | |
| } | |
| }, [workflowStore, getPostParams, getNodesReadOnly, handleRefreshWorkflowDraft]) | |
| const handleSyncWorkflowDraft = useCallback((sync?: boolean, notRefreshWhenSyncError?: boolean) => { | |
| if (getNodesReadOnly()) | |
| return | |
| if (sync) | |
| doSyncWorkflowDraft(notRefreshWhenSyncError) | |
| else | |
| debouncedSyncWorkflowDraft(doSyncWorkflowDraft) | |
| }, [debouncedSyncWorkflowDraft, doSyncWorkflowDraft, getNodesReadOnly]) | |
| return { | |
| doSyncWorkflowDraft, | |
| handleSyncWorkflowDraft, | |
| syncWorkflowDraftWhenPageClose, | |
| } | |
| } | |