fix(richtext-lexical): incorrectly hidden fields in drawers due to incorrect permissions handling (#11883)

Lexical nested fields are currently not set-up to handle access control
on the client properly. Despite that, we were passing parent permissions
to `RenderFields`, which causes certain fields to not show up if the
document does not have `create` permission.
This commit is contained in:
Alessio Gravili
2025-03-26 15:04:55 -06:00
committed by GitHub
parent 59c9feeb45
commit f34cc637e3
6 changed files with 117 additions and 7 deletions

View File

@@ -1135,6 +1135,33 @@ describe('lexicalMain', () => {
await expect(urlInput).toBeVisible()
})
test('ensure link drawer displays nested block fields if document does not have `create` permission', async () => {
await navigateToLexicalFields(true, 'lexical-access-control')
const richTextField = page.locator('.rich-text-lexical').first()
await richTextField.scrollIntoViewIfNeeded()
await expect(richTextField).toBeVisible()
const link = richTextField.locator('.LexicalEditorTheme__link').first()
await link.scrollIntoViewIfNeeded()
await expect(link).toBeVisible()
await link.click({
// eslint-disable-next-line playwright/no-force-option
force: true,
button: 'left',
})
await expect(page.locator('.link-edit')).toBeVisible()
await page.locator('.link-edit').click()
const linkDrawer = page.locator('dialog[id^=drawer_1_lexical-rich-text-link-]').first()
await expect(linkDrawer).toBeVisible()
const blockTextInput = linkDrawer.locator('#field-blocks__0__text').first()
await expect(blockTextInput).toBeVisible()
await expect(blockTextInput).toBeEditable()
})
test('lexical cursor / selection should be preserved when swapping upload field and clicking within with its list drawer', async () => {
await navigateToLexicalFields()
const richTextField = page.locator('.rich-text-lexical').first()
@@ -1494,6 +1521,7 @@ describe('lexicalMain', () => {
expect(htmlContent).not.toContain('Cargando...')
expect(htmlContent).toContain('Start typing, or press')
})
// eslint-disable-next-line playwright/expect-expect, playwright/no-skipped-test
test.skip('ensure simple localized lexical field works', async () => {
await navigateToLexicalFields(true, 'lexical-localized-fields')
})

View File

@@ -1,6 +1,6 @@
import type { CollectionConfig } from 'payload'
import { defaultEditorFeatures, lexicalEditor } from '@payloadcms/richtext-lexical'
import { defaultEditorFeatures, lexicalEditor, LinkFeature } from '@payloadcms/richtext-lexical'
import { lexicalAccessControlSlug } from '../../slugs.js'
@@ -22,7 +22,29 @@ export const LexicalAccessControl: CollectionConfig = {
name: 'richText',
type: 'richText',
editor: lexicalEditor({
features: [...defaultEditorFeatures],
features: [
...defaultEditorFeatures,
LinkFeature({
fields: ({ defaultFields }) => [
...defaultFields,
{
name: 'blocks',
type: 'blocks',
blocks: [
{
slug: 'block',
fields: [
{
name: 'text',
type: 'text',
},
],
},
],
},
],
}),
],
}),
},
],

View File

@@ -591,7 +591,67 @@ export const seed = async (_payload: Payload) => {
await _payload.create({
collection: 'lexical-access-control',
data: {
richText: textToLexicalJSON({ text: 'text' }),
richText: {
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'text ',
type: 'text',
version: 1,
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'link',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'link',
version: 3,
fields: {
url: 'https://',
newTab: false,
linkType: 'custom',
blocks: [
{
id: '67e45673cbd5181ca8cbeef7',
blockType: 'block',
},
],
},
id: '67e4566fcbd5181ca8cbeef5',
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
textFormat: 0,
textStyle: '',
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1,
},
},
title: 'title',
},
depth: 0,