Skip to content

Commit f34cc63

Browse files
authored
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.
1 parent 59c9fee commit f34cc63

File tree

6 files changed

+117
-7
lines changed

6 files changed

+117
-7
lines changed

packages/richtext-lexical/src/features/blocks/client/component/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ export const BlockComponent: React.FC<Props> = (props) => {
507507
parentIndexPath=""
508508
parentPath="" // See Blocks feature path for details as for why this is empty
509509
parentSchemaPath={schemaFieldsPath}
510-
permissions={permissions}
510+
permissions={true}
511511
readOnly={false}
512512
/>
513513
<FormSubmit programmaticSubmit={true}>{t('fields:saveChanges')}</FormSubmit>

packages/richtext-lexical/src/features/blocks/client/componentInline/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ export const InlineBlockComponent: React.FC<Props> = (props) => {
417417
parentIndexPath=""
418418
parentPath="" // See Blocks feature path for details as for why this is empty
419419
parentSchemaPath={schemaFieldsPath}
420-
permissions={permissions}
420+
permissions={true}
421421
readOnly={false}
422422
/>
423423
<FormSubmit programmaticSubmit={true}>{t('fields:saveChanges')}</FormSubmit>

packages/richtext-lexical/src/utilities/fieldsDrawer/DrawerContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const DrawerContent: React.FC<Omit<FieldsDrawerProps, 'drawerSlug' | 'dra
3737
const [initialState, setInitialState] = useState<false | FormState | undefined>(false)
3838

3939
const {
40-
fieldProps: { featureClientSchemaMap, permissions },
40+
fieldProps: { featureClientSchemaMap },
4141
} = useEditorConfigContext()
4242

4343
const { getFormState } = useServerFunctions()
@@ -155,7 +155,7 @@ export const DrawerContent: React.FC<Omit<FieldsDrawerProps, 'drawerSlug' | 'dra
155155
parentIndexPath=""
156156
parentPath="" // See Blocks feature path for details as for why this is empty
157157
parentSchemaPath={schemaFieldsPath}
158-
permissions={permissions}
158+
permissions={true}
159159
readOnly={false}
160160
/>
161161
<FormSubmit>{t('fields:saveChanges')}</FormSubmit>

test/fields/collections/Lexical/e2e/main/e2e.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,33 @@ describe('lexicalMain', () => {
11351135
await expect(urlInput).toBeVisible()
11361136
})
11371137

1138+
test('ensure link drawer displays nested block fields if document does not have `create` permission', async () => {
1139+
await navigateToLexicalFields(true, 'lexical-access-control')
1140+
const richTextField = page.locator('.rich-text-lexical').first()
1141+
await richTextField.scrollIntoViewIfNeeded()
1142+
await expect(richTextField).toBeVisible()
1143+
1144+
const link = richTextField.locator('.LexicalEditorTheme__link').first()
1145+
await link.scrollIntoViewIfNeeded()
1146+
await expect(link).toBeVisible()
1147+
await link.click({
1148+
// eslint-disable-next-line playwright/no-force-option
1149+
force: true,
1150+
button: 'left',
1151+
})
1152+
1153+
await expect(page.locator('.link-edit')).toBeVisible()
1154+
await page.locator('.link-edit').click()
1155+
1156+
const linkDrawer = page.locator('dialog[id^=drawer_1_lexical-rich-text-link-]').first()
1157+
await expect(linkDrawer).toBeVisible()
1158+
1159+
const blockTextInput = linkDrawer.locator('#field-blocks__0__text').first()
1160+
1161+
await expect(blockTextInput).toBeVisible()
1162+
await expect(blockTextInput).toBeEditable()
1163+
})
1164+
11381165
test('lexical cursor / selection should be preserved when swapping upload field and clicking within with its list drawer', async () => {
11391166
await navigateToLexicalFields()
11401167
const richTextField = page.locator('.rich-text-lexical').first()
@@ -1494,6 +1521,7 @@ describe('lexicalMain', () => {
14941521
expect(htmlContent).not.toContain('Cargando...')
14951522
expect(htmlContent).toContain('Start typing, or press')
14961523
})
1524+
// eslint-disable-next-line playwright/expect-expect, playwright/no-skipped-test
14971525
test.skip('ensure simple localized lexical field works', async () => {
14981526
await navigateToLexicalFields(true, 'lexical-localized-fields')
14991527
})

test/fields/collections/LexicalAccessControl/index.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CollectionConfig } from 'payload'
22

3-
import { defaultEditorFeatures, lexicalEditor } from '@payloadcms/richtext-lexical'
3+
import { defaultEditorFeatures, lexicalEditor, LinkFeature } from '@payloadcms/richtext-lexical'
44

55
import { lexicalAccessControlSlug } from '../../slugs.js'
66

@@ -22,7 +22,29 @@ export const LexicalAccessControl: CollectionConfig = {
2222
name: 'richText',
2323
type: 'richText',
2424
editor: lexicalEditor({
25-
features: [...defaultEditorFeatures],
25+
features: [
26+
...defaultEditorFeatures,
27+
LinkFeature({
28+
fields: ({ defaultFields }) => [
29+
...defaultFields,
30+
{
31+
name: 'blocks',
32+
type: 'blocks',
33+
blocks: [
34+
{
35+
slug: 'block',
36+
fields: [
37+
{
38+
name: 'text',
39+
type: 'text',
40+
},
41+
],
42+
},
43+
],
44+
},
45+
],
46+
}),
47+
],
2648
}),
2749
},
2850
],

test/fields/seed.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,67 @@ export const seed = async (_payload: Payload) => {
591591
await _payload.create({
592592
collection: 'lexical-access-control',
593593
data: {
594-
richText: textToLexicalJSON({ text: 'text' }),
594+
richText: {
595+
root: {
596+
children: [
597+
{
598+
children: [
599+
{
600+
detail: 0,
601+
format: 0,
602+
mode: 'normal',
603+
style: '',
604+
text: 'text ',
605+
type: 'text',
606+
version: 1,
607+
},
608+
{
609+
children: [
610+
{
611+
detail: 0,
612+
format: 0,
613+
mode: 'normal',
614+
style: '',
615+
text: 'link',
616+
type: 'text',
617+
version: 1,
618+
},
619+
],
620+
direction: 'ltr',
621+
format: '',
622+
indent: 0,
623+
type: 'link',
624+
version: 3,
625+
fields: {
626+
url: 'https://',
627+
newTab: false,
628+
linkType: 'custom',
629+
blocks: [
630+
{
631+
id: '67e45673cbd5181ca8cbeef7',
632+
blockType: 'block',
633+
},
634+
],
635+
},
636+
id: '67e4566fcbd5181ca8cbeef5',
637+
},
638+
],
639+
direction: 'ltr',
640+
format: '',
641+
indent: 0,
642+
type: 'paragraph',
643+
version: 1,
644+
textFormat: 0,
645+
textStyle: '',
646+
},
647+
],
648+
direction: 'ltr',
649+
format: '',
650+
indent: 0,
651+
type: 'root',
652+
version: 1,
653+
},
654+
},
595655
title: 'title',
596656
},
597657
depth: 0,

0 commit comments

Comments
 (0)