Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ const Restore: React.FC<Props> = ({
if (res.status === 200) {
const json = await res.json()
toast.success(json.message)
history.push(redirectURL)
history.push(redirectURL, {
refetchDocumentData: true,
})
} else {
toast.error(t('problemRestoringVersion'))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,16 @@ const EditView: React.FC<IndexProps> = (props) => {
} = config

const { params: { id } = {} } = useRouteMatch<Record<string, string>>()
const history = useHistory()
const history = useHistory<{ refetchDocumentData?: boolean }>()

const [internalState, setInternalState] = useState<Fields>()
const [updatedAt, setUpdatedAt] = useState<string>()
const { permissions, user } = useAuth()
const userRef = useRef(user)
const { docPermissions, getDocPermissions, getDocPreferences, getVersions } = useDocumentInfo()
const { t } = useTranslation('general')

const [{ data, isError, isLoading: isLoadingData }] = usePayloadAPI(
const [{ data, isError, isLoading: isLoadingData }, { refetchData }] = usePayloadAPI(
isEditing ? `${serverURL}${api}/${collectionSlug}/${id}` : '',
{ initialData: null, initialParams: { depth: 0, draft: 'true', 'fallback-locale': 'null' } },
)
Expand Down Expand Up @@ -128,10 +129,16 @@ const EditView: React.FC<IndexProps> = (props) => {
useEffect(() => {
setFormQueryParams((params) => ({
...params,
locale: locale,
locale,
}))
}, [locale])

useEffect(() => {
if (history.location.state?.refetchDocumentData) {
void refetchData()
}
}, [history.location.state?.refetchDocumentData, refetchData])

if (isError) {
return <NotFound marginTop="large" />
}
Expand Down
75 changes: 40 additions & 35 deletions packages/payload/src/admin/hooks/usePayloadAPI.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import queryString from 'qs'
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

import { requests } from '../api'
Expand All @@ -12,6 +12,7 @@ type Result = [
isLoading: boolean
},
{
refetchData: (abortController?: AbortController) => Promise<void>
setParams: React.Dispatch<unknown>
},
]
Expand Down Expand Up @@ -43,49 +44,53 @@ const usePayloadAPI: UsePayloadAPI = (url, options = {}) => {
},
)

useEffect(() => {
const abortController = new AbortController()

const fetchData = async () => {
setIsError(false)
setIsLoading(true)

try {
const response = await requests.get(`${url}${search}`, {
headers: {
'Accept-Language': i18n.language,
},
signal: abortController.signal,
})

if (response.status > 201) {
setIsError(true)
}

const json = await response.json()
setData(json)
setIsLoading(false)
} catch (error) {
if (!abortController.signal.aborted) {
setIsError(true)
const fetchData = useCallback(
async (abortController?: AbortController) => {
if (url) {
setIsError(false)
setIsLoading(true)
try {
const response = await requests.get(`${url}${search}`, {
headers: {
'Accept-Language': i18n.language,
},
signal: abortController ? abortController.signal : undefined,
})

if (response.status > 201) {
setIsError(true)
}

const json = await response.json()
setData(json)
setIsLoading(false)
} catch (error) {
if (!abortController || !abortController.signal.aborted) {
setIsError(true)
setIsLoading(false)
}
}
} else {
setIsError(false)
setIsLoading(false)
}
}
},
[url, search, i18n.language],
)

if (url) {
fetchData()
} else {
setIsError(false)
setIsLoading(false)
}
useEffect(() => {
const abortController = new AbortController()
void fetchData(abortController)

return () => {
abortController.abort()
}
}, [url, locale, search, i18n.language])
}, [url, search, fetchData])

return [{ data, isError, isLoading }, { setParams }]
return [
{ data, isError, isLoading },
{ refetchData: fetchData, setParams },
]
}

export default usePayloadAPI
3 changes: 3 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type { PlaywrightTestConfig } from '@playwright/test'

export const EXPECT_TIMEOUT = 45000
export const POLL_TOPASS_TIMEOUT = EXPECT_TIMEOUT * 4 // That way expect.poll() or expect().toPass can retry 4 times. 4x higher than default expect timeout => can retry 4 times if retryable expects are used inside

const config: PlaywrightTestConfig = {
// Look for test files in the "test" directory, relative to this configuration file
testDir: 'test',
Expand Down
34 changes: 34 additions & 0 deletions test/versions/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ import { expect, test } from '@playwright/test'

import payload from '../../packages/payload/src'
import wait from '../../packages/payload/src/utilities/wait'
import { POLL_TOPASS_TIMEOUT } from '../../playwright.config'
import { globalSlug } from '../admin/slugs'
import {
changeLocale,
exactText,
findTableCell,
initPageConsoleErrorCatch,
saveDocAndAssert,
selectTableRow,
} from '../helpers'
import { AdminUrlUtil } from '../helpers/adminUrlUtil'
Expand Down Expand Up @@ -240,6 +242,38 @@ describe('versions', () => {
await expect(page.locator('.app-header .collection-versions-button')).toHaveCount(1)
})

test('should restore version with correct data', async () => {
await page.goto(url.create)
await page.waitForURL(url.create)

// publish a doc
await page.locator('#field-title').fill('v1')
await page.locator('#field-description').fill('hello')
await saveDocAndAssert(page)

// save a draft
await page.locator('#field-title').fill('v2')
await saveDocAndAssert(page, '#action-save-draft')

// go to versions list view
const savedDocURL = page.url()
await page.goto(`${savedDocURL}/versions`)
await page.waitForURL(`${savedDocURL}/versions`)

// select the first version (row 2)
const row2 = page.locator('tbody .row-2')
const versionID = await row2.locator('.cell-id').textContent()
await page.goto(`${savedDocURL}/versions/${versionID}`)
await page.waitForURL(`${savedDocURL}/versions/${versionID}`)

// restore doc
await page.locator('.pill.restore-version').click()
await page.locator('button:has-text("Confirm")').click()
await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).not.toContain(versionID)

await expect(page.locator('#field-title')).toHaveValue('v1')
})

test('should show global versions view level action in globals versions view', async () => {
const global = new AdminUrlUtil(serverURL, draftGlobalSlug)
await page.goto(`${global.global(draftGlobalSlug)}/versions`)
Expand Down