diff --git a/apps/studio/components/interfaces/Storage/StorageExplorer/PreviewPane.tsx b/apps/studio/components/interfaces/Storage/StorageExplorer/PreviewPane.tsx index 7600bc04ab6..9aab438c033 100644 --- a/apps/studio/components/interfaces/Storage/StorageExplorer/PreviewPane.tsx +++ b/apps/studio/components/interfaces/Storage/StorageExplorer/PreviewPane.tsx @@ -232,6 +232,7 @@ export const PreviewPane = () => { openedFolders, setSelectedItemsToDelete, setItemToPurge, + refetchAllOpenedFolders, setSelectedFileCustomExpiry, downloadFile, } = useStorageExplorerStateSnapshot() @@ -276,9 +277,10 @@ export const PreviewPane = () => { }) const { mutate: restoreVersion, isPending: isRestoring } = useObjectVersionRestoreMutation({ - onSuccess: () => { + onSuccess: async () => { toast.success('Version restored as the current version') setPreviewedVersion(undefined) + await refetchAllOpenedFolders() }, }) diff --git a/apps/studio/components/interfaces/Storage/StorageExplorer/VersionHistory.test.tsx b/apps/studio/components/interfaces/Storage/StorageExplorer/VersionHistory.test.tsx new file mode 100644 index 00000000000..74f5ff81546 --- /dev/null +++ b/apps/studio/components/interfaces/Storage/StorageExplorer/VersionHistory.test.tsx @@ -0,0 +1,83 @@ +import { screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { describe, expect, it, vi } from 'vitest' + +import { VersionHistory } from '@/components/interfaces/Storage/StorageExplorer/VersionHistory' +import { customRender as render } from '@/tests/lib/custom-render' +import { addAPIMock } from '@/tests/lib/msw' + +const refetchAllOpenedFolders = vi.fn().mockResolvedValue(undefined) + +vi.mock('@/state/storage-explorer', () => ({ + useStorageExplorerStateSnapshot: () => ({ refetchAllOpenedFolders }), +})) +// The versions query is platform-only, and `IS_PLATFORM` is false under vitest. +vi.mock('@/lib/constants', async (importOriginal) => { + const actual = await importOriginal>() + return { ...actual, IS_PLATFORM: true } +}) + +const VERSIONS = [ + { + id: 'obj-1', + name: 'photo.png', + version: 'v-current', + created_at: '2024-01-02T00:00:00Z', + updated_at: '2024-01-02T00:00:00Z', + last_accessed_at: null, + archived_at: null, + is_delete_marker: false, + metadata: { size: 200, mimetype: 'image/png' }, + }, + { + id: 'obj-1', + name: 'photo.png', + version: 'v-older', + created_at: '2024-01-01T00:00:00Z', + updated_at: '2024-01-01T00:00:00Z', + last_accessed_at: null, + // Anything with an `archived_at` is a noncurrent version, which is what can be restored. + archived_at: '2024-01-02T00:00:00Z', + is_delete_marker: false, + metadata: { size: 100, mimetype: 'image/png' }, + }, +] + +const renderHistory = () => + render( + + ) + +describe('VersionHistory', () => { + it('refreshes the listing after a restore, so the row stops showing the old size', async () => { + addAPIMock({ + method: 'post', + path: '/platform/storage/:ref/buckets/:id/objects/list', + response: () => Response.json(VERSIONS), + }) + addAPIMock({ + method: 'post', + path: '/platform/storage/:ref/buckets/:id/objects/move', + response: () => Response.json({ message: 'ok' }), + }) + + renderHistory() + + await userEvent.click(await screen.findByRole('button', { name: /Actions for version/ })) + await userEvent.click(await screen.findByText('Restore as current')) + + // A restore changes the object's size, type and modified date, and the row + // showing them lives in the explorer's state rather than a React Query cache. + await waitFor(() => expect(refetchAllOpenedFolders).toHaveBeenCalled()) + }) +}) diff --git a/apps/studio/components/interfaces/Storage/StorageExplorer/VersionHistory.tsx b/apps/studio/components/interfaces/Storage/StorageExplorer/VersionHistory.tsx index 42cae17b614..314d9abdc80 100644 --- a/apps/studio/components/interfaces/Storage/StorageExplorer/VersionHistory.tsx +++ b/apps/studio/components/interfaces/Storage/StorageExplorer/VersionHistory.tsx @@ -30,6 +30,7 @@ import { type ObjectVersion, } from '@/data/storage/versioning/object-versions-query' import { formatBytes } from '@/lib/helpers' +import { useStorageExplorerStateSnapshot } from '@/state/storage-explorer' /** Version IDs are long opaque strings; show enough to tell two rows apart. */ export const shortVersion = (versionId: string) => `${versionId.slice(0, 6)}…${versionId.slice(-2)}` @@ -161,10 +162,17 @@ export const VersionHistory = ({ isSuccess, } = useQuery(objectVersionsQueryOptions({ projectRef, bucketId, path, lifecyclePolicy })) + const { refetchAllOpenedFolders } = useStorageExplorerStateSnapshot() + const [versionToDelete, setVersionToDelete] = useState() const { mutate: restoreVersion, isPending: isRestoring } = useObjectVersionRestoreMutation({ - onSuccess: () => toast.success('Version restored as the current version'), + onSuccess: async () => { + toast.success('Version restored as the current version') + // The object's size, type and modified date all change with it, and the row + // showing them is the explorer's own state. + await refetchAllOpenedFolders() + }, }) const { mutate: deleteVersion, isPending: isDeleting } = useObjectVersionDeleteMutation({