Skip to content

Commit 131d1be

Browse files
authored
fix(ui): lexical was incorrectly set to readonly in blocks (#9237)
Fixes a bug introduced in `beta-131` that rendered Lexical fields as read-only if they were within a block.
1 parent 30d66bf commit 131d1be

File tree

5 files changed

+115
-4
lines changed

5 files changed

+115
-4
lines changed

packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
136136
const disabledFromAdmin = field?.admin && 'disabled' in field.admin && field.admin.disabled
137137

138138
if (fieldAffectsData(field) && !(isHiddenField || disabledFromAdmin)) {
139-
const fieldPermissions = permissions[field.name]
139+
const fieldPermissions = permissions === true ? permissions : permissions?.[field.name]
140140

141141
let hasPermission: boolean = fieldPermissions === true || fieldPermissions?.read
142142

@@ -382,7 +382,10 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
382382
parentPassesCondition: passesCondition,
383383
parentPath,
384384
parentSchemaPath: rowSchemaPath,
385-
permissions: permissions?.[field.name]?.blocks?.[block.slug]?.fields || {},
385+
permissions:
386+
fieldPermissions === true
387+
? fieldPermissions
388+
: permissions?.[field.name]?.blocks?.[block.slug]?.fields || {},
386389
preferences,
387390
previousFormState,
388391
renderAllFields: requiresRender,
@@ -467,7 +470,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
467470
parentPassesCondition: passesCondition,
468471
parentPath: path,
469472
parentSchemaPath: schemaPath,
470-
permissions: permissions?.[field.name]?.fields || {},
473+
permissions: fieldPermissions ?? permissions?.[field.name]?.fields ?? {},
471474
preferences,
472475
previousFormState,
473476
renderAllFields,
@@ -658,7 +661,11 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
658661
parentPassesCondition: passesCondition,
659662
parentPath: tabHasName(tab) ? tabPath : parentPath,
660663
parentSchemaPath: tabHasName(tab) ? tabSchemaPath : parentSchemaPath,
661-
permissions: tabHasName(tab) ? permissions?.[tab.name]?.fields || {} : permissions,
664+
permissions: tabHasName(tab)
665+
? typeof permissions === 'boolean'
666+
? permissions
667+
: permissions?.[tab.name] || {}
668+
: permissions,
662669
preferences,
663670
previousFormState,
664671
renderAllFields,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { CollectionConfig } from 'payload'
2+
3+
export const RichText: CollectionConfig = {
4+
slug: 'rich-text',
5+
fields: [
6+
{
7+
name: 'blocks',
8+
type: 'blocks',
9+
blocks: [
10+
{
11+
slug: 'richText',
12+
fields: [
13+
{
14+
name: 'richText',
15+
type: 'richText',
16+
},
17+
],
18+
},
19+
],
20+
},
21+
],
22+
}

test/access-control/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { Config, User } from './payload-types.js'
99
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
1010
import { devUser } from '../credentials.js'
1111
import { Disabled } from './collections/Disabled/index.js'
12+
import { RichText } from './collections/RichText/index.js'
1213
import {
1314
createNotUpdateCollectionSlug,
1415
docLevelAccessSlug,
@@ -506,6 +507,7 @@ export default buildConfigWithDefaults({
506507
],
507508
},
508509
Disabled,
510+
RichText,
509511
],
510512
globals: [
511513
{

test/access-control/e2e.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ describe('access control', () => {
6565
let restrictedUrl: AdminUrlUtil
6666
let unrestrictedURL: AdminUrlUtil
6767
let readOnlyCollectionUrl: AdminUrlUtil
68+
let richTextUrl: AdminUrlUtil
6869
let readOnlyGlobalUrl: AdminUrlUtil
6970
let restrictedVersionsUrl: AdminUrlUtil
7071
let userRestrictedCollectionURL: AdminUrlUtil
@@ -80,6 +81,7 @@ describe('access control', () => {
8081

8182
url = new AdminUrlUtil(serverURL, slug)
8283
restrictedUrl = new AdminUrlUtil(serverURL, fullyRestrictedSlug)
84+
richTextUrl = new AdminUrlUtil(serverURL, 'rich-text')
8385
unrestrictedURL = new AdminUrlUtil(serverURL, unrestrictedSlug)
8486
readOnlyCollectionUrl = new AdminUrlUtil(serverURL, readOnlySlug)
8587
readOnlyGlobalUrl = new AdminUrlUtil(serverURL, readOnlySlug)
@@ -147,6 +149,28 @@ describe('access control', () => {
147149
})
148150
})
149151

152+
describe('rich text', () => {
153+
test('rich text within block should render as editable', async () => {
154+
await page.goto(richTextUrl.create)
155+
156+
await page.locator('.blocks-field__drawer-toggler').click()
157+
await page.locator('.thumbnail-card').click()
158+
const richTextField = page.locator('.rich-text-lexical')
159+
const contentEditable = richTextField.locator('.ContentEditable__root').first()
160+
await expect(contentEditable).toBeVisible()
161+
await contentEditable.click()
162+
163+
const typedText = 'Hello, this field is editable!'
164+
await page.keyboard.type(typedText)
165+
166+
await expect(
167+
page.locator('[data-lexical-text="true"]', {
168+
hasText: exactText(typedText),
169+
}),
170+
).toHaveCount(1)
171+
})
172+
})
173+
150174
describe('collection — fully restricted', () => {
151175
let existingDoc: ReadOnlyCollection
152176

test/access-control/payload-types.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface Config {
2929
'hidden-access': HiddenAccess;
3030
'hidden-access-count': HiddenAccessCount;
3131
disabled: Disabled;
32+
'rich-text': RichText;
3233
'payload-locked-documents': PayloadLockedDocument;
3334
'payload-preferences': PayloadPreference;
3435
'payload-migrations': PayloadMigration;
@@ -52,6 +53,7 @@ export interface Config {
5253
'hidden-access': HiddenAccessSelect<false> | HiddenAccessSelect<true>;
5354
'hidden-access-count': HiddenAccessCountSelect<false> | HiddenAccessCountSelect<true>;
5455
disabled: DisabledSelect<false> | DisabledSelect<true>;
56+
'rich-text': RichTextSelect<false> | RichTextSelect<true>;
5557
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
5658
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
5759
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
@@ -350,6 +352,37 @@ export interface Disabled {
350352
updatedAt: string;
351353
createdAt: string;
352354
}
355+
/**
356+
* This interface was referenced by `Config`'s JSON-Schema
357+
* via the `definition` "rich-text".
358+
*/
359+
export interface RichText {
360+
id: string;
361+
blocks?:
362+
| {
363+
richText?: {
364+
root: {
365+
type: string;
366+
children: {
367+
type: string;
368+
version: number;
369+
[k: string]: unknown;
370+
}[];
371+
direction: ('ltr' | 'rtl') | null;
372+
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
373+
indent: number;
374+
version: number;
375+
};
376+
[k: string]: unknown;
377+
} | null;
378+
id?: string | null;
379+
blockName?: string | null;
380+
blockType: 'richText';
381+
}[]
382+
| null;
383+
updatedAt: string;
384+
createdAt: string;
385+
}
353386
/**
354387
* This interface was referenced by `Config`'s JSON-Schema
355388
* via the `definition` "payload-locked-documents".
@@ -424,6 +457,10 @@ export interface PayloadLockedDocument {
424457
| ({
425458
relationTo: 'disabled';
426459
value: string | Disabled;
460+
} | null)
461+
| ({
462+
relationTo: 'rich-text';
463+
value: string | RichText;
427464
} | null);
428465
globalSlug?: string | null;
429466
user:
@@ -694,6 +731,25 @@ export interface DisabledSelect<T extends boolean = true> {
694731
updatedAt?: T;
695732
createdAt?: T;
696733
}
734+
/**
735+
* This interface was referenced by `Config`'s JSON-Schema
736+
* via the `definition` "rich-text_select".
737+
*/
738+
export interface RichTextSelect<T extends boolean = true> {
739+
blocks?:
740+
| T
741+
| {
742+
richText?:
743+
| T
744+
| {
745+
richText?: T;
746+
id?: T;
747+
blockName?: T;
748+
};
749+
};
750+
updatedAt?: T;
751+
createdAt?: T;
752+
}
697753
/**
698754
* This interface was referenced by `Config`'s JSON-Schema
699755
* via the `definition` "payload-locked-documents_select".

0 commit comments

Comments
 (0)