Merge pull request #5549 from payloadcms/temp33

fix: unload client functions after unmount (e.g. leaving document)
This commit is contained in:
Alessio Gravili
2024-03-29 11:07:47 -04:00
committed by GitHub
2 changed files with 74 additions and 13 deletions

View File

@@ -1,18 +1,24 @@
'use client'
import React from 'react'
type AddClientFunctionContextType = (func: any) => void
type ModifyClientFunctionContextType = {
addClientFunction: (args: ModifyFunctionArgs) => void
removeClientFunction: (args: ModifyFunctionArgs) => void
}
type ClientFunctionsContextType = Record<string, any>
const AddClientFunctionContext = React.createContext<AddClientFunctionContextType>(() => null)
const ModifyClientFunctionContext = React.createContext<ModifyClientFunctionContextType>({
addClientFunction: () => null,
removeClientFunction: () => null,
})
const ClientFunctionsContext = React.createContext<ClientFunctionsContextType>({})
type AddFunctionArgs = { func: any; key: string }
type ModifyFunctionArgs = { func: any; key: string }
export const ClientFunctionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [clientFunctions, setClientFunctions] = React.useState({})
const addClientFunction = React.useCallback((args: AddFunctionArgs) => {
const addClientFunction = React.useCallback((args: ModifyFunctionArgs) => {
setClientFunctions((state) => {
const newState = { ...state }
newState[args.key] = args.func
@@ -20,24 +26,44 @@ export const ClientFunctionProvider: React.FC<{ children: React.ReactNode }> = (
})
}, [])
const removeClientFunction = React.useCallback((args: ModifyFunctionArgs) => {
setClientFunctions((state) => {
const newState = { ...state }
delete newState[args.key]
return newState
})
}, [])
return (
<AddClientFunctionContext.Provider value={addClientFunction}>
<ModifyClientFunctionContext.Provider
value={{
addClientFunction,
removeClientFunction,
}}
>
<ClientFunctionsContext.Provider value={clientFunctions}>
{children}
</ClientFunctionsContext.Provider>
</AddClientFunctionContext.Provider>
</ModifyClientFunctionContext.Provider>
)
}
export const useAddClientFunction = (key: string, func: any) => {
const addClientFunction = React.useContext(AddClientFunctionContext)
const { addClientFunction, removeClientFunction } = React.useContext(ModifyClientFunctionContext)
React.useEffect(() => {
addClientFunction({
func,
key,
})
}, [func, key, addClientFunction])
return () => {
removeClientFunction({
func,
key,
})
}
}, [func, key, addClientFunction, removeClientFunction])
}
export const useClientFunctions = () => {

View File

@@ -28,9 +28,15 @@ let client: RESTClient
let page: Page
let serverURL: string
async function navigateToLexicalFields() {
const url: AdminUrlUtil = new AdminUrlUtil(serverURL, 'lexical-fields')
await page.goto(url.list)
/**
* Client-side navigation to the lexical editor from list view
*/
async function navigateToLexicalFields(navigateToListView: boolean = true) {
if (navigateToListView) {
const url: AdminUrlUtil = new AdminUrlUtil(serverURL, 'lexical-fields')
await page.goto(url.list)
}
const linkToDoc = page.locator('tbody tr:first-child .cell-title a').first()
await expect(() => expect(linkToDoc).toBeTruthy()).toPass({ timeout: POLL_TOPASS_TIMEOUT })
const linkDocHref = await linkToDoc.getAttribute('href')
@@ -718,8 +724,7 @@ describe('lexical', () => {
await expect(nestedEditorParagraph).toHaveText('Some text below relationship node 12345')
})
test('should respect row removal in nested array field', async () => {
await navigateToLexicalFields()
const shouldRespectRowRemovalTest = async () => {
const richTextField = page.locator('.rich-text-lexical').nth(1) // second
await richTextField.scrollIntoViewIfNeeded()
await expect(richTextField).toBeVisible()
@@ -762,6 +767,36 @@ describe('lexical', () => {
await saveDocAndAssert(page)
await expect(page.locator('.Toastify')).not.toContainText('Please correct invalid fields.')
}
// eslint-disable-next-line playwright/expect-expect
test('should respect row removal in nested array field', async () => {
await navigateToLexicalFields()
await shouldRespectRowRemovalTest()
})
test('should respect row removal in nested array field after navigating away from lexical document, then navigating back', async () => {
// This test verifies an issue where a lexical editor with blocks disappears when navigating away from the lexical document, then navigating back, without a hard refresh
await navigateToLexicalFields()
// Wait for lexical to be loaded up fully
const richTextField = page.locator('.rich-text-lexical').nth(1) // second
await richTextField.scrollIntoViewIfNeeded()
await expect(richTextField).toBeVisible()
const conditionalArrayBlock = richTextField.locator('.lexical-block').nth(7)
await conditionalArrayBlock.scrollIntoViewIfNeeded()
await expect(conditionalArrayBlock).toBeVisible()
// navigate to list view
await page.locator('.step-nav a').nth(1).click()
await page.waitForURL('**/lexical-fields?limit=10')
// Click on lexical document in list view (navigateToLexicalFields is client-side navigation which is what we need to reproduce the issue here)
await navigateToLexicalFields(false)
await shouldRespectRowRemovalTest()
})
test.skip('should respect required error state in deeply nested text field', async () => {