chore: separate Lexical tests into dedicated suite (#12047)

Lexical tests comprise almost half of the collections in the fields
suite, and are starting to become complex to manage.

They are sometimes related to other auxiliary collections, so
refactoring one test sometimes breaks another, seemingly unrelated one.

In addition, the fields suite is very large, taking a long time to
compile. This will make it faster.

Some ideas for future refactorings:
- 3 main collections: defaultFeatures, fully featured, and legacy.
Legacy is the current one that has multiple editors and could later be
migrated to the first two.
- Avoid collections with more than 1 editor.
- Create reseed buttons to restore the editor to certain states, to
avoid a proliferation of collections and documents.
- Reduce the complexity of the three auxiliary collections (text, array,
upload), which are rarely or never used and have many fields designed
for tests in the fields suite.
This commit is contained in:
Germán Jabloñski
2025-04-10 20:47:26 -03:00
committed by GitHub
parent 272914c818
commit a66f90ebb6
68 changed files with 2668 additions and 1210 deletions

View File

@@ -294,14 +294,10 @@ jobs:
- fields__collections__Email - fields__collections__Email
- fields__collections__Indexed - fields__collections__Indexed
- fields__collections__JSON - fields__collections__JSON
- fields__collections__Lexical__e2e__main
- fields__collections__Lexical__e2e__blocks
- fields__collections__Lexical__e2e__blocks#config.blockreferences.ts
- fields__collections__Number - fields__collections__Number
- fields__collections__Point - fields__collections__Point
- fields__collections__Radio - fields__collections__Radio
- fields__collections__Relationship - fields__collections__Relationship
- fields__collections__RichText
- fields__collections__Row - fields__collections__Row
- fields__collections__Select - fields__collections__Select
- fields__collections__Tabs - fields__collections__Tabs
@@ -310,6 +306,10 @@ jobs:
- fields__collections__UI - fields__collections__UI
- fields__collections__Upload - fields__collections__Upload
- hooks - hooks
- lexical__collections__Lexical__e2e__main
- lexical__collections__Lexical__e2e__blocks
- lexical__collections__Lexical__e2e__blocks#config.blockreferences.ts
- lexical__collections__RichText
- query-presets - query-presets
- form-state - form-state
- live-preview - live-preview

View File

@@ -8,7 +8,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 { textToLexicalJSON } from '../fields/collections/LexicalLocalized/textToLexicalJSON.js' import { textToLexicalJSON } from '../lexical/collections/LexicalLocalized/textToLexicalJSON.js'
import { Disabled } from './collections/Disabled/index.js' import { Disabled } from './collections/Disabled/index.js'
import { Hooks } from './collections/hooks/index.js' import { Hooks } from './collections/hooks/index.js'
import { Regression1 } from './collections/Regression-1/index.js' import { Regression1 } from './collections/Regression-1/index.js'

View File

@@ -20,22 +20,10 @@ import EmailFields from './collections/Email/index.js'
import GroupFields from './collections/Group/index.js' import GroupFields from './collections/Group/index.js'
import IndexedFields from './collections/Indexed/index.js' import IndexedFields from './collections/Indexed/index.js'
import JSONFields from './collections/JSON/index.js' import JSONFields from './collections/JSON/index.js'
import {
getLexicalFieldsCollection,
lexicalBlocks,
lexicalInlineBlocks,
} from './collections/Lexical/index.js'
import { LexicalAccessControl } from './collections/LexicalAccessControl/index.js'
import { LexicalInBlock } from './collections/LexicalInBlock/index.js'
import { LexicalLocalizedFields } from './collections/LexicalLocalized/index.js'
import { LexicalMigrateFields } from './collections/LexicalMigrate/index.js'
import { LexicalObjectReferenceBugCollection } from './collections/LexicalObjectReferenceBug/index.js'
import { LexicalRelationshipsFields } from './collections/LexicalRelationships/index.js'
import NumberFields from './collections/Number/index.js' import NumberFields from './collections/Number/index.js'
import PointFields from './collections/Point/index.js' import PointFields from './collections/Point/index.js'
import RadioFields from './collections/Radio/index.js' import RadioFields from './collections/Radio/index.js'
import RelationshipFields from './collections/Relationship/index.js' import RelationshipFields from './collections/Relationship/index.js'
import RichTextFields from './collections/RichText/index.js'
import RowFields from './collections/Row/index.js' import RowFields from './collections/Row/index.js'
import SelectFields from './collections/Select/index.js' import SelectFields from './collections/Select/index.js'
import SelectVersionsFields from './collections/SelectVersions/index.js' import SelectVersionsFields from './collections/SelectVersions/index.js'
@@ -50,17 +38,9 @@ import UploadsMultiPoly from './collections/UploadMultiPoly/index.js'
import UploadsPoly from './collections/UploadPoly/index.js' import UploadsPoly from './collections/UploadPoly/index.js'
import UploadRestricted from './collections/UploadRestricted/index.js' import UploadRestricted from './collections/UploadRestricted/index.js'
import Uploads3 from './collections/Uploads3/index.js' import Uploads3 from './collections/Uploads3/index.js'
import TabsWithRichText from './globals/TabsWithRichText.js'
import { clearAndSeedEverything } from './seed.js' import { clearAndSeedEverything } from './seed.js'
export const collectionSlugs: CollectionConfig[] = [ export const collectionSlugs: CollectionConfig[] = [
getLexicalFieldsCollection({
blocks: lexicalBlocks,
inlineBlocks: lexicalInlineBlocks,
}),
LexicalMigrateFields,
LexicalLocalizedFields,
LexicalObjectReferenceBugCollection,
{ {
slug: 'users', slug: 'users',
admin: { admin: {
@@ -75,8 +55,6 @@ export const collectionSlugs: CollectionConfig[] = [
}, },
], ],
}, },
LexicalInBlock,
LexicalAccessControl,
SelectVersionsFields, SelectVersionsFields,
ArrayFields, ArrayFields,
BlockFields, BlockFields,
@@ -97,8 +75,6 @@ export const collectionSlugs: CollectionConfig[] = [
NumberFields, NumberFields,
PointFields, PointFields,
RelationshipFields, RelationshipFields,
LexicalRelationshipsFields,
RichTextFields,
SelectFields, SelectFields,
TabsFields2, TabsFields2,
TabsFields, TabsFields,
@@ -115,7 +91,6 @@ export const collectionSlugs: CollectionConfig[] = [
export const baseConfig: Partial<Config> = { export const baseConfig: Partial<Config> = {
collections: collectionSlugs, collections: collectionSlugs,
globals: [TabsWithRichText],
blocks: [ blocks: [
{ {
slug: 'ConfigBlockTest', slug: 'ConfigBlockTest',

View File

@@ -1,35 +1,10 @@
/* eslint-disable no-restricted-exports */ /* eslint-disable no-restricted-exports */
import type { BlockSlug } from 'payload'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { autoDedupeBlocksPlugin } from '../helpers/autoDedupeBlocksPlugin/index.js' import { autoDedupeBlocksPlugin } from '../helpers/autoDedupeBlocksPlugin/index.js'
import { baseConfig } from './baseConfig.js' import { baseConfig } from './baseConfig.js'
import {
getLexicalFieldsCollection,
lexicalBlocks,
lexicalInlineBlocks,
} from './collections/Lexical/index.js'
import { lexicalFieldsSlug } from './slugs.js'
export default buildConfigWithDefaults({ export default buildConfigWithDefaults({
...baseConfig, ...baseConfig,
blocks: [
...(baseConfig.blocks ?? []),
...lexicalBlocks.filter((block) => typeof block !== 'string'),
...lexicalInlineBlocks.filter((block) => typeof block !== 'string'),
],
collections: baseConfig.collections?.map((collection) => {
if (collection.slug === lexicalFieldsSlug) {
return getLexicalFieldsCollection({
blocks: lexicalBlocks.map((block) =>
typeof block === 'string' ? block : block.slug,
) as BlockSlug[],
inlineBlocks: lexicalInlineBlocks.map((block) =>
typeof block === 'string' ? block : block.slug,
) as BlockSlug[],
})
}
return collection
}),
plugins: [autoDedupeBlocksPlugin({ silent: true })], plugins: [autoDedupeBlocksPlugin({ silent: true })],
}) })

View File

@@ -2,11 +2,11 @@ import type { MongooseAdapter } from '@payloadcms/db-mongodb'
import type { IndexDirection, IndexOptions } from 'mongoose' import type { IndexDirection, IndexOptions } from 'mongoose'
import path from 'path' import path from 'path'
import { type PaginatedDocs, type Payload, reload } from 'payload' import { type Payload, reload } from 'payload'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { NextRESTClient } from '../helpers/NextRESTClient.js'
import type { BlockField, GroupField, RichTextField } from './payload-types.js' import type { BlockField, GroupField } from './payload-types.js'
import { devUser } from '../credentials.js' import { devUser } from '../credentials.js'
import { initPayloadInt } from '../helpers/initPayloadInt.js' import { initPayloadInt } from '../helpers/initPayloadInt.js'
@@ -3023,91 +3023,6 @@ describe('Fields', () => {
}) })
}) })
describe('richText', () => {
it('should allow querying on rich text content', async () => {
const emptyRichTextQuery = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.text': {
like: 'doesnt exist',
},
},
})
expect(emptyRichTextQuery.docs).toHaveLength(0)
const workingRichTextQuery = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.text': {
like: 'hello',
},
},
})
expect(workingRichTextQuery.docs).toHaveLength(1)
})
it('should show center alignment', async () => {
const query = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.text': {
like: 'hello',
},
},
})
expect(query.docs[0].richText[0].textAlign).toEqual('center')
})
it('should populate link relationship', async () => {
const query = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.linkType': {
equals: 'internal',
},
},
})
const nodes = query.docs[0].richText
expect(nodes).toBeDefined()
const child = nodes.flatMap((n) => n.children).find((c) => c.doc)
expect(child).toMatchObject({
type: 'link',
linkType: 'internal',
})
expect(child.doc.relationTo).toEqual('array-fields')
if (payload.db.defaultIDType === 'number') {
expect(typeof child.doc.value.id).toBe('number')
} else {
expect(typeof child.doc.value.id).toBe('string')
}
expect(child.doc.value.items).toHaveLength(6)
})
it('should respect rich text depth parameter', async () => {
const query = `query {
RichTextFields {
docs {
richText(depth: 2)
}
}
}`
const { data } = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query }),
})
.then((res) => res.json())
const { docs }: PaginatedDocs<RichTextField> = data.RichTextFields
const uploadElement = docs[0].richText.find((el) => el.type === 'upload') as any
expect(uploadElement.value.media.filename).toStrictEqual('payload.png')
})
})
describe('relationships', () => { describe('relationships', () => {
it('should not crash if querying with empty in operator', async () => { it('should not crash if querying with empty in operator', async () => {
const query = await payload.find({ const query = await payload.find({

View File

@@ -61,22 +61,6 @@ export type SupportedTimezones =
| 'Pacific/Auckland' | 'Pacific/Auckland'
| 'Pacific/Fiji' | 'Pacific/Fiji'
| 'America/Monterrey'; | 'America/Monterrey';
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "BlockColumns".
*/
export type BlockColumns =
| {
text?: string | null;
subArray?:
| {
requiredText: string;
id?: string | null;
}[]
| null;
id?: string | null;
}[]
| null;
export interface Config { export interface Config {
auth: { auth: {
@@ -88,13 +72,7 @@ export interface Config {
localizedTextReference2: LocalizedTextReference2; localizedTextReference2: LocalizedTextReference2;
}; };
collections: { collections: {
'lexical-fields': LexicalField;
'lexical-migrate-fields': LexicalMigrateField;
'lexical-localized-fields': LexicalLocalizedField;
lexicalObjectReferenceBug: LexicalObjectReferenceBug;
users: User; users: User;
LexicalInBlock: LexicalInBlock;
'lexical-access-control': LexicalAccessControl;
'select-versions-fields': SelectVersionsField; 'select-versions-fields': SelectVersionsField;
'array-fields': ArrayField; 'array-fields': ArrayField;
'block-fields': BlockField; 'block-fields': BlockField;
@@ -115,8 +93,6 @@ export interface Config {
'number-fields': NumberField; 'number-fields': NumberField;
'point-fields': PointField; 'point-fields': PointField;
'relationship-fields': RelationshipField; 'relationship-fields': RelationshipField;
'lexical-relationship-fields': LexicalRelationshipField;
'rich-text-fields': RichTextField;
'select-fields': SelectField; 'select-fields': SelectField;
'tabs-fields-2': TabsFields2; 'tabs-fields-2': TabsFields2;
'tabs-fields': TabsField; 'tabs-fields': TabsField;
@@ -135,13 +111,7 @@ export interface Config {
}; };
collectionsJoins: {}; collectionsJoins: {};
collectionsSelect: { collectionsSelect: {
'lexical-fields': LexicalFieldsSelect<false> | LexicalFieldsSelect<true>;
'lexical-migrate-fields': LexicalMigrateFieldsSelect<false> | LexicalMigrateFieldsSelect<true>;
'lexical-localized-fields': LexicalLocalizedFieldsSelect<false> | LexicalLocalizedFieldsSelect<true>;
lexicalObjectReferenceBug: LexicalObjectReferenceBugSelect<false> | LexicalObjectReferenceBugSelect<true>;
users: UsersSelect<false> | UsersSelect<true>; users: UsersSelect<false> | UsersSelect<true>;
LexicalInBlock: LexicalInBlockSelect<false> | LexicalInBlockSelect<true>;
'lexical-access-control': LexicalAccessControlSelect<false> | LexicalAccessControlSelect<true>;
'select-versions-fields': SelectVersionsFieldsSelect<false> | SelectVersionsFieldsSelect<true>; 'select-versions-fields': SelectVersionsFieldsSelect<false> | SelectVersionsFieldsSelect<true>;
'array-fields': ArrayFieldsSelect<false> | ArrayFieldsSelect<true>; 'array-fields': ArrayFieldsSelect<false> | ArrayFieldsSelect<true>;
'block-fields': BlockFieldsSelect<false> | BlockFieldsSelect<true>; 'block-fields': BlockFieldsSelect<false> | BlockFieldsSelect<true>;
@@ -162,8 +132,6 @@ export interface Config {
'number-fields': NumberFieldsSelect<false> | NumberFieldsSelect<true>; 'number-fields': NumberFieldsSelect<false> | NumberFieldsSelect<true>;
'point-fields': PointFieldsSelect<false> | PointFieldsSelect<true>; 'point-fields': PointFieldsSelect<false> | PointFieldsSelect<true>;
'relationship-fields': RelationshipFieldsSelect<false> | RelationshipFieldsSelect<true>; 'relationship-fields': RelationshipFieldsSelect<false> | RelationshipFieldsSelect<true>;
'lexical-relationship-fields': LexicalRelationshipFieldsSelect<false> | LexicalRelationshipFieldsSelect<true>;
'rich-text-fields': RichTextFieldsSelect<false> | RichTextFieldsSelect<true>;
'select-fields': SelectFieldsSelect<false> | SelectFieldsSelect<true>; 'select-fields': SelectFieldsSelect<false> | SelectFieldsSelect<true>;
'tabs-fields-2': TabsFields2Select<false> | TabsFields2Select<true>; 'tabs-fields-2': TabsFields2Select<false> | TabsFields2Select<true>;
'tabs-fields': TabsFieldsSelect<false> | TabsFieldsSelect<true>; 'tabs-fields': TabsFieldsSelect<false> | TabsFieldsSelect<true>;
@@ -183,12 +151,8 @@ export interface Config {
db: { db: {
defaultIDType: string; defaultIDType: string;
}; };
globals: { globals: {};
tabsWithRichText: TabsWithRichText; globalsSelect: {};
};
globalsSelect: {
tabsWithRichText: TabsWithRichTextSelect<false> | TabsWithRichTextSelect<true>;
};
locale: 'en' | 'es'; locale: 'en' | 'es';
user: User & { user: User & {
collection: 'users'; collection: 'users';
@@ -246,242 +210,6 @@ export interface LocalizedTextReference2 {
blockName?: string | null; blockName?: string | null;
blockType: 'localizedTextReference2'; blockType: 'localizedTextReference2';
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-fields".
*/
export interface LexicalField {
id: string;
title: string;
lexicalRootEditor?: {
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;
lexicalSimple?: {
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;
lexicalWithBlocks: {
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;
};
lexicalWithBlocks_markdown?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-migrate-fields".
*/
export interface LexicalMigrateField {
id: string;
title: string;
lexicalWithLexicalPluginData?: {
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;
lexicalWithSlateData?: {
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;
lexicalSimple?: {
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;
lexicalSimple_html?: string | null;
groupWithLexicalField?: {
lexicalInGroupField?: {
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;
lexicalInGroupField_html?: string | null;
};
arrayWithLexicalField?:
| {
lexicalInArrayField?: {
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;
lexicalInArrayField_html?: string | null;
id?: string | null;
}[]
| null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-localized-fields".
*/
export interface LexicalLocalizedField {
id: string;
title: string;
/**
* Non-localized field with localized block subfields
*/
lexicalBlocksSubLocalized?: {
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;
/**
* Localized field with localized block subfields
*/
lexicalBlocksLocalized?: {
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;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexicalObjectReferenceBug".
*/
export interface LexicalObjectReferenceBug {
id: string;
lexicalDefault?: {
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;
lexicalEditor?: {
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;
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` "users". * via the `definition` "users".
@@ -500,77 +228,6 @@ export interface User {
lockUntil?: string | null; lockUntil?: string | null;
password?: string | null; password?: string | null;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "LexicalInBlock".
*/
export interface LexicalInBlock {
id: string;
content?: {
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;
blocks?:
| {
lexical?: {
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: 'lexicalInBlock2';
}[]
| null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-access-control".
*/
export interface LexicalAccessControl {
id: string;
title?: string | null;
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;
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` "select-versions-fields". * via the `definition` "select-versions-fields".
@@ -1658,126 +1315,6 @@ export interface RelationshipField {
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-relationship-fields".
*/
export interface LexicalRelationshipField {
id: string;
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;
richText2?: {
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;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "rich-text-fields".
*/
export interface RichTextField {
id: string;
title: string;
lexicalCustomFields: {
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;
};
lexicalCustomFields_html?: string | null;
/**
* This rich text field uses the lexical editor.
*/
lexical?: {
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;
/**
* This select field is rendered here to ensure its options dropdown renders above the rich text toolbar.
*/
selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null;
richText: {
[k: string]: unknown;
}[];
richTextCustomFields?:
| {
[k: string]: unknown;
}[]
| null;
richTextReadOnly?:
| {
[k: string]: unknown;
}[]
| null;
blocks?:
| (
| {
text?: string | null;
id?: string | null;
blockName?: string | null;
blockType: 'textBlock';
}
| {
text?:
| {
[k: string]: unknown;
}[]
| null;
id?: string | null;
blockName?: string | null;
blockType: 'richTextBlockSlate';
}
)[]
| 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` "select-fields". * via the `definition` "select-fields".
@@ -2067,34 +1604,10 @@ export interface UiField {
export interface PayloadLockedDocument { export interface PayloadLockedDocument {
id: string; id: string;
document?: document?:
| ({
relationTo: 'lexical-fields';
value: string | LexicalField;
} | null)
| ({
relationTo: 'lexical-migrate-fields';
value: string | LexicalMigrateField;
} | null)
| ({
relationTo: 'lexical-localized-fields';
value: string | LexicalLocalizedField;
} | null)
| ({
relationTo: 'lexicalObjectReferenceBug';
value: string | LexicalObjectReferenceBug;
} | null)
| ({ | ({
relationTo: 'users'; relationTo: 'users';
value: string | User; value: string | User;
} | null) } | null)
| ({
relationTo: 'LexicalInBlock';
value: string | LexicalInBlock;
} | null)
| ({
relationTo: 'lexical-access-control';
value: string | LexicalAccessControl;
} | null)
| ({ | ({
relationTo: 'select-versions-fields'; relationTo: 'select-versions-fields';
value: string | SelectVersionsField; value: string | SelectVersionsField;
@@ -2175,14 +1688,6 @@ export interface PayloadLockedDocument {
relationTo: 'relationship-fields'; relationTo: 'relationship-fields';
value: string | RelationshipField; value: string | RelationshipField;
} | null) } | null)
| ({
relationTo: 'lexical-relationship-fields';
value: string | LexicalRelationshipField;
} | null)
| ({
relationTo: 'rich-text-fields';
value: string | RichTextField;
} | null)
| ({ | ({
relationTo: 'select-fields'; relationTo: 'select-fields';
value: string | SelectField; value: string | SelectField;
@@ -2273,66 +1778,6 @@ export interface PayloadMigration {
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-fields_select".
*/
export interface LexicalFieldsSelect<T extends boolean = true> {
title?: T;
lexicalRootEditor?: T;
lexicalSimple?: T;
lexicalWithBlocks?: T;
lexicalWithBlocks_markdown?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-migrate-fields_select".
*/
export interface LexicalMigrateFieldsSelect<T extends boolean = true> {
title?: T;
lexicalWithLexicalPluginData?: T;
lexicalWithSlateData?: T;
lexicalSimple?: T;
lexicalSimple_html?: T;
groupWithLexicalField?:
| T
| {
lexicalInGroupField?: T;
lexicalInGroupField_html?: T;
};
arrayWithLexicalField?:
| T
| {
lexicalInArrayField?: T;
lexicalInArrayField_html?: T;
id?: T;
};
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-localized-fields_select".
*/
export interface LexicalLocalizedFieldsSelect<T extends boolean = true> {
title?: T;
lexicalBlocksSubLocalized?: T;
lexicalBlocksLocalized?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexicalObjectReferenceBug_select".
*/
export interface LexicalObjectReferenceBugSelect<T extends boolean = true> {
lexicalDefault?: T;
lexicalEditor?: 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` "users_select". * via the `definition` "users_select".
@@ -2349,36 +1794,6 @@ export interface UsersSelect<T extends boolean = true> {
loginAttempts?: T; loginAttempts?: T;
lockUntil?: T; lockUntil?: T;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "LexicalInBlock_select".
*/
export interface LexicalInBlockSelect<T extends boolean = true> {
content?: T;
blocks?:
| T
| {
lexicalInBlock2?:
| T
| {
lexical?: T;
id?: T;
blockName?: T;
};
};
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-access-control_select".
*/
export interface LexicalAccessControlSelect<T extends boolean = true> {
title?: T;
richText?: 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` "select-versions-fields_select". * via the `definition` "select-versions-fields_select".
@@ -3374,50 +2789,6 @@ export interface RelationshipFieldsSelect<T extends boolean = true> {
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "lexical-relationship-fields_select".
*/
export interface LexicalRelationshipFieldsSelect<T extends boolean = true> {
richText?: T;
richText2?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "rich-text-fields_select".
*/
export interface RichTextFieldsSelect<T extends boolean = true> {
title?: T;
lexicalCustomFields?: T;
lexicalCustomFields_html?: T;
lexical?: T;
selectHasMany?: T;
richText?: T;
richTextCustomFields?: T;
richTextReadOnly?: T;
blocks?:
| T
| {
textBlock?:
| T
| {
text?: T;
id?: T;
blockName?: T;
};
richTextBlockSlate?:
| T
| {
text?: 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` "select-fields_select". * via the `definition` "select-fields_select".
@@ -3766,93 +3137,6 @@ export interface PayloadMigrationsSelect<T extends boolean = true> {
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "tabsWithRichText".
*/
export interface TabsWithRichText {
id: string;
tab1?: {
rt1?: {
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;
};
tab2?: {
rt2?: {
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;
};
updatedAt?: string | null;
createdAt?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "tabsWithRichText_select".
*/
export interface TabsWithRichTextSelect<T extends boolean = true> {
tab1?:
| T
| {
rt1?: T;
};
tab2?:
| T
| {
rt2?: T;
};
updatedAt?: T;
createdAt?: T;
globalType?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "LexicalBlocksRadioButtonsBlock".
*/
export interface LexicalBlocksRadioButtonsBlock {
radioButtons?: ('option1' | 'option2' | 'option3') | null;
id?: string | null;
blockName?: string | null;
blockType: 'radioButtons';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "AvatarGroupBlock".
*/
export interface AvatarGroupBlock {
avatars?:
| {
image?: (string | null) | Upload;
id?: string | null;
}[]
| null;
id?: string | null;
blockName?: string | null;
blockType: 'AvatarGroup';
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth". * via the `definition` "auth".

View File

@@ -6,7 +6,9 @@ import { fileURLToPath } from 'url'
import { devUser } from '../credentials.js' import { devUser } from '../credentials.js'
import { seedDB } from '../helpers/seed.js' import { seedDB } from '../helpers/seed.js'
import { anotherArrayDoc, arrayDoc } from './collections/Array/shared.js' // TODO: decouple blocks from both test suites
import { richTextDocData } from '../lexical/collections/RichText/data.js'
import { arrayDoc } from './collections/Array/shared.js'
import { blocksDoc } from './collections/Blocks/shared.js' import { blocksDoc } from './collections/Blocks/shared.js'
import { codeDoc } from './collections/Code/shared.js' import { codeDoc } from './collections/Code/shared.js'
import { collapsibleDoc } from './collections/Collapsible/shared.js' import { collapsibleDoc } from './collections/Collapsible/shared.js'
@@ -16,14 +18,9 @@ import { dateDoc } from './collections/Date/shared.js'
import { anotherEmailDoc, emailDoc } from './collections/Email/shared.js' import { anotherEmailDoc, emailDoc } from './collections/Email/shared.js'
import { groupDoc } from './collections/Group/shared.js' import { groupDoc } from './collections/Group/shared.js'
import { jsonDoc } from './collections/JSON/shared.js' import { jsonDoc } from './collections/JSON/shared.js'
import { lexicalDocData } from './collections/Lexical/data.js'
import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js'
import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js'
import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js'
import { numberDoc } from './collections/Number/shared.js' import { numberDoc } from './collections/Number/shared.js'
import { pointDoc } from './collections/Point/shared.js' import { pointDoc } from './collections/Point/shared.js'
import { radiosDoc } from './collections/Radio/shared.js' import { radiosDoc } from './collections/Radio/shared.js'
import { richTextBulletsDocData, richTextDocData } from './collections/RichText/data.js'
import { selectsDoc } from './collections/Select/shared.js' import { selectsDoc } from './collections/Select/shared.js'
import { tabsDoc } from './collections/Tabs/shared.js' import { tabsDoc } from './collections/Tabs/shared.js'
import { anotherTextDoc, textDoc } from './collections/Text/shared.js' import { anotherTextDoc, textDoc } from './collections/Text/shared.js'
@@ -43,22 +40,15 @@ import {
emailFieldsSlug, emailFieldsSlug,
groupFieldsSlug, groupFieldsSlug,
jsonFieldsSlug, jsonFieldsSlug,
lexicalFieldsSlug,
lexicalLocalizedFieldsSlug,
lexicalMigrateFieldsSlug,
lexicalRelationshipFieldsSlug,
numberFieldsSlug, numberFieldsSlug,
pointFieldsSlug, pointFieldsSlug,
radioFieldsSlug, radioFieldsSlug,
relationshipFieldsSlug, relationshipFieldsSlug,
richTextFieldsSlug,
selectFieldsSlug, selectFieldsSlug,
tabsFieldsSlug, tabsFieldsSlug,
textFieldsSlug, textFieldsSlug,
uiSlug, uiSlug,
uploads2Slug,
uploadsMulti, uploadsMulti,
uploadsMultiPoly,
uploadsPoly, uploadsPoly,
uploadsSlug, uploadsSlug,
usersSlug, usersSlug,
@@ -86,13 +76,6 @@ export const seed = async (_payload: Payload) => {
overrideAccess: true, overrideAccess: true,
}) })
const createdAnotherArrayDoc = await _payload.create({
collection: arrayFieldsSlug,
data: anotherArrayDoc,
depth: 0,
overrideAccess: true,
})
const createdTextDoc = await _payload.create({ const createdTextDoc = await _payload.create({
collection: textFieldsSlug, collection: textFieldsSlug,
data: textDoc, data: textDoc,
@@ -177,7 +160,6 @@ export const seed = async (_payload: Payload) => {
// media: { value: createdJPGDocSlug2.id, relationTo: uploads2Slug }, // media: { value: createdJPGDocSlug2.id, relationTo: uploads2Slug },
// }, // },
// }) // })
const formattedID = const formattedID =
_payload.db.defaultIDType === 'number' ? createdArrayDoc.id : `"${createdArrayDoc.id}"` _payload.db.defaultIDType === 'number' ? createdArrayDoc.id : `"${createdArrayDoc.id}"`
@@ -193,29 +175,14 @@ export const seed = async (_payload: Payload) => {
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`), .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`),
) )
const richTextBulletsDocWithRelId = JSON.parse(
JSON.stringify(richTextBulletsDocData)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`),
)
const richTextDocWithRelationship = { ...richTextDocWithRelId }
const blocksDocWithRichText = { const blocksDocWithRichText = {
...(blocksDoc as any), ...(blocksDoc as any),
} }
const richTextDocWithRelationship = { ...richTextDocWithRelId }
blocksDocWithRichText.blocks[0].richText = richTextDocWithRelationship.richText blocksDocWithRichText.blocks[0].richText = richTextDocWithRelationship.richText
blocksDocWithRichText.localizedBlocks[0].richText = richTextDocWithRelationship.richText blocksDocWithRichText.localizedBlocks[0].richText = richTextDocWithRelationship.richText
await _payload.create({
collection: richTextFieldsSlug,
data: richTextBulletsDocWithRelId,
depth: 0,
overrideAccess: true,
})
await _payload.create({ await _payload.create({
collection: emailFieldsSlug, collection: emailFieldsSlug,
data: emailDoc, data: emailDoc,
@@ -230,32 +197,6 @@ export const seed = async (_payload: Payload) => {
overrideAccess: true, overrideAccess: true,
}) })
const createdRichTextDoc = await _payload.create({
collection: richTextFieldsSlug,
data: richTextDocWithRelationship,
depth: 0,
overrideAccess: true,
})
const formattedRichTextDocID =
_payload.db.defaultIDType === 'number' ? createdRichTextDoc.id : `"${createdRichTextDoc.id}"`
const lexicalDocWithRelId = JSON.parse(
JSON.stringify(lexicalDocData)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`)
.replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`),
)
const lexicalMigrateDocWithRelId = JSON.parse(
JSON.stringify(lexicalMigrateDocData)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`)
.replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`),
)
await _payload.create({ await _payload.create({
collection: usersSlug, collection: usersSlug,
depth: 0, depth: 0,
@@ -392,96 +333,6 @@ export const seed = async (_payload: Payload) => {
console.error(e) console.error(e)
} }
await _payload.create({
collection: lexicalFieldsSlug,
data: lexicalDocWithRelId,
depth: 0,
overrideAccess: true,
})
const lexicalLocalizedDoc1 = await _payload.create({
collection: lexicalLocalizedFieldsSlug,
data: {
title: 'Localized Lexical en',
lexicalBlocksLocalized: textToLexicalJSON({ text: 'English text' }),
lexicalBlocksSubLocalized: generateLexicalLocalizedRichText(
'Shared text',
'English text in block',
) as any,
},
locale: 'en',
depth: 0,
overrideAccess: true,
})
await _payload.create({
collection: lexicalRelationshipFieldsSlug,
data: {
richText: textToLexicalJSON({ text: 'English text' }),
},
depth: 0,
overrideAccess: true,
})
await _payload.update({
collection: lexicalLocalizedFieldsSlug,
id: lexicalLocalizedDoc1.id,
data: {
title: 'Localized Lexical es',
lexicalBlocksLocalized: textToLexicalJSON({ text: 'Spanish text' }),
lexicalBlocksSubLocalized: generateLexicalLocalizedRichText(
'Shared text',
'Spanish text in block',
(lexicalLocalizedDoc1.lexicalBlocksSubLocalized.root.children[1].fields as any).id,
) as any,
},
locale: 'es',
depth: 0,
overrideAccess: true,
})
const lexicalLocalizedDoc2 = await _payload.create({
collection: lexicalLocalizedFieldsSlug,
data: {
title: 'Localized Lexical en 2',
lexicalBlocksLocalized: textToLexicalJSON({
text: 'English text 2',
lexicalLocalizedRelID: lexicalLocalizedDoc1.id,
}),
lexicalBlocksSubLocalized: textToLexicalJSON({
text: 'English text 2',
lexicalLocalizedRelID: lexicalLocalizedDoc1.id,
}),
},
locale: 'en',
depth: 0,
overrideAccess: true,
})
await _payload.update({
collection: lexicalLocalizedFieldsSlug,
id: lexicalLocalizedDoc2.id,
data: {
title: 'Localized Lexical es 2',
lexicalBlocksLocalized: textToLexicalJSON({
text: 'Spanish text 2',
lexicalLocalizedRelID: lexicalLocalizedDoc1.id,
}),
},
locale: 'es',
depth: 0,
overrideAccess: true,
})
await _payload.create({
collection: lexicalMigrateFieldsSlug,
data: lexicalMigrateDocWithRelId,
depth: 0,
overrideAccess: true,
})
await _payload.create({ await _payload.create({
collection: numberFieldsSlug, collection: numberFieldsSlug,
data: { number: 2 }, data: { number: 2 },
@@ -511,152 +362,6 @@ export const seed = async (_payload: Payload) => {
depth: 0, depth: 0,
}) })
const getInlineBlock = () => ({
type: 'inlineBlock',
fields: {
id: Math.random().toString(36).substring(2, 15),
text: 'text',
blockType: 'inlineBlockInLexical',
},
version: 1,
})
await _payload.create({
collection: 'LexicalInBlock',
depth: 0,
data: {
content: {
root: {
children: [
{
format: '',
type: 'block',
version: 2,
fields: {
id: '6773773284be8978db7a498d',
lexicalInBlock: textToLexicalJSON({ text: 'text' }),
blockName: '',
blockType: 'blockInLexical',
},
},
],
direction: null,
format: '',
indent: 0,
type: 'root',
version: 1,
},
},
blocks: [
{
blockType: 'lexicalInBlock2',
blockName: '1',
lexical: textToLexicalJSON({ text: '1' }),
},
{
blockType: 'lexicalInBlock2',
blockName: '2',
lexical: textToLexicalJSON({ text: '2' }),
},
{
blockType: 'lexicalInBlock2',
lexical: {
root: {
children: [
{
children: [...Array.from({ length: 20 }, () => getInlineBlock())],
direction: null,
format: '',
indent: 0,
type: 'paragraph',
version: 1,
textFormat: 0,
textStyle: '',
},
],
direction: null,
format: '',
indent: 0,
type: 'root',
version: 1,
},
},
id: '67e1af0b78de3228e23ef1d5',
blockName: '1',
},
],
},
})
await _payload.create({
collection: 'lexical-access-control',
data: {
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,
})
await Promise.all([ await Promise.all([
_payload.create({ _payload.create({
collection: customIDSlug, collection: customIDSlug,

View File

@@ -13,18 +13,11 @@ export const emailFieldsSlug = 'email-fields'
export const groupFieldsSlug = 'group-fields' export const groupFieldsSlug = 'group-fields'
export const indexedFieldsSlug = 'indexed-fields' export const indexedFieldsSlug = 'indexed-fields'
export const jsonFieldsSlug = 'json-fields' export const jsonFieldsSlug = 'json-fields'
export const lexicalFieldsSlug = 'lexical-fields'
export const lexicalLocalizedFieldsSlug = 'lexical-localized-fields'
export const lexicalMigrateFieldsSlug = 'lexical-migrate-fields'
export const lexicalRelationshipFieldsSlug = 'lexical-relationship-fields'
export const lexicalAccessControlSlug = 'lexical-access-control'
export const numberFieldsSlug = 'number-fields' export const numberFieldsSlug = 'number-fields'
export const pointFieldsSlug = 'point-fields' export const pointFieldsSlug = 'point-fields'
export const radioFieldsSlug = 'radio-fields' export const radioFieldsSlug = 'radio-fields'
export const relationshipFieldsSlug = 'relationship-fields' export const relationshipFieldsSlug = 'relationship-fields'
export const richTextFieldsSlug = 'rich-text-fields'
export const rowFieldsSlug = 'row-fields' export const rowFieldsSlug = 'row-fields'
export const selectFieldsSlug = 'select-fields' export const selectFieldsSlug = 'select-fields'
export const selectVersionsFieldsSlug = 'select-versions-fields' export const selectVersionsFieldsSlug = 'select-versions-fields'
@@ -52,15 +45,10 @@ export const collectionSlugs = [
groupFieldsSlug, groupFieldsSlug,
indexedFieldsSlug, indexedFieldsSlug,
jsonFieldsSlug, jsonFieldsSlug,
lexicalFieldsSlug,
lexicalMigrateFieldsSlug,
lexicalRelationshipFieldsSlug,
lexicalAccessControlSlug,
numberFieldsSlug, numberFieldsSlug,
pointFieldsSlug, pointFieldsSlug,
radioFieldsSlug, radioFieldsSlug,
relationshipFieldsSlug, relationshipFieldsSlug,
richTextFieldsSlug,
rowFieldsSlug, rowFieldsSlug,
selectFieldsSlug, selectFieldsSlug,
tabsFieldsSlug, tabsFieldsSlug,

View File

@@ -0,0 +1,63 @@
import { fileURLToPath } from 'node:url'
import path from 'path'
import { type Config } from 'payload'
import ArrayFields from './collections/Array/index.js'
import {
getLexicalFieldsCollection,
lexicalBlocks,
lexicalInlineBlocks,
} from './collections/Lexical/index.js'
import { LexicalAccessControl } from './collections/LexicalAccessControl/index.js'
import { LexicalInBlock } from './collections/LexicalInBlock/index.js'
import { LexicalLocalizedFields } from './collections/LexicalLocalized/index.js'
import { LexicalMigrateFields } from './collections/LexicalMigrate/index.js'
import { LexicalObjectReferenceBugCollection } from './collections/LexicalObjectReferenceBug/index.js'
import { LexicalRelationshipsFields } from './collections/LexicalRelationships/index.js'
import RichTextFields from './collections/RichText/index.js'
import TextFields from './collections/Text/index.js'
import Uploads from './collections/Upload/index.js'
import TabsWithRichText from './globals/TabsWithRichText.js'
import { clearAndSeedEverything } from './seed.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
export const baseConfig: Partial<Config> = {
// ...extend config here
collections: [
getLexicalFieldsCollection({
blocks: lexicalBlocks,
inlineBlocks: lexicalInlineBlocks,
}),
LexicalMigrateFields,
LexicalLocalizedFields,
LexicalObjectReferenceBugCollection,
LexicalInBlock,
LexicalAccessControl,
LexicalRelationshipsFields,
RichTextFields,
TextFields,
Uploads,
ArrayFields,
],
globals: [TabsWithRichText],
admin: {
importMap: {
baseDir: path.resolve(dirname),
},
},
onInit: async (payload) => {
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
await clearAndSeedEverything(payload)
}
},
localization: {
defaultLocale: 'en',
fallback: true,
locales: ['en', 'es'],
},
typescript: {
outputFile: path.resolve(dirname, 'payload-types.ts'),
},
}

View File

@@ -0,0 +1,29 @@
'use client'
import { useForm } from '@payloadcms/ui'
const AddRowButton = () => {
const { addFieldRow } = useForm()
const handleClick = () => {
addFieldRow({
path: 'externallyUpdatedArray',
schemaPath: 'externallyUpdatedArray',
subFieldState: {
text: {
initialValue: 'Hello, world!',
valid: true,
value: 'Hello, world!',
},
},
})
}
return (
<button id="updateArrayExternally" onClick={handleClick} type="button">
Add Row
</button>
)
}
export default AddRowButton

View File

@@ -0,0 +1,12 @@
'use client'
import type { ArrayFieldClientComponent } from 'payload'
import { ArrayField } from '@payloadcms/ui'
export const CustomArrayField: ArrayFieldClientComponent = (props) => {
return (
<div id="custom-array-field">
<ArrayField {...props} />
</div>
)
}

View File

@@ -0,0 +1,11 @@
import type { TextFieldServerComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
export const CustomTextField: TextFieldServerComponent = ({ clientField, path }) => {
return (
<div id="custom-text-field">
<TextField field={clientField} path={path} />
</div>
)
}

View File

@@ -0,0 +1,15 @@
'use client'
import type { PayloadClientReactComponent, RowLabelComponent } from 'payload'
import { useRowLabel } from '@payloadcms/ui'
import React from 'react'
export const ArrayRowLabel: PayloadClientReactComponent<RowLabelComponent> = () => {
const { data } = useRowLabel<{ title: string }>()
return (
<div id="custom-array-row-label" style={{ color: 'coral', textTransform: 'uppercase' }}>
{data.title || 'Untitled'}
</div>
)
}

View File

@@ -0,0 +1,268 @@
import type { CollectionConfig } from 'payload'
import { arrayFieldsSlug } from '../../slugs.js'
export const arrayDefaultValue = [{ text: 'row one' }, { text: 'row two' }]
const ArrayFields: CollectionConfig = {
admin: {
enableRichTextLink: false,
},
fields: [
{
name: 'title',
type: 'text',
required: false,
},
{
name: 'items',
defaultValue: arrayDefaultValue,
fields: [
{
name: 'text',
type: 'text',
required: true,
},
{
name: 'anotherText',
type: 'text',
},
{
name: 'uiField',
type: 'ui',
admin: {
components: {
Field: {
path: './collections/Array/LabelComponent.js#ArrayRowLabel',
serverProps: {
// While this doesn't do anything, this will reproduce a bug where having server-only props in here will throw a "Functions cannot be passed directly to Client Components" error
someFn: () => 'Hello',
},
},
},
},
},
{
name: 'localizedText',
type: 'text',
localized: true,
},
{
name: 'subArray',
fields: [
{
name: 'text',
type: 'text',
},
{
name: 'textTwo',
label: 'Second text field',
type: 'text',
required: true,
defaultValue: 'default',
},
{
type: 'row',
fields: [
{
name: 'textInRow',
type: 'text',
required: true,
defaultValue: 'default',
},
],
},
],
type: 'array',
},
],
required: true,
type: 'array',
},
{
name: 'collapsedArray',
admin: {
initCollapsed: true,
},
fields: [
{
name: 'text',
required: true,
type: 'text',
},
],
type: 'array',
},
{
name: 'localized',
defaultValue: arrayDefaultValue,
fields: [
{
name: 'text',
required: true,
type: 'text',
},
],
localized: true,
required: true,
type: 'array',
},
{
name: 'readOnly',
admin: {
readOnly: true,
},
defaultValue: [
{
text: 'defaultValue',
},
{
text: 'defaultValue2',
},
],
fields: [
{
name: 'text',
type: 'text',
},
],
type: 'array',
},
{
name: 'potentiallyEmptyArray',
fields: [
{
name: 'text',
type: 'text',
},
{
name: 'groupInRow',
fields: [
{
name: 'textInGroupInRow',
type: 'text',
},
],
type: 'group',
},
],
type: 'array',
},
{
name: 'rowLabelAsComponent',
admin: {
components: {
RowLabel: '/collections/Array/LabelComponent.js#ArrayRowLabel',
},
description: 'Row labels rendered as react components.',
},
fields: [
{
name: 'title',
type: 'text',
},
],
type: 'array',
},
{
name: 'arrayWithMinRows',
fields: [
{
name: 'text',
type: 'text',
},
],
minRows: 2,
type: 'array',
},
{
name: 'disableSort',
defaultValue: arrayDefaultValue,
admin: {
isSortable: false,
},
fields: [
{
name: 'text',
required: true,
type: 'text',
},
],
type: 'array',
},
{
name: 'nestedArrayLocalized',
type: 'array',
fields: [
{
type: 'array',
name: 'array',
fields: [
{
name: 'text',
type: 'text',
localized: true,
},
],
},
],
},
{
name: 'externallyUpdatedArray',
type: 'array',
fields: [
{
name: 'customTextField',
type: 'ui',
admin: {
components: {
Field: '/collections/Array/CustomTextField.js#CustomTextField',
},
},
},
],
},
{
name: 'customArrayField',
type: 'array',
admin: {
components: {
Field: '/collections/Array/CustomArrayField.js#CustomArrayField',
},
},
fields: [
{
name: 'text',
type: 'text',
},
],
},
{
name: 'ui',
type: 'ui',
admin: {
components: {
Field: '/collections/Array/AddRowButton.js',
},
},
},
{
name: 'arrayWithLabels',
type: 'array',
labels: {
singular: ({ t }) => t('authentication:account'),
plural: ({ t }) => t('authentication:generate'),
},
fields: [
{
name: 'text',
type: 'text',
},
],
},
],
slug: arrayFieldsSlug,
versions: true,
}
export default ArrayFields

View File

@@ -0,0 +1,68 @@
import type { RequiredDataFromCollection } from 'payload/types'
import type { ArrayField } from '../../payload-types.js'
export const arrayDoc: RequiredDataFromCollection<ArrayField> = {
arrayWithMinRows: [
{
text: 'first row',
},
{
text: 'second row',
},
],
collapsedArray: [
{
text: 'initialize collapsed',
},
],
items: [
{
text: 'first row',
},
{
text: 'second row',
},
{
text: 'third row',
},
{
text: 'fourth row',
},
{
text: 'fifth row',
},
{
text: 'sixth row',
},
],
title: 'array doc 1',
}
export const anotherArrayDoc: RequiredDataFromCollection<ArrayField> = {
arrayWithMinRows: [
{
text: 'first row',
},
{
text: 'second row',
},
],
collapsedArray: [
{
text: 'initialize collapsed',
},
],
items: [
{
text: 'first row',
},
{
text: 'second row',
},
{
text: 'third row',
},
],
title: 'array doc 2',
}

View File

@@ -2,7 +2,7 @@ import type { ArrayField, Block, TextFieldSingleValidation } from 'payload'
import { BlocksFeature, FixedToolbarFeature, lexicalEditor } from '@payloadcms/richtext-lexical' import { BlocksFeature, FixedToolbarFeature, lexicalEditor } from '@payloadcms/richtext-lexical'
import { textFieldsSlug } from '../Text/shared.js' import { textFieldsSlug } from '../../slugs.js'
async function asyncFunction(param: string) { async function asyncFunction(param: string) {
return new Promise((resolve) => { return new Promise((resolve) => {

View File

@@ -514,21 +514,8 @@ describe('lexicalMain', () => {
await wait(500) await wait(500)
await expect(page.locator('.shimmer-effect')).toHaveCount(0) await expect(page.locator('.shimmer-effect')).toHaveCount(0)
await uploadListDrawer.locator('.rs__control .value-container').first().click() await page.getByRole('dialog').getByLabel('Add new Upload').first().click()
await wait(500) const createUploadDrawer = page.locator('dialog[id^=doc-drawer_uploads_]').first() // IDs starting with list-drawer_1_ (there's some other symbol after the underscore)
await expect(uploadListDrawer.locator('.rs__option').nth(1)).toBeVisible()
await expect(uploadListDrawer.locator('.rs__option').nth(1)).toContainText('Upload 2')
await uploadListDrawer.locator('.rs__option').nth(1).click()
// wait till the text appears in uploadListDrawer: "No Uploads 2 found. Either no Uploads 2 exist yet or none match the filters you've specified above."
await expect(
uploadListDrawer.getByText(
"No Uploads 2 found. Either no Uploads 2 exist yet or none match the filters you've specified above.",
),
).toBeVisible()
await uploadListDrawer.getByText('Create New').first().click()
const createUploadDrawer = page.locator('dialog[id^=doc-drawer_uploads2_]').first() // IDs starting with list-drawer_1_ (there's some other symbol after the underscore)
await expect(createUploadDrawer).toBeVisible() await expect(createUploadDrawer).toBeVisible()
await wait(500) await wait(500)
@@ -555,10 +542,10 @@ describe('lexicalMain', () => {
await expect(secondUploadNode).toBeVisible() await expect(secondUploadNode).toBeVisible()
await expect(secondUploadNode.locator('.lexical-upload__bottomRow')).toContainText( await expect(secondUploadNode.locator('.lexical-upload__bottomRow')).toContainText(
'payload.jpg', 'payload-1.jpg',
) )
await expect(secondUploadNode.locator('.lexical-upload__collectionLabel')).toContainText( await expect(secondUploadNode.locator('.lexical-upload__collectionLabel')).toContainText(
'Upload 2', 'Upload',
) )
}) })

View File

@@ -182,27 +182,6 @@ describe('Rich Text', () => {
await expect(modalTrigger).toBeDisabled() await expect(modalTrigger).toBeDisabled()
}) })
test('should only list RTE enabled upload collections in drawer', async () => {
await navigateToRichTextFields()
await wait(1000)
// Open link drawer
await page
.locator('.rich-text__toolbar button:not([disabled]) .upload-rich-text-button')
.first()
.click()
const drawer = page.locator('[id^=list-drawer_1_]')
await expect(drawer).toBeVisible()
// open the list select menu
await page.locator('.list-drawer__select-collection-wrap .rs__control').click()
const menu = page.locator('.list-drawer__select-collection-wrap .rs__menu')
// `uploads-3` has enableRichTextRelationship set to false
await expect(menu).not.toContainText('Uploads3')
})
// TODO: this test can't find the selector for the search filter, but functionality works. // TODO: this test can't find the selector for the search filter, but functionality works.
// Need to debug // Need to debug
test.skip('should search correct useAsTitle field after toggling collection in list drawer', async () => { test.skip('should search correct useAsTitle field after toggling collection in list drawer', async () => {

View File

@@ -0,0 +1,5 @@
import React from 'react'
export default function CustomDescription() {
return <div>Custom Description</div>
}

View File

@@ -0,0 +1,200 @@
import type { CollectionConfig } from 'payload'
import { defaultText, textFieldsSlug } from './shared.js'
const TextFields: CollectionConfig = {
slug: textFieldsSlug,
admin: {
useAsTitle: 'text',
},
defaultSort: 'id',
fields: [
{
name: 'text',
type: 'text',
required: true,
hooks: {
beforeDuplicate: [({ value }) => `${value} - duplicate`],
},
},
{
name: 'hiddenTextField',
type: 'text',
hidden: true,
},
{
name: 'adminHiddenTextField',
type: 'text',
admin: {
hidden: true,
description: 'This field should be hidden',
},
},
{
name: 'disabledTextField',
type: 'text',
admin: {
disabled: true,
description: 'This field should be disabled',
},
},
{
type: 'row',
admin: {
components: {
Field: './components/CustomField.tsx#CustomField',
},
},
fields: [],
},
{
name: 'localizedText',
type: 'text',
localized: true,
},
{
name: 'i18nText',
type: 'text',
admin: {
description: {
en: 'en description',
es: 'es description',
},
placeholder: {
en: 'en placeholder',
es: 'es placeholder',
},
},
label: {
en: 'Text en',
es: 'Text es',
},
},
{
name: 'defaultString',
type: 'text',
defaultValue: defaultText,
},
{
name: 'defaultEmptyString',
type: 'text',
defaultValue: '',
},
{
name: 'defaultFunction',
type: 'text',
defaultValue: () => defaultText,
},
{
name: 'defaultAsync',
type: 'text',
defaultValue: async (): Promise<string> => {
return new Promise((resolve) =>
setTimeout(() => {
resolve(defaultText)
}, 1),
)
},
},
{
name: 'overrideLength',
type: 'text',
label: 'Override the 40k text length default',
maxLength: 50000,
},
{
name: 'fieldWithDefaultValue',
type: 'text',
defaultValue: async () => {
const defaultValue = new Promise((resolve) => setTimeout(() => resolve('some-value'), 1000))
return defaultValue
},
},
{
name: 'dependentOnFieldWithDefaultValue',
type: 'text',
hooks: {
beforeChange: [
({ data }) => {
return data?.fieldWithDefaultValue || ''
},
],
},
},
{
name: 'hasMany',
type: 'text',
hasMany: true,
},
{
name: 'readOnlyHasMany',
type: 'text',
hasMany: true,
admin: {
readOnly: true,
},
defaultValue: ['default'],
},
{
name: 'validatesHasMany',
type: 'text',
hasMany: true,
minLength: 3,
},
{
name: 'localizedHasMany',
type: 'text',
hasMany: true,
localized: true,
},
{
name: 'withMinRows',
type: 'text',
hasMany: true,
minRows: 2,
},
{
name: 'withMaxRows',
type: 'text',
hasMany: true,
maxRows: 4,
},
{
name: 'defaultValueFromReq',
type: 'text',
defaultValue: async ({ req }) => {
return Promise.resolve(req.context.defaultValue)
},
},
{
name: 'array',
type: 'array',
fields: [
{
name: 'texts',
type: 'text',
hasMany: true,
},
],
},
{
name: 'blocks',
type: 'blocks',
blocks: [
{
slug: 'blockWithText',
fields: [
{
name: 'texts',
type: 'text',
hasMany: true,
},
],
},
],
},
],
}
export default TextFields

View File

@@ -0,0 +1,15 @@
import type { RequiredDataFromCollection } from 'payload/types'
import type { TextField } from '../../payload-types.js'
export const defaultText = 'default-text'
export const textFieldsSlug = 'text-fields'
export const textDoc: RequiredDataFromCollection<TextField> = {
text: 'Seeded text document',
localizedText: 'Localized text',
}
export const anotherTextDoc: RequiredDataFromCollection<TextField> = {
text: 'Another text document',
}

View File

@@ -0,0 +1 @@
uploads

View File

@@ -0,0 +1,37 @@
import type { CollectionConfig } from 'payload'
import path from 'path'
import { fileURLToPath } from 'url'
import { uploadsSlug } from '../../slugs.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
const Uploads: CollectionConfig = {
slug: uploadsSlug,
fields: [
{
name: 'text',
type: 'text',
},
{
name: 'media',
type: 'upload',
filterOptions: {
mimeType: {
equals: 'image/png',
},
},
relationTo: uploadsSlug,
},
// {
// name: 'richText',
// type: 'richText',
// },
],
upload: {
staticDir: path.resolve(dirname, './uploads'),
},
}
export default Uploads

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -0,0 +1,5 @@
import type { Upload } from '../../payload-types.js'
export const uploadsDoc: Partial<Upload> = {
text: 'An upload here',
}

View File

@@ -0,0 +1,9 @@
'use client'
import type { TextFieldClientComponent } from 'payload'
import React from 'react'
export const CustomField: TextFieldClientComponent = ({ schemaPath }) => {
return <div id="custom-field-schema-path">{schemaPath}</div>
}

View File

@@ -0,0 +1,36 @@
/* eslint-disable no-restricted-exports */
import type { BlockSlug } from 'payload'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { autoDedupeBlocksPlugin } from '../helpers/autoDedupeBlocksPlugin/index.js'
import { baseConfig } from './baseConfig.js'
import {
getLexicalFieldsCollection,
lexicalBlocks,
lexicalInlineBlocks,
} from './collections/Lexical/index.js'
import { lexicalFieldsSlug } from './slugs.js'
export default buildConfigWithDefaults({
...baseConfig,
blocks: [
...(baseConfig.blocks ?? []),
...lexicalBlocks.filter((block) => typeof block !== 'string'),
...lexicalInlineBlocks.filter((block) => typeof block !== 'string'),
],
collections: baseConfig.collections?.map((collection) => {
if (collection.slug === lexicalFieldsSlug) {
return getLexicalFieldsCollection({
blocks: lexicalBlocks.map((block) =>
typeof block === 'string' ? block : block.slug,
) as BlockSlug[],
inlineBlocks: lexicalInlineBlocks.map((block) =>
typeof block === 'string' ? block : block.slug,
) as BlockSlug[],
})
}
return collection
}),
plugins: [autoDedupeBlocksPlugin({ silent: false })],
})

5
test/lexical/config.ts Normal file
View File

@@ -0,0 +1,5 @@
/* eslint-disable no-restricted-exports */
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { baseConfig } from './baseConfig.js'
export default buildConfigWithDefaults(baseConfig)

View File

@@ -1,3 +1,4 @@
/* eslint-disable jest/no-conditional-in-test */
import type { import type {
SerializedBlockNode, SerializedBlockNode,
SerializedLinkNode, SerializedLinkNode,
@@ -679,4 +680,71 @@ describe('Lexical', () => {
).toEqual(210) // Initial: 20. BeforeChange: +1 (21). AfterRead: *10 (210) ).toEqual(210) // Initial: 20. BeforeChange: +1 (21). AfterRead: *10 (210)
}) })
}) })
describe('richText', () => {
it('should allow querying on rich text content', async () => {
const emptyRichTextQuery = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.text': {
like: 'doesnt exist',
},
},
})
expect(emptyRichTextQuery.docs).toHaveLength(0)
const workingRichTextQuery = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.text': {
like: 'hello',
},
},
})
expect(workingRichTextQuery.docs).toHaveLength(1)
})
it('should show center alignment', async () => {
const query = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.text': {
like: 'hello',
},
},
})
expect(query.docs[0]?.richText[0]?.textAlign).toEqual('center')
})
it('should populate link relationship', async () => {
const query = await payload.find({
collection: 'rich-text-fields',
where: {
'richText.children.linkType': {
equals: 'internal',
},
},
})
const nodes = query.docs[0]?.richText
expect(nodes).toBeDefined()
const child = nodes?.flatMap((n) => n.children).find((c) => c?.doc)
expect(child).toMatchObject({
type: 'link',
linkType: 'internal',
})
expect(child.doc.relationTo).toEqual('array-fields')
if (payload.db.defaultIDType === 'number') {
expect(typeof child.doc.value.id).toBe('number')
} else {
expect(typeof child.doc.value.id).toBe('string')
}
expect(child.doc.value.items).toHaveLength(6)
})
})
}) })

File diff suppressed because it is too large Load Diff

452
test/lexical/seed.ts Normal file
View File

@@ -0,0 +1,452 @@
import type { Payload } from 'payload'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { lexicalDocData } from './collections/Lexical/data.js'
import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js'
import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js'
import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js'
import { richTextBulletsDocData, richTextDocData } from './collections/RichText/data.js'
import {
arrayFieldsSlug,
collectionSlugs,
lexicalFieldsSlug,
lexicalLocalizedFieldsSlug,
lexicalMigrateFieldsSlug,
lexicalRelationshipFieldsSlug,
richTextFieldsSlug,
textFieldsSlug,
uploadsSlug,
usersSlug,
} from './slugs.js'
// import type { Payload } from 'payload'
import { getFileByPath } from 'payload'
import { devUser } from '../credentials.js'
import { seedDB } from '../helpers/seed.js'
import { arrayDoc } from './collections/Array/shared.js'
import { anotherTextDoc, textDoc } from './collections/Text/shared.js'
import { uploadsDoc } from './collections/Upload/shared.js'
// import { blocksDoc } from './collections/Blocks/shared.js'
// import { codeDoc } from './collections/Code/shared.js'
// import { collapsibleDoc } from './collections/Collapsible/shared.js'
// import { conditionalLogicDoc } from './collections/ConditionalLogic/shared.js'
// import { customRowID, customTabID, nonStandardID } from './collections/CustomID/shared.js'
// import { dateDoc } from './collections/Date/shared.js'
// import { anotherEmailDoc, emailDoc } from './collections/Email/shared.js'
// import { groupDoc } from './collections/Group/shared.js'
// import { jsonDoc } from './collections/JSON/shared.js'
// import { lexicalDocData } from './collections/Lexical/data.js'
// import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js'
// import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js'
// import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js'
// import { numberDoc } from './collections/Number/shared.js'
// import { pointDoc } from './collections/Point/shared.js'
// import { radiosDoc } from './collections/Radio/shared.js'
// import { richTextBulletsDocData, richTextDocData } from './collections/RichText/data.js'
// import { selectsDoc } from './collections/Select/shared.js'
// import { tabsDoc } from './collections/Tabs/shared.js'
// import { anotherTextDoc, textDoc } from './collections/Text/shared.js'
// import { uploadsDoc } from './collections/Upload/shared.js'
// import {
// arrayFieldsSlug,
// blockFieldsSlug,
// checkboxFieldsSlug,
// codeFieldsSlug,
// collapsibleFieldsSlug,
// collectionSlugs,
// conditionalLogicSlug,
// customIDSlug,
// customRowIDSlug,
// customTabIDSlug,
// dateFieldsSlug,
// emailFieldsSlug,
// groupFieldsSlug,
// jsonFieldsSlug,
// lexicalFieldsSlug,
// lexicalLocalizedFieldsSlug,
// lexicalMigrateFieldsSlug,
// lexicalRelationshipFieldsSlug,
// numberFieldsSlug,
// pointFieldsSlug,
// radioFieldsSlug,
// relationshipFieldsSlug,
// richTextFieldsSlug,
// selectFieldsSlug,
// tabsFieldsSlug,
// textFieldsSlug,
// uiSlug,
// uploads2Slug,
// uploadsMulti,
// uploadsMultiPoly,
// uploadsPoly,
// uploadsSlug,
// usersSlug,
// } from './slugs.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
export const seed = async (_payload: Payload) => {
const jpgPath = path.resolve(dirname, './collections/Upload/payload.jpg')
const pngPath = path.resolve(dirname, './uploads/payload.png')
// Get both files in parallel
const [jpgFile, pngFile] = await Promise.all([getFileByPath(jpgPath), getFileByPath(pngPath)])
const createdArrayDoc = await _payload.create({
collection: arrayFieldsSlug,
data: arrayDoc,
depth: 0,
overrideAccess: true,
})
const createdTextDoc = await _payload.create({
collection: textFieldsSlug,
data: textDoc,
depth: 0,
overrideAccess: true,
})
await _payload.create({
collection: textFieldsSlug,
data: anotherTextDoc,
depth: 0,
overrideAccess: true,
})
const createdPNGDoc = await _payload.create({
collection: uploadsSlug,
data: {},
file: pngFile,
depth: 0,
overrideAccess: true,
})
const createdJPGDoc = await _payload.create({
collection: uploadsSlug,
data: {
...uploadsDoc,
media: createdPNGDoc.id,
},
file: jpgFile,
depth: 0,
overrideAccess: true,
})
const formattedID =
_payload.db.defaultIDType === 'number' ? createdArrayDoc.id : `"${createdArrayDoc.id}"`
const formattedJPGID =
_payload.db.defaultIDType === 'number' ? createdJPGDoc.id : `"${createdJPGDoc.id}"`
const formattedTextID =
_payload.db.defaultIDType === 'number' ? createdTextDoc.id : `"${createdTextDoc.id}"`
const richTextDocWithRelId = JSON.parse(
JSON.stringify(richTextDocData)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`),
)
const richTextBulletsDocWithRelId = JSON.parse(
JSON.stringify(richTextBulletsDocData)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`),
)
const richTextDocWithRelationship = { ...richTextDocWithRelId }
await _payload.create({
collection: richTextFieldsSlug,
data: richTextBulletsDocWithRelId,
depth: 0,
overrideAccess: true,
})
const createdRichTextDoc = await _payload.create({
collection: richTextFieldsSlug,
data: richTextDocWithRelationship,
depth: 0,
overrideAccess: true,
})
const formattedRichTextDocID =
_payload.db.defaultIDType === 'number' ? createdRichTextDoc.id : `"${createdRichTextDoc.id}"`
const lexicalDocWithRelId = JSON.parse(
JSON.stringify(lexicalDocData)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`)
.replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`),
)
const lexicalMigrateDocWithRelId = JSON.parse(
JSON.stringify(lexicalMigrateDocData)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`)
.replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`),
)
await _payload.create({
collection: usersSlug,
depth: 0,
data: {
email: devUser.email,
password: devUser.password,
},
overrideAccess: true,
})
await _payload.create({
collection: lexicalFieldsSlug,
data: lexicalDocWithRelId,
depth: 0,
overrideAccess: true,
})
const lexicalLocalizedDoc1 = await _payload.create({
collection: lexicalLocalizedFieldsSlug,
data: {
title: 'Localized Lexical en',
lexicalBlocksLocalized: textToLexicalJSON({ text: 'English text' }),
lexicalBlocksSubLocalized: generateLexicalLocalizedRichText(
'Shared text',
'English text in block',
) as any,
},
locale: 'en',
depth: 0,
overrideAccess: true,
})
await _payload.create({
collection: lexicalRelationshipFieldsSlug,
data: {
richText: textToLexicalJSON({ text: 'English text' }),
},
depth: 0,
overrideAccess: true,
})
await _payload.update({
collection: lexicalLocalizedFieldsSlug,
id: lexicalLocalizedDoc1.id,
data: {
title: 'Localized Lexical es',
lexicalBlocksLocalized: textToLexicalJSON({ text: 'Spanish text' }),
lexicalBlocksSubLocalized: generateLexicalLocalizedRichText(
'Shared text',
'Spanish text in block',
(lexicalLocalizedDoc1.lexicalBlocksSubLocalized.root.children[1].fields as any).id,
) as any,
},
locale: 'es',
depth: 0,
overrideAccess: true,
})
const lexicalLocalizedDoc2 = await _payload.create({
collection: lexicalLocalizedFieldsSlug,
data: {
title: 'Localized Lexical en 2',
lexicalBlocksLocalized: textToLexicalJSON({
text: 'English text 2',
lexicalLocalizedRelID: lexicalLocalizedDoc1.id,
}),
lexicalBlocksSubLocalized: textToLexicalJSON({
text: 'English text 2',
lexicalLocalizedRelID: lexicalLocalizedDoc1.id,
}),
},
locale: 'en',
depth: 0,
overrideAccess: true,
})
await _payload.update({
collection: lexicalLocalizedFieldsSlug,
id: lexicalLocalizedDoc2.id,
data: {
title: 'Localized Lexical es 2',
lexicalBlocksLocalized: textToLexicalJSON({
text: 'Spanish text 2',
lexicalLocalizedRelID: lexicalLocalizedDoc1.id,
}),
},
locale: 'es',
depth: 0,
overrideAccess: true,
})
await _payload.create({
collection: lexicalMigrateFieldsSlug,
data: lexicalMigrateDocWithRelId,
depth: 0,
overrideAccess: true,
})
const getInlineBlock = () => ({
type: 'inlineBlock',
fields: {
id: Math.random().toString(36).substring(2, 15),
text: 'text',
blockType: 'inlineBlockInLexical',
},
version: 1,
})
await _payload.create({
collection: 'LexicalInBlock',
depth: 0,
data: {
content: {
root: {
children: [
{
format: '',
type: 'block',
version: 2,
fields: {
id: '6773773284be8978db7a498d',
lexicalInBlock: textToLexicalJSON({ text: 'text' }),
blockName: '',
blockType: 'blockInLexical',
},
},
],
direction: null,
format: '',
indent: 0,
type: 'root',
version: 1,
},
},
blocks: [
{
blockType: 'lexicalInBlock2',
blockName: '1',
lexical: textToLexicalJSON({ text: '1' }),
},
{
blockType: 'lexicalInBlock2',
blockName: '2',
lexical: textToLexicalJSON({ text: '2' }),
},
{
blockType: 'lexicalInBlock2',
lexical: {
root: {
children: [
{
children: [...Array.from({ length: 20 }, () => getInlineBlock())],
direction: null,
format: '',
indent: 0,
type: 'paragraph',
version: 1,
textFormat: 0,
textStyle: '',
},
],
direction: null,
format: '',
indent: 0,
type: 'root',
version: 1,
},
},
id: '67e1af0b78de3228e23ef1d5',
blockName: '1',
},
],
},
})
await _payload.create({
collection: 'lexical-access-control',
data: {
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,
})
}
export async function clearAndSeedEverything(_payload: Payload) {
return await seedDB({
_payload,
collectionSlugs,
seedFunction: seed,
snapshotKey: 'fieldsTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
}

24
test/lexical/slugs.ts Normal file
View File

@@ -0,0 +1,24 @@
export const usersSlug = 'users'
export const lexicalFieldsSlug = 'lexical-fields'
export const lexicalLocalizedFieldsSlug = 'lexical-localized-fields'
export const lexicalMigrateFieldsSlug = 'lexical-migrate-fields'
export const lexicalRelationshipFieldsSlug = 'lexical-relationship-fields'
export const lexicalAccessControlSlug = 'lexical-access-control'
export const richTextFieldsSlug = 'rich-text-fields'
// Auxiliary slugs
export const textFieldsSlug = 'text-fields'
export const uploadsSlug = 'uploads'
export const arrayFieldsSlug = 'array-fields'
export const collectionSlugs = [
lexicalFieldsSlug,
lexicalLocalizedFieldsSlug,
lexicalMigrateFieldsSlug,
lexicalRelationshipFieldsSlug,
lexicalAccessControlSlug,
richTextFieldsSlug,
textFieldsSlug,
uploadsSlug,
]

View File

@@ -0,0 +1,13 @@
{
// extend your base config to share compilerOptions, etc
//"extends": "./tsconfig.json",
"compilerOptions": {
// ensure that nobody can accidentally use this config for a build
"noEmit": true
},
"include": [
// whatever paths you intend to lint
"./**/*.ts",
"./**/*.tsx"
]
}

View File

@@ -0,0 +1,3 @@
{
"extends": "../tsconfig.json"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB