|
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, |
|
} |
|
} |
|
|