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:
@@ -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,
|
||||||
|
|||||||
22
test/access-control/collections/RichText/index.ts
Normal file
22
test/access-control/collections/RichText/index.ts
Normal 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',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -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: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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".
|
||||||
|
|||||||
Reference in New Issue
Block a user