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.
This commit is contained in:
James Mikrut
2024-11-15 17:47:26 -05:00
committed by GitHub
parent 30d66bf601
commit 131d1be8fc
5 changed files with 115 additions and 4 deletions

View File

@@ -136,7 +136,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
const disabledFromAdmin = field?.admin && 'disabled' in field.admin && field.admin.disabled const disabledFromAdmin = field?.admin && 'disabled' in field.admin && field.admin.disabled
if (fieldAffectsData(field) && !(isHiddenField || disabledFromAdmin)) { if (fieldAffectsData(field) && !(isHiddenField || disabledFromAdmin)) {
const fieldPermissions = permissions[field.name] const fieldPermissions = permissions === true ? permissions : permissions?.[field.name]
let hasPermission: boolean = fieldPermissions === true || fieldPermissions?.read let hasPermission: boolean = fieldPermissions === true || fieldPermissions?.read
@@ -382,7 +382,10 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
parentPassesCondition: passesCondition, parentPassesCondition: passesCondition,
parentPath, parentPath,
parentSchemaPath: rowSchemaPath, parentSchemaPath: rowSchemaPath,
permissions: permissions?.[field.name]?.blocks?.[block.slug]?.fields || {}, permissions:
fieldPermissions === true
? fieldPermissions
: permissions?.[field.name]?.blocks?.[block.slug]?.fields || {},
preferences, preferences,
previousFormState, previousFormState,
renderAllFields: requiresRender, renderAllFields: requiresRender,
@@ -467,7 +470,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
parentPassesCondition: passesCondition, parentPassesCondition: passesCondition,
parentPath: path, parentPath: path,
parentSchemaPath: schemaPath, parentSchemaPath: schemaPath,
permissions: permissions?.[field.name]?.fields || {}, permissions: fieldPermissions ?? permissions?.[field.name]?.fields ?? {},
preferences, preferences,
previousFormState, previousFormState,
renderAllFields, renderAllFields,
@@ -658,7 +661,11 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
parentPassesCondition: passesCondition, parentPassesCondition: passesCondition,
parentPath: tabHasName(tab) ? tabPath : parentPath, parentPath: tabHasName(tab) ? tabPath : parentPath,
parentSchemaPath: tabHasName(tab) ? tabSchemaPath : parentSchemaPath, parentSchemaPath: tabHasName(tab) ? tabSchemaPath : parentSchemaPath,
permissions: tabHasName(tab) ? permissions?.[tab.name]?.fields || {} : permissions, permissions: tabHasName(tab)
? typeof permissions === 'boolean'
? permissions
: permissions?.[tab.name] || {}
: permissions,
preferences, preferences,
previousFormState, previousFormState,
renderAllFields, renderAllFields,

View File

@@ -0,0 +1,22 @@
import type { CollectionConfig } from 'payload'
export const RichText: CollectionConfig = {
slug: 'rich-text',
fields: [
{
name: 'blocks',
type: 'blocks',
blocks: [
{
slug: 'richText',
fields: [
{
name: 'richText',
type: 'richText',
},
],
},
],
},
],
}

View File

@@ -9,6 +9,7 @@ import type { Config, User } from './payload-types.js'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { devUser } from '../credentials.js' import { devUser } from '../credentials.js'
import { Disabled } from './collections/Disabled/index.js' import { Disabled } from './collections/Disabled/index.js'
import { RichText } from './collections/RichText/index.js'
import { import {
createNotUpdateCollectionSlug, createNotUpdateCollectionSlug,
docLevelAccessSlug, docLevelAccessSlug,
@@ -506,6 +507,7 @@ export default buildConfigWithDefaults({
], ],
}, },
Disabled, Disabled,
RichText,
], ],
globals: [ globals: [
{ {

View File

@@ -65,6 +65,7 @@ describe('access control', () => {
let restrictedUrl: AdminUrlUtil let restrictedUrl: AdminUrlUtil
let unrestrictedURL: AdminUrlUtil let unrestrictedURL: AdminUrlUtil
let readOnlyCollectionUrl: AdminUrlUtil let readOnlyCollectionUrl: AdminUrlUtil
let richTextUrl: AdminUrlUtil
let readOnlyGlobalUrl: AdminUrlUtil let readOnlyGlobalUrl: AdminUrlUtil
let restrictedVersionsUrl: AdminUrlUtil let restrictedVersionsUrl: AdminUrlUtil
let userRestrictedCollectionURL: AdminUrlUtil let userRestrictedCollectionURL: AdminUrlUtil
@@ -80,6 +81,7 @@ describe('access control', () => {
url = new AdminUrlUtil(serverURL, slug) url = new AdminUrlUtil(serverURL, slug)
restrictedUrl = new AdminUrlUtil(serverURL, fullyRestrictedSlug) restrictedUrl = new AdminUrlUtil(serverURL, fullyRestrictedSlug)
richTextUrl = new AdminUrlUtil(serverURL, 'rich-text')
unrestrictedURL = new AdminUrlUtil(serverURL, unrestrictedSlug) unrestrictedURL = new AdminUrlUtil(serverURL, unrestrictedSlug)
readOnlyCollectionUrl = new AdminUrlUtil(serverURL, readOnlySlug) readOnlyCollectionUrl = new AdminUrlUtil(serverURL, readOnlySlug)
readOnlyGlobalUrl = new AdminUrlUtil(serverURL, readOnlySlug) readOnlyGlobalUrl = new AdminUrlUtil(serverURL, readOnlySlug)
@@ -147,6 +149,28 @@ describe('access control', () => {
}) })
}) })
describe('rich text', () => {
test('rich text within block should render as editable', async () => {
await page.goto(richTextUrl.create)
await page.locator('.blocks-field__drawer-toggler').click()
await page.locator('.thumbnail-card').click()
const richTextField = page.locator('.rich-text-lexical')
const contentEditable = richTextField.locator('.ContentEditable__root').first()
await expect(contentEditable).toBeVisible()
await contentEditable.click()
const typedText = 'Hello, this field is editable!'
await page.keyboard.type(typedText)
await expect(
page.locator('[data-lexical-text="true"]', {
hasText: exactText(typedText),
}),
).toHaveCount(1)
})
})
describe('collection — fully restricted', () => { describe('collection — fully restricted', () => {
let existingDoc: ReadOnlyCollection let existingDoc: ReadOnlyCollection

View File

@@ -29,6 +29,7 @@ export interface Config {
'hidden-access': HiddenAccess; 'hidden-access': HiddenAccess;
'hidden-access-count': HiddenAccessCount; 'hidden-access-count': HiddenAccessCount;
disabled: Disabled; disabled: Disabled;
'rich-text': RichText;
'payload-locked-documents': PayloadLockedDocument; 'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference; 'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration; 'payload-migrations': PayloadMigration;
@@ -52,6 +53,7 @@ export interface Config {
'hidden-access': HiddenAccessSelect<false> | HiddenAccessSelect<true>; 'hidden-access': HiddenAccessSelect<false> | HiddenAccessSelect<true>;
'hidden-access-count': HiddenAccessCountSelect<false> | HiddenAccessCountSelect<true>; 'hidden-access-count': HiddenAccessCountSelect<false> | HiddenAccessCountSelect<true>;
disabled: DisabledSelect<false> | DisabledSelect<true>; disabled: DisabledSelect<false> | DisabledSelect<true>;
'rich-text': RichTextSelect<false> | RichTextSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>; 'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>; 'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>; 'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
@@ -350,6 +352,37 @@ export interface Disabled {
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "rich-text".
*/
export interface RichText {
id: string;
blocks?:
| {
richText?: {
root: {
type: string;
children: {
type: string;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
} | null;
id?: string | null;
blockName?: string | null;
blockType: 'richText';
}[]
| null;
updatedAt: string;
createdAt: string;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents". * via the `definition` "payload-locked-documents".
@@ -424,6 +457,10 @@ export interface PayloadLockedDocument {
| ({ | ({
relationTo: 'disabled'; relationTo: 'disabled';
value: string | Disabled; value: string | Disabled;
} | null)
| ({
relationTo: 'rich-text';
value: string | RichText;
} | null); } | null);
globalSlug?: string | null; globalSlug?: string | null;
user: user:
@@ -694,6 +731,25 @@ export interface DisabledSelect<T extends boolean = true> {
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "rich-text_select".
*/
export interface RichTextSelect<T extends boolean = true> {
blocks?:
| T
| {
richText?:
| T
| {
richText?: T;
id?: T;
blockName?: T;
};
};
updatedAt?: T;
createdAt?: T;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select". * via the `definition` "payload-locked-documents_select".