mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
fix(workflow): prevent redundant sandbox download refetch after reset
Problem:\n- In variable inspect artifacts view, clicking Reset All invalidates sandbox download query keys.\n- If a previously selected file has been removed, the download-url query may still refetch with stale path and return 400.\n- Default query retry amplifies this into repeated failed requests in this scenario.\n\nSolution:\n- Extend sandbox file invalidation with an option to skip download query refetch.\n- Use that option in Reset All flow so download-url queries are marked stale without immediate refetch.\n- Derive selected file path from latest sandbox flat data and disable download-url query when file no longer exists.\n- Disable retry only for artifacts-tab download-url query to avoid repeated 400 retries in this path.\n- Align tree selectedPath with derived selectedFilePath and add hook tests for invalidation behavior.\n\nValidation:\n- pnpm vitest --run service/use-sandbox-file.spec.tsx
This commit is contained in:
60
web/service/use-sandbox-file.spec.tsx
Normal file
60
web/service/use-sandbox-file.spec.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { act, renderHook } from '@testing-library/react'
|
||||
import { consoleQuery } from './client'
|
||||
import { useInvalidateSandboxFiles } from './use-sandbox-file'
|
||||
|
||||
const createQueryClient = () => new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const createWrapper = (queryClient: QueryClient) => {
|
||||
return ({ children }: { children: ReactNode }) => (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('useInvalidateSandboxFiles', () => {
|
||||
it('should keep download query refetch enabled by default', async () => {
|
||||
const queryClient = createQueryClient()
|
||||
const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries').mockResolvedValue(undefined)
|
||||
const { result } = renderHook(() => useInvalidateSandboxFiles(), {
|
||||
wrapper: createWrapper(queryClient),
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
await result.current()
|
||||
})
|
||||
|
||||
expect(invalidateSpy).toHaveBeenNthCalledWith(1, {
|
||||
queryKey: consoleQuery.sandboxFile.listFiles.key(),
|
||||
})
|
||||
expect(invalidateSpy).toHaveBeenNthCalledWith(2, {
|
||||
queryKey: consoleQuery.sandboxFile.downloadFile.key(),
|
||||
})
|
||||
})
|
||||
|
||||
it('should disable download query refetch when requested', async () => {
|
||||
const queryClient = createQueryClient()
|
||||
const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries').mockResolvedValue(undefined)
|
||||
const { result } = renderHook(() => useInvalidateSandboxFiles(), {
|
||||
wrapper: createWrapper(queryClient),
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
await result.current({ refetchDownloadFile: false })
|
||||
})
|
||||
|
||||
expect(invalidateSpy).toHaveBeenNthCalledWith(1, {
|
||||
queryKey: consoleQuery.sandboxFile.listFiles.key(),
|
||||
})
|
||||
expect(invalidateSpy).toHaveBeenNthCalledWith(2, {
|
||||
queryKey: consoleQuery.sandboxFile.downloadFile.key(),
|
||||
refetchType: 'none',
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -14,6 +14,15 @@ type UseGetSandboxFilesOptions = {
|
||||
refetchInterval?: number | false
|
||||
}
|
||||
|
||||
type UseSandboxFileDownloadUrlOptions = {
|
||||
enabled?: boolean
|
||||
retry?: boolean | number
|
||||
}
|
||||
|
||||
type InvalidateSandboxFilesOptions = {
|
||||
refetchDownloadFile?: boolean
|
||||
}
|
||||
|
||||
export function useGetSandboxFiles(
|
||||
appId: string | undefined,
|
||||
options?: UseGetSandboxFilesOptions,
|
||||
@ -39,6 +48,7 @@ export function useGetSandboxFiles(
|
||||
export function useSandboxFileDownloadUrl(
|
||||
appId: string | undefined,
|
||||
path: string | undefined,
|
||||
options?: UseSandboxFileDownloadUrlOptions,
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: consoleQuery.sandboxFile.downloadFile.queryKey({
|
||||
@ -48,19 +58,22 @@ export function useSandboxFileDownloadUrl(
|
||||
params: { appId: appId! },
|
||||
body: { path: path! },
|
||||
}),
|
||||
enabled: !!appId && !!path,
|
||||
enabled: !!appId && !!path && (options?.enabled ?? true),
|
||||
retry: options?.retry,
|
||||
})
|
||||
}
|
||||
|
||||
export function useInvalidateSandboxFiles() {
|
||||
const queryClient = useQueryClient()
|
||||
return useCallback(() => {
|
||||
return useCallback((options?: InvalidateSandboxFilesOptions) => {
|
||||
const shouldRefetchDownloadFile = options?.refetchDownloadFile ?? true
|
||||
return Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.sandboxFile.listFiles.key(),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.sandboxFile.downloadFile.key(),
|
||||
...(shouldRefetchDownloadFile ? {} : { refetchType: 'none' as const }),
|
||||
}),
|
||||
])
|
||||
}, [queryClient])
|
||||
|
||||
Reference in New Issue
Block a user