mirror of
https://github.com/langgenius/dify.git
synced 2026-06-24 13:01:16 +08:00
feat(web): preserve snippet draft fields
This commit is contained in:
parent
cd2c40e7c0
commit
0bfce31e25
@ -9,6 +9,7 @@ import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -135,12 +136,16 @@ const SnippetMain = ({
|
||||
const effectiveDraftNodes = localDraftState?.nodes ?? draftNodes
|
||||
const effectiveDraftEdges = localDraftState?.edges ?? draftEdges
|
||||
const effectiveDraftViewport = localDraftState?.viewport ?? draftViewport
|
||||
const currentInputFieldsRef = useRef<SnippetInputField[]>(effectiveDraftPayload.inputFields)
|
||||
const { graph, snippet } = effectiveDraftPayload
|
||||
const canSave = currentCanvasNodeCount > 0
|
||||
const getCurrentInputFields = useCallback(() => currentInputFieldsRef.current, [])
|
||||
const {
|
||||
doSyncWorkflowDraft: syncWorkflowDraft,
|
||||
syncWorkflowDraftWhenPageClose,
|
||||
} = useNodesSyncDraft(snippetId)
|
||||
} = useNodesSyncDraft(snippetId, {
|
||||
getInputFields: getCurrentInputFields,
|
||||
})
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { handleRefreshWorkflowDraft } = useSnippetRefreshDraft(snippetId)
|
||||
const {
|
||||
@ -220,6 +225,7 @@ const SnippetMain = ({
|
||||
}, [reset, snippetId])
|
||||
|
||||
useEffect(() => {
|
||||
currentInputFieldsRef.current = effectiveDraftPayload.inputFields
|
||||
setFields(effectiveDraftPayload.inputFields)
|
||||
}, [effectiveDraftPayload.inputFields, setFields, snippetId])
|
||||
|
||||
@ -248,6 +254,7 @@ const SnippetMain = ({
|
||||
) => syncWorkflowDraft(...args), [syncWorkflowDraft])
|
||||
|
||||
const handleFieldsChange = useCallback((nextFields: SnippetInputField[]) => {
|
||||
currentInputFieldsRef.current = nextFields
|
||||
handleSnippetFieldsChange(nextFields)
|
||||
}, [handleSnippetFieldsChange])
|
||||
|
||||
@ -279,6 +286,7 @@ const SnippetMain = ({
|
||||
? syncedDraftPayload.input_fields as SnippetInputField[]
|
||||
: fields
|
||||
|
||||
currentInputFieldsRef.current = inputFields
|
||||
setLocalDraftState({
|
||||
payload: {
|
||||
...draftPayload,
|
||||
|
||||
@ -139,6 +139,27 @@ describe('snippet/use-nodes-sync-draft', () => {
|
||||
expect(mockUseNodesReadOnlyByCanEdit).toHaveBeenCalledWith(true)
|
||||
})
|
||||
|
||||
it('should use provided input_fields when the snippet store is not initialized yet', async () => {
|
||||
useSnippetDetailStore.setState({
|
||||
fields: [],
|
||||
})
|
||||
const inputFields = [createInputField('topic')]
|
||||
const { result } = renderHook(() => useNodesSyncDraft('snippet-1', {
|
||||
getInputFields: () => inputFields,
|
||||
}))
|
||||
|
||||
await act(async () => {
|
||||
await result.current.doSyncWorkflowDraft()
|
||||
})
|
||||
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenCalledWith({
|
||||
params: { snippetId: 'snippet-1' },
|
||||
body: expect.objectContaining({
|
||||
input_fields: inputFields,
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
it('should snapshot graph before queued draft sync executes', async () => {
|
||||
deferSerialCallbacks = true
|
||||
const { result } = renderHook(() => useNodesSyncDraft('snippet-1'))
|
||||
@ -246,4 +267,22 @@ describe('snippet/use-nodes-sync-draft', () => {
|
||||
hash: 'draft-hash',
|
||||
})
|
||||
})
|
||||
|
||||
it('should use provided input_fields when syncing on page close before the snippet store initializes', () => {
|
||||
useSnippetDetailStore.setState({
|
||||
fields: [],
|
||||
})
|
||||
const inputFields = [createInputField('topic')]
|
||||
const { result } = renderHook(() => useNodesSyncDraft('snippet-1', {
|
||||
getInputFields: () => inputFields,
|
||||
}))
|
||||
|
||||
act(() => {
|
||||
result.current.syncWorkflowDraftWhenPageClose()
|
||||
})
|
||||
|
||||
expect(mockPostWithKeepalive).toHaveBeenCalledWith('/api/snippets/snippet-1/workflows/draft', expect.objectContaining({
|
||||
input_fields: inputFields,
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@ -8,6 +8,7 @@ import { useNodesReadOnlyByCanEdit } from '@/app/components/workflow/hooks/use-w
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { API_PREFIX } from '@/config'
|
||||
import { consoleClient } from '@/service/client'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { postWithKeepalive } from '@/service/fetch'
|
||||
import { useSnippetDetailStore } from '../store'
|
||||
import { useSnippetRefreshDraft } from './use-snippet-refresh-draft'
|
||||
@ -24,6 +25,10 @@ type SyncInputFieldsDraftCallback = SyncDraftCallback & {
|
||||
onRefresh?: (inputFields: SnippetInputField[]) => void
|
||||
}
|
||||
|
||||
type UseNodesSyncDraftOptions = {
|
||||
getInputFields?: () => SnippetInputField[]
|
||||
}
|
||||
|
||||
const snippetDraftSyncQueues = new Map<string, Promise<unknown>>()
|
||||
|
||||
const enqueueSnippetDraftSync = <Result>(
|
||||
@ -43,17 +48,18 @@ const enqueueSnippetDraftSync = <Result>(
|
||||
return nextTask
|
||||
}
|
||||
|
||||
export const useNodesSyncDraft = (snippetId: string) => {
|
||||
export const useNodesSyncDraft = (snippetId: string, options: UseNodesSyncDraftOptions = {}) => {
|
||||
const store = useStoreApi()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { getNodesReadOnly } = useNodesReadOnlyByCanEdit(true)
|
||||
const { handleRefreshWorkflowDraft } = useSnippetRefreshDraft(snippetId)
|
||||
const { getInputFields } = options
|
||||
|
||||
const getInputFieldsSyncPayload = useCallback((inputFields?: SnippetInputField[]) => {
|
||||
return {
|
||||
input_fields: inputFields ?? useSnippetDetailStore.getState().fields,
|
||||
input_fields: inputFields ?? getInputFields?.() ?? useSnippetDetailStore.getState().fields,
|
||||
}
|
||||
}, [])
|
||||
}, [getInputFields])
|
||||
|
||||
const getDraftSyncPayload = useCallback((inputFields?: SnippetInputField[]) => {
|
||||
const {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user