mirror of
https://github.com/langgenius/dify.git
synced 2026-03-05 15:47:06 +08:00
fix(web): invalidate plugin checkInstalled cache after version updates
This commit is contained in:
@ -15,6 +15,7 @@ type VersionPickerMock = {
|
||||
const {
|
||||
mockSetShowUpdatePluginModal,
|
||||
mockRefreshModelProviders,
|
||||
mockInvalidateCheckInstalled,
|
||||
mockInvalidateAllToolProviders,
|
||||
mockUninstallPlugin,
|
||||
mockFetchReleases,
|
||||
@ -23,6 +24,7 @@ const {
|
||||
return {
|
||||
mockSetShowUpdatePluginModal: vi.fn(),
|
||||
mockRefreshModelProviders: vi.fn(),
|
||||
mockInvalidateCheckInstalled: vi.fn(),
|
||||
mockInvalidateAllToolProviders: vi.fn(),
|
||||
mockUninstallPlugin: vi.fn(() => Promise.resolve({ success: true })),
|
||||
mockFetchReleases: vi.fn(() => Promise.resolve([{ tag_name: 'v2.0.0' }])),
|
||||
@ -46,6 +48,10 @@ vi.mock('@/service/plugins', () => ({
|
||||
uninstallPlugin: mockUninstallPlugin,
|
||||
}))
|
||||
|
||||
vi.mock('@/service/use-plugins', () => ({
|
||||
useInvalidateCheckInstalled: () => mockInvalidateCheckInstalled,
|
||||
}))
|
||||
|
||||
vi.mock('@/service/use-tools', () => ({
|
||||
useInvalidateAllToolProviders: () => mockInvalidateAllToolProviders,
|
||||
}))
|
||||
@ -178,6 +184,7 @@ describe('usePluginOperations', () => {
|
||||
result.current.handleUpdatedFromMarketplace()
|
||||
})
|
||||
|
||||
expect(mockInvalidateCheckInstalled).toHaveBeenCalled()
|
||||
expect(mockOnUpdate).toHaveBeenCalled()
|
||||
expect(modalStates.hideUpdateModal).toHaveBeenCalled()
|
||||
})
|
||||
@ -251,6 +258,32 @@ describe('usePluginOperations', () => {
|
||||
expect(mockSetShowUpdatePluginModal).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should invalidate checkInstalled when GitHub update save callback fires', async () => {
|
||||
const detail = createPluginDetail({
|
||||
source: PluginSource.github,
|
||||
meta: { repo: 'owner/repo', version: 'v1.0.0', package: 'pkg' },
|
||||
})
|
||||
const { result } = renderHook(() =>
|
||||
usePluginOperations({
|
||||
detail,
|
||||
modalStates,
|
||||
versionPicker,
|
||||
isFromMarketplace: false,
|
||||
onUpdate: mockOnUpdate,
|
||||
}),
|
||||
)
|
||||
|
||||
await act(async () => {
|
||||
await result.current.handleUpdate()
|
||||
})
|
||||
|
||||
const firstCall = mockSetShowUpdatePluginModal.mock.calls.at(0)?.[0]
|
||||
firstCall?.onSaveCallback()
|
||||
|
||||
expect(mockInvalidateCheckInstalled).toHaveBeenCalled()
|
||||
expect(mockOnUpdate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not show modal when no releases found', async () => {
|
||||
mockFetchReleases.mockResolvedValueOnce([])
|
||||
const detail = createPluginDetail({
|
||||
@ -388,6 +421,7 @@ describe('usePluginOperations', () => {
|
||||
await result.current.handleDelete()
|
||||
})
|
||||
|
||||
expect(mockInvalidateCheckInstalled).toHaveBeenCalled()
|
||||
expect(mockOnUpdate).toHaveBeenCalledWith(true)
|
||||
})
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import Toast from '@/app/components/base/toast'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { uninstallPlugin } from '@/service/plugins'
|
||||
import { useInvalidateCheckInstalled } from '@/service/use-plugins'
|
||||
import { useInvalidateAllToolProviders } from '@/service/use-tools'
|
||||
import { useGitHubReleases } from '../../../install-plugin/hooks'
|
||||
import { PluginCategoryEnum, PluginSource } from '../../../types'
|
||||
@ -41,10 +42,15 @@ export const usePluginOperations = ({
|
||||
const { checkForUpdates, fetchReleases } = useGitHubReleases()
|
||||
const { setShowUpdatePluginModal } = useModalContext()
|
||||
const { refreshModelProviders } = useProviderContext()
|
||||
const invalidateCheckInstalled = useInvalidateCheckInstalled()
|
||||
const invalidateAllToolProviders = useInvalidateAllToolProviders()
|
||||
|
||||
const { id, meta, plugin_id } = detail
|
||||
const { author, category, name } = detail.declaration || detail
|
||||
const handlePluginUpdated = useCallback((isDelete?: boolean) => {
|
||||
invalidateCheckInstalled()
|
||||
onUpdate?.(isDelete)
|
||||
}, [invalidateCheckInstalled, onUpdate])
|
||||
|
||||
const handleUpdate = useCallback(async (isDowngrade?: boolean) => {
|
||||
if (isFromMarketplace) {
|
||||
@ -73,7 +79,7 @@ export const usePluginOperations = ({
|
||||
if (needUpdate) {
|
||||
setShowUpdatePluginModal({
|
||||
onSaveCallback: () => {
|
||||
onUpdate?.()
|
||||
handlePluginUpdated()
|
||||
},
|
||||
payload: {
|
||||
type: PluginSource.github,
|
||||
@ -99,15 +105,15 @@ export const usePluginOperations = ({
|
||||
checkForUpdates,
|
||||
setShowUpdatePluginModal,
|
||||
detail,
|
||||
onUpdate,
|
||||
handlePluginUpdated,
|
||||
modalStates,
|
||||
versionPicker,
|
||||
])
|
||||
|
||||
const handleUpdatedFromMarketplace = useCallback(() => {
|
||||
onUpdate?.()
|
||||
handlePluginUpdated()
|
||||
modalStates.hideUpdateModal()
|
||||
}, [onUpdate, modalStates])
|
||||
}, [handlePluginUpdated, modalStates])
|
||||
|
||||
const handleDelete = useCallback(async () => {
|
||||
modalStates.showDeleting()
|
||||
@ -120,7 +126,7 @@ export const usePluginOperations = ({
|
||||
type: 'success',
|
||||
message: t('action.deleteSuccess', { ns: 'plugin' }),
|
||||
})
|
||||
onUpdate?.(true)
|
||||
handlePluginUpdated(true)
|
||||
|
||||
if (PluginCategoryEnum.model.includes(category))
|
||||
refreshModelProviders()
|
||||
@ -136,7 +142,7 @@ export const usePluginOperations = ({
|
||||
plugin_id,
|
||||
name,
|
||||
modalStates,
|
||||
onUpdate,
|
||||
handlePluginUpdated,
|
||||
refreshModelProviders,
|
||||
invalidateAllToolProviders,
|
||||
])
|
||||
|
||||
@ -47,6 +47,7 @@ import { useInvalidateAllBuiltInTools } from './use-tools'
|
||||
const NAME_SPACE = 'plugins'
|
||||
|
||||
const useInstalledPluginListKey = [NAME_SPACE, 'installedPluginList']
|
||||
const useCheckInstalledKey = [NAME_SPACE, 'checkInstalled'] as const
|
||||
export const useCheckInstalled = ({
|
||||
pluginIds,
|
||||
enabled,
|
||||
@ -55,7 +56,7 @@ export const useCheckInstalled = ({
|
||||
enabled: boolean
|
||||
}) => {
|
||||
return useQuery<{ plugins: PluginDetail[] }>({
|
||||
queryKey: [NAME_SPACE, 'checkInstalled', pluginIds],
|
||||
queryKey: [...useCheckInstalledKey, pluginIds],
|
||||
queryFn: () => post<{ plugins: PluginDetail[] }>('/workspaces/current/plugin/list/installations/ids', {
|
||||
body: {
|
||||
plugin_ids: pluginIds,
|
||||
@ -66,6 +67,17 @@ export const useCheckInstalled = ({
|
||||
})
|
||||
}
|
||||
|
||||
export const useInvalidateCheckInstalled = () => {
|
||||
const queryClient = useQueryClient()
|
||||
return () => {
|
||||
queryClient.invalidateQueries(
|
||||
{
|
||||
queryKey: useCheckInstalledKey,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const useRecommendedMarketplacePluginsKey = [NAME_SPACE, 'recommendedMarketplacePlugins']
|
||||
export const useRecommendedMarketplacePlugins = ({
|
||||
collection = '__recommended-plugins-tools',
|
||||
|
||||
Reference in New Issue
Block a user