feat(web): centralize snippet draft fields

This commit is contained in:
JzoNg 2026-06-23 11:21:08 +08:00
parent 0bfce31e25
commit 362129e53b
16 changed files with 138 additions and 150 deletions

View File

@ -28,13 +28,12 @@ import { DETAIL_SIDEBAR_STORAGE_KEY } from '../storage'
const activeEdgeClassName = 'before:pointer-events-none'
type SnippetNavigationTestState = {
fields: SnippetInputField[]
onFieldsChange?: (fields: SnippetInputField[]) => void
readonly: boolean
snippet?: SnippetDetail
}
const { mockIsAgentV2Enabled, mockSnippetFieldsChange, mockSwitchWorkspace, mockToastSuccess, hotkeyRegistrations, snippetNavigationState } = vi.hoisted(() => ({
const { mockIsAgentV2Enabled, mockSnippetFieldsChange, mockSwitchWorkspace, mockToastSuccess, hotkeyRegistrations, snippetDraftState, snippetNavigationState } = vi.hoisted(() => ({
mockSwitchWorkspace: vi.fn(),
mockSnippetFieldsChange: vi.fn(),
mockToastSuccess: vi.fn(),
@ -43,8 +42,10 @@ const { mockIsAgentV2Enabled, mockSnippetFieldsChange, mockSwitchWorkspace, mock
handler: (event: { preventDefault: () => void }) => void
options?: { ignoreInputs?: boolean }
}>(),
snippetDraftState: {
inputFields: [],
} as { inputFields: SnippetInputField[] },
snippetNavigationState: {
fields: [],
readonly: true,
snippet: undefined,
onFieldsChange: undefined,
@ -204,6 +205,10 @@ vi.mock('@/app/components/snippets/store', () => ({
useSnippetDetailStore: (selector: (state: SnippetNavigationTestState) => unknown) => selector(snippetNavigationState),
}))
vi.mock('@/app/components/snippets/draft-store', () => ({
useSnippetDraftStore: (selector: (state: typeof snippetDraftState) => unknown) => selector(snippetDraftState),
}))
vi.mock('@/app/components/snippets/components/snippet-sidebar', () => ({
SnippetSidebarContent: ({
fields,
@ -423,7 +428,7 @@ describe('MainNav', () => {
})
mockSwitchWorkspace.mockReturnValue(new Promise(() => {}))
hotkeyRegistrations.clear()
snippetNavigationState.fields = []
snippetDraftState.inputFields = []
snippetNavigationState.onFieldsChange = undefined
snippetNavigationState.readonly = true
snippetNavigationState.snippet = undefined
@ -634,7 +639,7 @@ describe('MainNav', () => {
it('replaces global navigation with snippet detail navigation on snippet routes', () => {
mockPathname = '/snippets/snippet-1/orchestrate'
snippetNavigationState.fields = snippetFields
snippetDraftState.inputFields = snippetFields
snippetNavigationState.onFieldsChange = mockSnippetFieldsChange
snippetNavigationState.readonly = false
snippetNavigationState.snippet = snippet
@ -661,7 +666,7 @@ describe('MainNav', () => {
it('collapses snippet detail navigation from the top-right toggle', () => {
mockPathname = '/snippets/snippet-1/orchestrate'
snippetNavigationState.fields = snippetFields
snippetDraftState.inputFields = snippetFields
snippetNavigationState.onFieldsChange = mockSnippetFieldsChange
snippetNavigationState.snippet = snippet

View File

@ -15,6 +15,7 @@ import { useStore as useAppStore } from '@/app/components/app/store'
import DifyLogo from '@/app/components/base/logo/dify-logo'
import EnvNav from '@/app/components/header/env-nav'
import { SnippetSidebarContent } from '@/app/components/snippets/components/snippet-sidebar'
import { useSnippetDraftStore } from '@/app/components/snippets/draft-store'
import { useSnippetDetailStore } from '@/app/components/snippets/store'
import { useAppContext } from '@/context/app-context'
import { AgentDetailSection, AgentDetailTop } from '@/features/agent-v2/agent-detail/navigation'
@ -101,11 +102,11 @@ const MainNav = ({
const showSnippetDetailNavigation = isSnippetDetailPathname(pathname)
const showDetailNavigation = showAppDetailNavigation || showDatasetDetailNavigation || showAgentDetailNavigation || showDeploymentDetailNavigation || showSnippetDetailNavigation
const snippetNavigation = useSnippetDetailStore(useShallow(state => ({
fields: state.fields,
onFieldsChange: state.onFieldsChange,
readonly: state.readonly,
snippet: state.snippet,
})))
const snippetInputFields = useSnippetDraftStore(state => state.inputFields)
const { hasAppDetail, setAppDetail } = useAppStore(useShallow(state => ({
hasAppDetail: !!state.appDetail,
setAppDetail: state.setAppDetail,
@ -307,7 +308,7 @@ const MainNav = ({
? (
<SnippetSidebarContent
snippet={snippetNavigation.snippet}
fields={snippetNavigation.fields}
fields={snippetInputFields}
readonly={snippetNavigation.readonly}
onFieldsChange={snippetNavigation.onFieldsChange}
/>

View File

@ -6,13 +6,13 @@ import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import { renderWorkflowComponent } from '@/app/components/workflow/__tests__/workflow-test-env'
import { BlockEnum } from '@/app/components/workflow/types'
import { PipelineInputVarType } from '@/models/pipeline'
import { useSnippetDraftStore } from '../../draft-store'
import SnippetMain from '../snippet-main'
const mockSyncInputFieldsDraft = vi.fn()
const mockDoSyncWorkflowDraft = vi.fn()
const mockSyncWorkflowDraftWhenPageClose = vi.fn()
const mockReset = vi.fn()
const mockSetFields = vi.fn()
const mockSetNavigationState = vi.fn()
const mockPublishSnippetMutateAsync = vi.fn()
const mockFetchInspectVars = vi.fn()
@ -52,11 +52,9 @@ vi.mock('@langgenius/dify-ui/toast', () => ({
let capturedHooksStore: Record<string, unknown> | undefined
let capturedWorkflowNodes: WorkflowProps['nodes'] | undefined
let snippetDetailStoreState: {
fields: SnippetInputField[]
onFieldsChange?: (fields: SnippetInputField[]) => void
readonly: boolean
reset: typeof mockReset
setFields: typeof mockSetFields
setNavigationState: typeof mockSetNavigationState
snippet?: SnippetDetail
snippetId?: string
@ -277,11 +275,10 @@ describe('SnippetMain', () => {
})
capturedHooksStore = undefined
capturedWorkflowNodes = undefined
useSnippetDraftStore.getState().reset()
snippetDetailStoreState = {
fields: [...payload.inputFields],
readonly: true,
reset: mockReset,
setFields: mockSetFields,
setNavigationState: mockSetNavigationState,
}
})

View File

@ -1,15 +1,10 @@
import type { SnippetInputField } from '@/models/snippet'
import { act, renderHook } from '@testing-library/react'
import { PipelineInputVarType } from '@/models/pipeline'
import { useSnippetDraftStore } from '../../../draft-store'
import { useSnippetInputFieldActions } from '../use-snippet-input-field-actions'
const mockSyncInputFieldsDraft = vi.fn()
const mockSetFields = vi.fn()
let snippetDetailStoreState: {
fields: SnippetInputField[]
setFields: typeof mockSetFields
}
vi.mock('../../../hooks/use-nodes-sync-draft', () => ({
useNodesSyncDraft: () => ({
@ -17,10 +12,6 @@ vi.mock('../../../hooks/use-nodes-sync-draft', () => ({
}),
}))
vi.mock('../../../store', () => ({
useSnippetDetailStore: (selector: (state: typeof snippetDetailStoreState) => unknown) => selector(snippetDetailStoreState),
}))
const createField = (overrides: Partial<SnippetInputField> = {}): SnippetInputField => ({
type: PipelineInputVarType.textInput,
label: 'Blog URL',
@ -32,19 +23,13 @@ const createField = (overrides: Partial<SnippetInputField> = {}): SnippetInputFi
describe('useSnippetInputFieldActions', () => {
beforeEach(() => {
vi.clearAllMocks()
snippetDetailStoreState = {
fields: [],
setFields: mockSetFields,
}
mockSetFields.mockImplementation((fields: SnippetInputField[]) => {
snippetDetailStoreState.fields = fields
})
useSnippetDraftStore.getState().reset()
mockSyncInputFieldsDraft.mockResolvedValue(undefined)
})
describe('Field sync', () => {
it('should update fields and sync the draft', () => {
snippetDetailStoreState.fields = [createField()]
useSnippetDraftStore.getState().setInputFields([createField()])
const { result } = renderHook(() => useSnippetInputFieldActions({
snippetId: 'snippet-1',
}))
@ -60,8 +45,8 @@ describe('useSnippetInputFieldActions', () => {
result.current.handleFieldsChange(nextFields)
})
expect(result.current.fields).toEqual([createField()])
expect(mockSetFields).toHaveBeenCalledWith(nextFields)
expect(result.current.fields).toEqual(nextFields)
expect(useSnippetDraftStore.getState().inputFields).toEqual(nextFields)
expect(mockSyncInputFieldsDraft).toHaveBeenCalledWith(nextFields, {
onRefresh: expect.any(Function),
})

View File

@ -1,8 +1,8 @@
import type { SnippetInputField } from '@/models/snippet'
import { useCallback } from 'react'
import { useShallow } from 'zustand/react/shallow'
import { useSnippetDraftStore } from '../../draft-store'
import { useNodesSyncDraft } from '../../hooks/use-nodes-sync-draft'
import { useSnippetDetailStore } from '../../store'
type UseSnippetInputFieldActionsOptions = {
canEdit?: boolean
@ -15,25 +15,25 @@ export const useSnippetInputFieldActions = ({
}: UseSnippetInputFieldActionsOptions) => {
const { syncInputFieldsDraft } = useNodesSyncDraft(snippetId)
const {
fields,
setFields,
} = useSnippetDetailStore(useShallow(state => ({
fields: state.fields,
setFields: state.setFields,
inputFields,
setInputFields,
} = useSnippetDraftStore(useShallow(state => ({
inputFields: state.inputFields,
setInputFields: state.setInputFields,
})))
const handleFieldsChange = useCallback((newFields: SnippetInputField[]) => {
if (!canEdit)
return
setFields(newFields)
setInputFields(newFields)
void syncInputFieldsDraft(newFields, {
onRefresh: setFields,
onRefresh: setInputFields,
})
}, [canEdit, setFields, syncInputFieldsDraft])
}, [canEdit, setInputFields, syncInputFieldsDraft])
return {
fields,
fields: inputFields,
handleFieldsChange,
}
}

View File

@ -8,8 +8,8 @@ import { toast } from '@langgenius/dify-ui/toast'
import {
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
@ -23,6 +23,7 @@ import {
initialEdges,
initialNodes,
} from '@/app/components/workflow/utils'
import { useSnippetDraftStore } from '../draft-store'
import { useConfigsMap } from '../hooks/use-configs-map'
import { useGetRunAndTraceUrl } from '../hooks/use-get-run-and-trace-url'
import { useInspectVarsCrud } from '../hooks/use-inspect-vars-crud'
@ -136,16 +137,12 @@ 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, {
getInputFields: getCurrentInputFields,
})
} = useNodesSyncDraft(snippetId)
const workflowStore = useWorkflowStore()
const { handleRefreshWorkflowDraft } = useSnippetRefreshDraft(snippetId)
const {
@ -197,13 +194,18 @@ const SnippetMain = ({
}, [workflowAvailableNodesMetaData])
const {
reset,
setFields,
setNavigationState,
} = useSnippetDetailStore(useShallow(state => ({
reset: state.reset,
setFields: state.setFields,
setNavigationState: state.setNavigationState,
})))
const {
hydrateDraft,
setInputFields,
} = useSnippetDraftStore(useShallow(state => ({
hydrateDraft: state.hydrateDraft,
setInputFields: state.setInputFields,
})))
const {
fields,
handleFieldsChange: handleSnippetFieldsChange,
@ -224,10 +226,12 @@ const SnippetMain = ({
return () => reset()
}, [reset, snippetId])
useEffect(() => {
currentInputFieldsRef.current = effectiveDraftPayload.inputFields
setFields(effectiveDraftPayload.inputFields)
}, [effectiveDraftPayload.inputFields, setFields, snippetId])
useLayoutEffect(() => {
hydrateDraft({
snippetId,
inputFields: effectiveDraftPayload.inputFields,
})
}, [effectiveDraftPayload.inputFields, hydrateDraft, snippetId])
useEffect(() => {
workflowStore.setState({ canvasReadOnly: false })
@ -254,7 +258,6 @@ const SnippetMain = ({
) => syncWorkflowDraft(...args), [syncWorkflowDraft])
const handleFieldsChange = useCallback((nextFields: SnippetInputField[]) => {
currentInputFieldsRef.current = nextFields
handleSnippetFieldsChange(nextFields)
}, [handleSnippetFieldsChange])
@ -286,7 +289,6 @@ const SnippetMain = ({
? syncedDraftPayload.input_fields as SnippetInputField[]
: fields
currentInputFieldsRef.current = inputFields
setLocalDraftState({
payload: {
...draftPayload,
@ -297,8 +299,8 @@ const SnippetMain = ({
edges: initialEdges(draftGraph.edges, draftGraph.nodes),
viewport: draftGraph.viewport,
})
setFields(inputFields)
}, [draftPayload, fields, setFields])
setInputFields(inputFields)
}, [draftPayload, fields, setInputFields])
const hooksStore = useMemo(() => {
return {

View File

@ -0,0 +1,36 @@
import type { SnippetInputField } from '@/models/snippet'
import { PipelineInputVarType } from '@/models/pipeline'
import { useSnippetDraftStore } from '..'
const createField = (variable: string): SnippetInputField => ({
label: variable,
variable,
type: PipelineInputVarType.textInput,
required: true,
})
describe('useSnippetDraftStore', () => {
beforeEach(() => {
useSnippetDraftStore.getState().reset()
})
it('should store and reset snippet input fields', () => {
const inputFields = [
createField('topic'),
createField('audience'),
]
useSnippetDraftStore.getState().hydrateDraft({
snippetId: 'snippet-1',
inputFields,
})
expect(useSnippetDraftStore.getState().snippetId).toBe('snippet-1')
expect(useSnippetDraftStore.getState().inputFields).toEqual(inputFields)
useSnippetDraftStore.getState().reset()
expect(useSnippetDraftStore.getState().snippetId).toBeUndefined()
expect(useSnippetDraftStore.getState().inputFields).toEqual([])
})
})

View File

@ -0,0 +1,24 @@
'use client'
import type { SnippetInputField } from '@/models/snippet'
import { create } from 'zustand'
type SnippetDraftState = {
snippetId?: string
inputFields: SnippetInputField[]
hydrateDraft: (payload: { snippetId: string, inputFields: SnippetInputField[] }) => void
setInputFields: (inputFields: SnippetInputField[]) => void
reset: () => void
}
const initialState = {
snippetId: undefined,
inputFields: [] as SnippetInputField[],
}
export const useSnippetDraftStore = create<SnippetDraftState>(set => ({
...initialState,
hydrateDraft: ({ snippetId, inputFields }) => set({ snippetId, inputFields }),
setInputFields: inputFields => set({ inputFields }),
reset: () => set(initialState),
}))

View File

@ -1,7 +1,7 @@
import type { SnippetInputField } from '@/models/snippet'
import { act, renderHook } from '@testing-library/react'
import { PipelineInputVarType } from '@/models/pipeline'
import { useSnippetDetailStore } from '../../store'
import { useSnippetDraftStore } from '../../draft-store'
import { useNodesSyncDraft } from '../use-nodes-sync-draft'
const mockGetNodes = vi.fn()
@ -112,9 +112,7 @@ describe('snippet/use-nodes-sync-draft', () => {
mockSetSyncWorkflowDraftHash.mockImplementation((hash: string) => {
workflowStoreState.syncWorkflowDraftHash = hash
})
useSnippetDetailStore.setState({
fields: [createInputField('topic')],
})
useSnippetDraftStore.getState().setInputFields([createInputField('topic')])
})
it('should include current input_fields when syncing the draft graph', async () => {
@ -139,25 +137,16 @@ 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: [],
it('should keep draft input_fields when the navigation store is reset during route leave', () => {
const { result } = renderHook(() => useNodesSyncDraft('snippet-1'))
act(() => {
result.current.syncWorkflowDraftWhenPageClose()
})
const inputFields = [createInputField('topic')]
const { result } = renderHook(() => useNodesSyncDraft('snippet-1', {
getInputFields: () => inputFields,
expect(mockPostWithKeepalive).toHaveBeenCalledWith('/api/snippets/snippet-1/workflows/draft', expect.objectContaining({
input_fields: [createInputField('topic')],
}))
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 () => {
@ -267,22 +256,4 @@ 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,
}))
})
})

View File

@ -31,8 +31,8 @@ vi.mock('@/app/components/workflow/store', () => ({
}),
}))
vi.mock('../../store', () => ({
useSnippetDetailStore: {
vi.mock('../../draft-store', () => ({
useSnippetDraftStore: {
setState: (...args: unknown[]) => mockSnippetSetState(...args),
},
}))
@ -75,7 +75,7 @@ describe('useSnippetRefreshDraft', () => {
})
expect(mockFetchSnippetDraftWorkflow).toHaveBeenCalledWith('snippet-1')
expect(mockSnippetSetState).toHaveBeenCalledWith({
fields: [],
inputFields: [],
})
expect(mockSetSyncWorkflowDraftHash).toHaveBeenCalledWith('draft-hash')
expect(mockSetDraftUpdatedAt).toHaveBeenCalledWith(1_712_345_678)

View File

@ -4,7 +4,7 @@ import { act } from 'react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
import { PipelineInputVarType } from '@/models/pipeline'
import { useSnippetDetailStore } from '../../store'
import { useSnippetDraftStore } from '../../draft-store'
import { useSnippetStartRun } from '../use-snippet-start-run'
const mockWorkflowStoreGetState = vi.fn()
@ -39,7 +39,7 @@ const inputFields: SnippetInputField[] = [
describe('useSnippetStartRun', () => {
beforeEach(() => {
vi.clearAllMocks()
useSnippetDetailStore.getState().reset()
useSnippetDraftStore.getState().reset()
mockWorkflowStoreGetState.mockReturnValue({
workflowRunningData: undefined,
showDebugAndPreviewPanel: false,
@ -51,7 +51,7 @@ describe('useSnippetStartRun', () => {
})
it('should open the debug panel and input form when snippet has input fields', () => {
useSnippetDetailStore.setState({ fields: inputFields })
useSnippetDraftStore.getState().setInputFields(inputFields)
const { result } = renderHook(() => useSnippetStartRun({
handleRun: mockHandleRun,
@ -83,7 +83,7 @@ describe('useSnippetStartRun', () => {
})
it('should use current snippet input fields from the store before starting a run', () => {
useSnippetDetailStore.setState({ fields: inputFields })
useSnippetDraftStore.getState().setInputFields(inputFields)
const { result } = renderHook(() => useSnippetStartRun({
handleRun: mockHandleRun,
@ -99,7 +99,7 @@ describe('useSnippetStartRun', () => {
})
it('should close the panel when debug panel is already open', () => {
useSnippetDetailStore.setState({ fields: inputFields })
useSnippetDraftStore.getState().setInputFields(inputFields)
mockWorkflowStoreGetState.mockReturnValue({
workflowRunningData: undefined,
@ -122,7 +122,7 @@ describe('useSnippetStartRun', () => {
})
it('should do nothing when workflow is already running', () => {
useSnippetDetailStore.setState({ fields: inputFields })
useSnippetDraftStore.getState().setInputFields(inputFields)
mockWorkflowStoreGetState.mockReturnValue({
workflowRunningData: {

View File

@ -10,7 +10,7 @@ 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 { useSnippetDraftStore } from '../draft-store'
import { useSnippetRefreshDraft } from './use-snippet-refresh-draft'
const isSyncConflictError = (error: unknown): error is { bodyUsed: boolean, json: () => Promise<{ code?: string }> } => {
@ -25,10 +25,6 @@ type SyncInputFieldsDraftCallback = SyncDraftCallback & {
onRefresh?: (inputFields: SnippetInputField[]) => void
}
type UseNodesSyncDraftOptions = {
getInputFields?: () => SnippetInputField[]
}
const snippetDraftSyncQueues = new Map<string, Promise<unknown>>()
const enqueueSnippetDraftSync = <Result>(
@ -48,18 +44,17 @@ const enqueueSnippetDraftSync = <Result>(
return nextTask
}
export const useNodesSyncDraft = (snippetId: string, options: UseNodesSyncDraftOptions = {}) => {
export const useNodesSyncDraft = (snippetId: string) => {
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 ?? getInputFields?.() ?? useSnippetDetailStore.getState().fields,
input_fields: inputFields ?? useSnippetDraftStore.getState().inputFields,
}
}, [getInputFields])
}, [])
const getDraftSyncPayload = useCallback((inputFields?: SnippetInputField[]) => {
const {

View File

@ -5,7 +5,7 @@ import { useCallback } from 'react'
import { useWorkflowUpdate } from '@/app/components/workflow/hooks'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { fetchSnippetDraftWorkflow } from '@/service/use-snippet-workflows'
import { useSnippetDetailStore } from '../store'
import { useSnippetDraftStore } from '../draft-store'
export const useSnippetRefreshDraft = (snippetId: string) => {
const workflowStore = useWorkflowStore()
@ -36,8 +36,8 @@ export const useSnippetRefreshDraft = (snippetId: string) => {
edges: response.graph?.edges || [],
viewport: response.graph?.viewport || { x: 0, y: 0, zoom: 1 },
} as WorkflowDataUpdater)
useSnippetDetailStore.setState({
fields: inputFields,
useSnippetDraftStore.setState({
inputFields,
})
setSyncWorkflowDraftHash(response.hash)
setDraftUpdatedAt(response.updated_at)

View File

@ -3,7 +3,7 @@ import { useCallback } from 'react'
import { useWorkflowInteractions } from '@/app/components/workflow/hooks'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
import { useSnippetDetailStore } from '../store'
import { useSnippetDraftStore } from '../draft-store'
type UseSnippetStartRunOptions = {
handleRun: (params: SnippetDraftRunPayload) => void
@ -38,7 +38,7 @@ export const useSnippetStartRun = ({
setShowDebugAndPreviewPanel(true)
const currentInputFields = useSnippetDetailStore.getState().fields
const currentInputFields = useSnippetDraftStore.getState().inputFields
if (currentInputFields.length > 0) {
setShowInputsPanel(true)

View File

@ -1,14 +1,6 @@
import type { SnippetDetail, SnippetInputField } from '@/models/snippet'
import { PipelineInputVarType } from '@/models/pipeline'
import type { SnippetDetail } from '@/models/snippet'
import { useSnippetDetailStore } from '..'
const createField = (variable: string): SnippetInputField => ({
label: variable,
variable,
type: PipelineInputVarType.textInput,
required: true,
})
const snippet: SnippetDetail = {
id: 'snippet-1',
name: 'Snippet',
@ -23,21 +15,6 @@ describe('useSnippetDetailStore', () => {
useSnippetDetailStore.getState().reset()
})
it('should store and reset snippet input fields', () => {
const fields = [
createField('topic'),
createField('audience'),
]
useSnippetDetailStore.getState().setFields(fields)
expect(useSnippetDetailStore.getState().fields).toEqual(fields)
useSnippetDetailStore.getState().reset()
expect(useSnippetDetailStore.getState().fields).toEqual([])
})
it('should store and reset snippet navigation state', () => {
const onFieldsChange = vi.fn()
@ -58,7 +35,6 @@ describe('useSnippetDetailStore', () => {
useSnippetDetailStore.getState().reset()
expect(useSnippetDetailStore.getState()).toMatchObject({
fields: [],
readonly: true,
snippet: undefined,
snippetId: undefined,

View File

@ -11,14 +11,11 @@ type SnippetNavigationState = {
}
type SnippetDetailUIState = {
fields: SnippetInputField[]
setFields: (fields: SnippetInputField[]) => void
setNavigationState: (state: SnippetNavigationState) => void
reset: () => void
} & SnippetNavigationState
const initialState = {
fields: [] as SnippetInputField[],
readonly: true,
snippet: undefined,
snippetId: undefined,
@ -27,7 +24,6 @@ const initialState = {
export const useSnippetDetailStore = create<SnippetDetailUIState>(set => ({
...initialState,
setFields: fields => set({ fields }),
setNavigationState: state => set(state),
reset: () => set(initialState),
}))