mirror of
https://github.com/langgenius/dify.git
synced 2026-04-05 16:26:25 +08:00
feat(web): add variable inspect for snippet
This commit is contained in:
@@ -14,6 +14,24 @@ const mockSetPublishMenuOpen = vi.fn()
|
||||
const mockToggleInputPanel = vi.fn()
|
||||
const mockTogglePublishMenu = vi.fn()
|
||||
const mockPublishSnippetMutateAsync = vi.fn()
|
||||
const mockFetchInspectVars = vi.fn()
|
||||
const mockInspectVarsCrud = {
|
||||
hasNodeInspectVars: vi.fn(),
|
||||
hasSetInspectVar: vi.fn(),
|
||||
fetchInspectVarValue: vi.fn(),
|
||||
editInspectVarValue: vi.fn(),
|
||||
renameInspectVarName: vi.fn(),
|
||||
appendNodeInspectVars: vi.fn(),
|
||||
deleteInspectVar: vi.fn(),
|
||||
deleteNodeInspectorVars: vi.fn(),
|
||||
deleteAllInspectorVars: vi.fn(),
|
||||
isInspectVarEdited: vi.fn(),
|
||||
resetToLastRunVar: vi.fn(),
|
||||
invalidateSysVarValues: vi.fn(),
|
||||
resetConversationVar: vi.fn(),
|
||||
invalidateConversationVarValues: vi.fn(),
|
||||
}
|
||||
let capturedHooksStore: Record<string, unknown> | undefined
|
||||
|
||||
vi.mock('@/hooks/use-breakpoints', () => ({
|
||||
default: () => 'desktop',
|
||||
@@ -69,6 +87,16 @@ vi.mock('@/app/components/snippets/hooks/use-configs-map', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/hooks/use-fetch-workflow-inspect-vars', () => ({
|
||||
useSetWorkflowVarsWithValue: () => ({
|
||||
fetchInspectVars: mockFetchInspectVars,
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/snippets/hooks/use-inspect-vars-crud', () => ({
|
||||
useInspectVarsCrud: () => mockInspectVarsCrud,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/snippets/hooks/use-nodes-sync-draft', () => ({
|
||||
useNodesSyncDraft: () => ({
|
||||
doSyncWorkflowDraft: vi.fn(),
|
||||
@@ -111,9 +139,19 @@ vi.mock('@/app/components/evaluation', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow', () => ({
|
||||
WorkflowWithInnerContext: ({ children }: { children: React.ReactNode }) => (
|
||||
<div data-testid="workflow-inner-context">{children}</div>
|
||||
),
|
||||
WorkflowWithInnerContext: ({
|
||||
children,
|
||||
hooksStore,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
hooksStore?: Record<string, unknown>
|
||||
}) => {
|
||||
capturedHooksStore = hooksStore
|
||||
|
||||
return (
|
||||
<div data-testid="workflow-inner-context">{children}</div>
|
||||
)
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/snippets/components/snippet-children', () => ({
|
||||
@@ -193,6 +231,7 @@ describe('SnippetMain', () => {
|
||||
vi.clearAllMocks()
|
||||
mockSyncInputFieldsDraft.mockResolvedValue(undefined)
|
||||
mockPublishSnippetMutateAsync.mockResolvedValue(undefined)
|
||||
capturedHooksStore = undefined
|
||||
})
|
||||
|
||||
describe('Input Fields Sync', () => {
|
||||
@@ -243,4 +282,26 @@ describe('SnippetMain', () => {
|
||||
expect(mockSetPublishMenuOpen).toHaveBeenCalledWith(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Inspect Vars', () => {
|
||||
it('should pass inspect vars handlers to WorkflowWithInnerContext', () => {
|
||||
renderSnippetMain()
|
||||
|
||||
expect(capturedHooksStore?.fetchInspectVars).toBe(mockFetchInspectVars)
|
||||
expect(capturedHooksStore?.hasNodeInspectVars).toBe(mockInspectVarsCrud.hasNodeInspectVars)
|
||||
expect(capturedHooksStore?.hasSetInspectVar).toBe(mockInspectVarsCrud.hasSetInspectVar)
|
||||
expect(capturedHooksStore?.fetchInspectVarValue).toBe(mockInspectVarsCrud.fetchInspectVarValue)
|
||||
expect(capturedHooksStore?.editInspectVarValue).toBe(mockInspectVarsCrud.editInspectVarValue)
|
||||
expect(capturedHooksStore?.renameInspectVarName).toBe(mockInspectVarsCrud.renameInspectVarName)
|
||||
expect(capturedHooksStore?.appendNodeInspectVars).toBe(mockInspectVarsCrud.appendNodeInspectVars)
|
||||
expect(capturedHooksStore?.deleteInspectVar).toBe(mockInspectVarsCrud.deleteInspectVar)
|
||||
expect(capturedHooksStore?.deleteNodeInspectorVars).toBe(mockInspectVarsCrud.deleteNodeInspectorVars)
|
||||
expect(capturedHooksStore?.deleteAllInspectorVars).toBe(mockInspectVarsCrud.deleteAllInspectorVars)
|
||||
expect(capturedHooksStore?.isInspectVarEdited).toBe(mockInspectVarsCrud.isInspectVarEdited)
|
||||
expect(capturedHooksStore?.resetToLastRunVar).toBe(mockInspectVarsCrud.resetToLastRunVar)
|
||||
expect(capturedHooksStore?.invalidateSysVarValues).toBe(mockInspectVarsCrud.invalidateSysVarValues)
|
||||
expect(capturedHooksStore?.resetConversationVar).toBe(mockInspectVarsCrud.resetConversationVar)
|
||||
expect(capturedHooksStore?.invalidateConversationVarValues).toBe(mockInspectVarsCrud.invalidateConversationVarValues)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -21,9 +21,11 @@ import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import Evaluation from '@/app/components/evaluation'
|
||||
import { WorkflowWithInnerContext } from '@/app/components/workflow'
|
||||
import { useAvailableNodesMetaData } from '@/app/components/workflow-app/hooks'
|
||||
import { useSetWorkflowVarsWithValue } from '@/app/components/workflow/hooks/use-fetch-workflow-inspect-vars'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import { useConfigsMap } from '../hooks/use-configs-map'
|
||||
import { useInspectVarsCrud } from '../hooks/use-inspect-vars-crud'
|
||||
import { useNodesSyncDraft } from '../hooks/use-nodes-sync-draft'
|
||||
import { useSnippetRefreshDraft } from '../hooks/use-snippet-refresh-draft'
|
||||
import { useSnippetDetailStore } from '../store'
|
||||
@@ -65,6 +67,25 @@ const SnippetMain = ({
|
||||
} = useNodesSyncDraft(snippetId)
|
||||
const { handleRefreshWorkflowDraft } = useSnippetRefreshDraft(snippetId)
|
||||
const configsMap = useConfigsMap(snippetId)
|
||||
const { fetchInspectVars } = useSetWorkflowVarsWithValue({
|
||||
...configsMap,
|
||||
})
|
||||
const {
|
||||
hasNodeInspectVars,
|
||||
hasSetInspectVar,
|
||||
fetchInspectVarValue,
|
||||
editInspectVarValue,
|
||||
renameInspectVarName,
|
||||
appendNodeInspectVars,
|
||||
deleteInspectVar,
|
||||
deleteNodeInspectorVars,
|
||||
deleteAllInspectorVars,
|
||||
isInspectVarEdited,
|
||||
resetToLastRunVar,
|
||||
invalidateSysVarValues,
|
||||
resetConversationVar,
|
||||
invalidateConversationVarValues,
|
||||
} = useInspectVarsCrud(snippetId)
|
||||
const workflowAvailableNodesMetaData = useAvailableNodesMetaData()
|
||||
const availableNodesMetaData = useMemo(() => {
|
||||
const nodes = workflowAvailableNodesMetaData.nodes.filter(node =>
|
||||
@@ -128,9 +149,45 @@ const SnippetMain = ({
|
||||
syncWorkflowDraftWhenPageClose,
|
||||
handleRefreshWorkflowDraft,
|
||||
availableNodesMetaData,
|
||||
fetchInspectVars,
|
||||
hasNodeInspectVars,
|
||||
hasSetInspectVar,
|
||||
fetchInspectVarValue,
|
||||
editInspectVarValue,
|
||||
renameInspectVarName,
|
||||
appendNodeInspectVars,
|
||||
deleteInspectVar,
|
||||
deleteNodeInspectorVars,
|
||||
deleteAllInspectorVars,
|
||||
isInspectVarEdited,
|
||||
resetToLastRunVar,
|
||||
invalidateSysVarValues,
|
||||
resetConversationVar,
|
||||
invalidateConversationVarValues,
|
||||
configsMap,
|
||||
}
|
||||
}, [availableNodesMetaData, configsMap, doSyncWorkflowDraft, handleRefreshWorkflowDraft, syncWorkflowDraftWhenPageClose])
|
||||
}, [
|
||||
appendNodeInspectVars,
|
||||
availableNodesMetaData,
|
||||
configsMap,
|
||||
deleteAllInspectorVars,
|
||||
deleteInspectVar,
|
||||
deleteNodeInspectorVars,
|
||||
doSyncWorkflowDraft,
|
||||
editInspectVarValue,
|
||||
fetchInspectVarValue,
|
||||
fetchInspectVars,
|
||||
handleRefreshWorkflowDraft,
|
||||
hasNodeInspectVars,
|
||||
hasSetInspectVar,
|
||||
invalidateConversationVarValues,
|
||||
invalidateSysVarValues,
|
||||
isInspectVarEdited,
|
||||
renameInspectVarName,
|
||||
resetConversationVar,
|
||||
resetToLastRunVar,
|
||||
syncWorkflowDraftWhenPageClose,
|
||||
])
|
||||
|
||||
return (
|
||||
<div className="relative flex h-full overflow-hidden bg-background-body">
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { renderHook } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useInspectVarsCrud } from '../use-inspect-vars-crud'
|
||||
|
||||
const mockApis = {
|
||||
hasNodeInspectVars: vi.fn(),
|
||||
hasSetInspectVar: vi.fn(),
|
||||
fetchInspectVarValue: vi.fn(),
|
||||
editInspectVarValue: vi.fn(),
|
||||
renameInspectVarName: vi.fn(),
|
||||
appendNodeInspectVars: vi.fn(),
|
||||
deleteInspectVar: vi.fn(),
|
||||
deleteNodeInspectorVars: vi.fn(),
|
||||
deleteAllInspectorVars: vi.fn(),
|
||||
isInspectVarEdited: vi.fn(),
|
||||
resetToLastRunVar: vi.fn(),
|
||||
invalidateSysVarValues: vi.fn(),
|
||||
resetConversationVar: vi.fn(),
|
||||
invalidateConversationVarValues: vi.fn(),
|
||||
}
|
||||
|
||||
const mockUseInspectVarsCrudCommon = vi.fn(() => mockApis)
|
||||
vi.mock('../../../workflow/hooks/use-inspect-vars-crud-common', () => ({
|
||||
useInspectVarsCrudCommon: (...args: Parameters<typeof mockUseInspectVarsCrudCommon>) => mockUseInspectVarsCrudCommon(...args),
|
||||
}))
|
||||
|
||||
const mockConfigsMap = {
|
||||
flowId: 'snippet-123',
|
||||
flowType: 'snippet',
|
||||
fileSettings: {
|
||||
image: { enabled: false },
|
||||
fileUploadConfig: {},
|
||||
},
|
||||
}
|
||||
|
||||
vi.mock('../use-configs-map', () => ({
|
||||
useConfigsMap: () => mockConfigsMap,
|
||||
}))
|
||||
|
||||
describe('useInspectVarsCrud', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('Composition', () => {
|
||||
it('should pass configsMap to useInspectVarsCrudCommon', () => {
|
||||
renderHook(() => useInspectVarsCrud('snippet-123'))
|
||||
|
||||
expect(mockUseInspectVarsCrudCommon).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
flowId: 'snippet-123',
|
||||
flowType: 'snippet',
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('should return all APIs from useInspectVarsCrudCommon', () => {
|
||||
const { result } = renderHook(() => useInspectVarsCrud('snippet-123'))
|
||||
|
||||
expect(result.current.hasNodeInspectVars).toBe(mockApis.hasNodeInspectVars)
|
||||
expect(result.current.fetchInspectVarValue).toBe(mockApis.fetchInspectVarValue)
|
||||
expect(result.current.editInspectVarValue).toBe(mockApis.editInspectVarValue)
|
||||
expect(result.current.deleteInspectVar).toBe(mockApis.deleteInspectVar)
|
||||
expect(result.current.deleteAllInspectorVars).toBe(mockApis.deleteAllInspectorVars)
|
||||
expect(result.current.resetToLastRunVar).toBe(mockApis.resetToLastRunVar)
|
||||
expect(result.current.resetConversationVar).toBe(mockApis.resetConversationVar)
|
||||
})
|
||||
})
|
||||
|
||||
describe('API Surface', () => {
|
||||
it('should expose all expected API methods', () => {
|
||||
const { result } = renderHook(() => useInspectVarsCrud('snippet-123'))
|
||||
|
||||
const expectedKeys = [
|
||||
'hasNodeInspectVars',
|
||||
'hasSetInspectVar',
|
||||
'fetchInspectVarValue',
|
||||
'editInspectVarValue',
|
||||
'renameInspectVarName',
|
||||
'appendNodeInspectVars',
|
||||
'deleteInspectVar',
|
||||
'deleteNodeInspectorVars',
|
||||
'deleteAllInspectorVars',
|
||||
'isInspectVarEdited',
|
||||
'resetToLastRunVar',
|
||||
'invalidateSysVarValues',
|
||||
'resetConversationVar',
|
||||
'invalidateConversationVarValues',
|
||||
]
|
||||
|
||||
for (const key of expectedKeys)
|
||||
expect(result.current).toHaveProperty(key)
|
||||
})
|
||||
})
|
||||
})
|
||||
13
web/app/components/snippets/hooks/use-inspect-vars-crud.ts
Normal file
13
web/app/components/snippets/hooks/use-inspect-vars-crud.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useInspectVarsCrudCommon } from '../../workflow/hooks/use-inspect-vars-crud-common'
|
||||
import { useConfigsMap } from './use-configs-map'
|
||||
|
||||
export const useInspectVarsCrud = (snippetId: string) => {
|
||||
const configsMap = useConfigsMap(snippetId)
|
||||
const apis = useInspectVarsCrudCommon({
|
||||
...configsMap,
|
||||
})
|
||||
|
||||
return {
|
||||
...apis,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user