Compare commits

...

4 Commits

Author SHA1 Message Date
Elliot DeNolf
aa3833ec83 chore(release): payload/2.16.1 [skip ci] 2024-05-07 15:52:06 -04:00
Dan Ribbens
2972af2af1 chore: add index to version status field (#6256) 2024-05-07 15:47:55 -04:00
Alessio Gravili
857b9a4ac3 feat(richtext-lexical): add maxDepth property to various lexical features (#6250)
Backports #6242
2024-05-07 09:39:48 -04:00
Alessio Gravili
f829b084ba fix(richtext-lexical): export missing HorizontalRuleFeature (#6236) 2024-05-06 13:54:49 -04:00
16 changed files with 116 additions and 50 deletions

View File

@@ -1,3 +1,15 @@
## [2.16.1](https://github.com/payloadcms/payload/compare/v2.16.0...v2.16.1) (2024-05-07)
### Features
* **richtext-lexical:** add maxDepth property to various lexical features ([#6250](https://github.com/payloadcms/payload/issues/6250)) ([857b9a4](https://github.com/payloadcms/payload/commit/857b9a4ac3236c740458750f156a3a4274eda210)), closes [#6242](https://github.com/payloadcms/payload/issues/6242)
### Bug Fixes
* **richtext-lexical:** export missing HorizontalRuleFeature ([#6236](https://github.com/payloadcms/payload/issues/6236)) ([f829b08](https://github.com/payloadcms/payload/commit/f829b084ba9649ef596cce4a7bf6ae8c7ccf57e3))
## [2.16.0](https://github.com/payloadcms/payload/compare/v2.15.0...v2.16.0) (2024-05-06)

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "2.16.0",
"version": "2.16.1",
"description": "Node, React and MongoDB Headless CMS and Application Framework",
"license": "MIT",
"main": "./dist/index.js",

View File

@@ -477,6 +477,7 @@ export const richText = baseField.keys({
validate: joi.func().required(),
})
.unknown(),
maxDepth: joi.number(),
})
export const date = baseField.keys({

View File

@@ -551,6 +551,10 @@ export type RichTextField<
}
}
editor?: RichTextAdapter<Value, AdapterProps, AdapterProps>
/**
* Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached.
*/
maxDepth?: number
type: 'richText'
} & ExtraProperties

View File

@@ -143,10 +143,13 @@ export const promise = async ({
const editor: RichTextAdapter = field?.editor
// This is run here AND in the GraphQL Resolver
if (editor?.populationPromise) {
const populateDepth =
field?.maxDepth !== undefined && field?.maxDepth < depth ? field?.maxDepth : depth
const populationPromise = editor.populationPromise({
context,
currentDepth,
depth,
depth: populateDepth,
draft,
field,
findMany,

View File

@@ -476,9 +476,12 @@ function buildObjectType({
// In the graphql find.ts resolver, the depth is then hard-coded to 0.
// Effectively, this means that the populationPromise for GraphQL is only run here, and not in the find.ts resolver / normal population promise.
if (editor?.populationPromise) {
const populateDepth =
field?.maxDepth !== undefined && field?.maxDepth < depth ? field?.maxDepth : depth
await editor?.populationPromise({
context,
depth,
depth: populateDepth,
draft: args.draft,
field,
findMany: false,

View File

@@ -18,6 +18,7 @@ export const statuses = [
const baseVersionFields: Field[] = [
{
name: '_status',
type: 'select',
admin: {
components: {
Field: () => null,
@@ -25,9 +26,9 @@ const baseVersionFields: Field[] = [
disableBulkEdit: true,
},
defaultValue: 'draft',
index: true,
label: labels['version:status'],
options: statuses,
type: 'select',
},
]

View File

@@ -21,6 +21,7 @@ export const getBaseFields = (
config: Config,
enabledCollections: false | string[],
disabledCollections: false | string[],
maxDepth?: number,
): Field[] => {
let enabledRelations: string[]
@@ -48,12 +49,13 @@ export const getBaseFields = (
const baseFields = [
{
name: 'text',
type: 'text',
label: translations['fields:textToDisplay'],
required: true,
type: 'text',
},
{
name: 'fields',
type: 'group',
admin: {
style: {
borderBottom: 0,
@@ -65,6 +67,7 @@ export const getBaseFields = (
fields: [
{
name: 'linkType',
type: 'radio',
admin: {
description: translations['fields:chooseBetweenCustomTextOrDocument'],
},
@@ -77,13 +80,12 @@ export const getBaseFields = (
},
],
required: true,
type: 'radio',
},
{
name: 'url',
type: 'text',
label: translations['fields:enterURL'],
required: true,
type: 'text',
validate: (value: string) => {
if (value && !validateUrl(value)) {
return 'Invalid URL'
@@ -91,7 +93,6 @@ export const getBaseFields = (
},
},
] as Field[],
type: 'group',
},
]
@@ -113,6 +114,7 @@ export const getBaseFields = (
},
},
// when admin.hidden is a function we need to dynamically call hidden with the user to know if the collection should be shown
type: 'relationship',
filterOptions:
!enabledCollections && !disabledCollections
? ({ relationTo, user }) => {
@@ -123,16 +125,16 @@ export const getBaseFields = (
}
: null,
label: translations['fields:chooseDocumentToLink'],
maxDepth,
relationTo: enabledRelations,
required: true,
type: 'relationship',
})
}
baseFields[1].fields.push({
name: 'newTab',
label: translations['fields:openInNewTab'],
type: 'checkbox',
label: translations['fields:openInNewTab'],
})
return baseFields as Field[]

View File

@@ -52,6 +52,11 @@ export type LinkFeatureProps = ExclusiveLinkCollectionsProps & {
i18n: i18n
}) => FieldWithRichTextRequiredEditor[])
| FieldWithRichTextRequiredEditor[]
/**
* Sets a maximum population depth for the internal doc default field of link, regardless of the remaining depth when the field is reached.
* This behaves exactly like the maxDepth properties of relationship and upload fields.
*/
maxDepth?: number
}
export const LinkFeature = (props: LinkFeatureProps): FeatureProvider => {

View File

@@ -45,6 +45,7 @@ export function LinkEditor({
disabledCollections,
enabledCollections,
fields: customFieldSchema,
maxDepth,
}: { anchorElem: HTMLElement } & LinkFeatureProps): JSX.Element {
const [editor] = useLexicalComposerContext()
@@ -71,6 +72,7 @@ export function LinkEditor({
i18n,
enabledCollections,
disabledCollections,
maxDepth,
)
// Sanitize custom fields here
const validRelationships = config.collections.map((c) => c.slug) || []

View File

@@ -15,8 +15,14 @@ export function transformExtraFields(
i18n: i18n,
enabledCollections?: false | string[],
disabledCollections?: false | string[],
maxDepth?: number,
): Field[] {
const baseFields: Field[] = getBaseFields(config, enabledCollections, disabledCollections)
const baseFields: Field[] = getBaseFields(
config,
enabledCollections,
disabledCollections,
maxDepth,
)
const fields =
typeof customFieldSchema === 'function'

View File

@@ -3,9 +3,9 @@ import type { FeatureProvider } from '../types'
import { SlashMenuOption } from '../../lexical/plugins/SlashMenu/LexicalTypeaheadMenuPlugin/types'
import { INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND } from './drawer/commands'
import { RelationshipNode } from './nodes/RelationshipNode'
import { relationshipPopulationPromise } from './populationPromise'
import { relationshipPopulationPromiseHOC } from './populationPromise'
export type RelationshipFeatureProps =
export type ExclusiveRelationshipFeatureProps =
| {
/**
* The collections that should be disabled. Overrides the `enableRichTextRelationship` property in the collection config.
@@ -27,15 +27,23 @@ export type RelationshipFeatureProps =
enabledCollections?: string[]
}
export type RelationshipFeatureProps = ExclusiveRelationshipFeatureProps & {
/**
* Sets a maximum population depth for this relationship, regardless of the remaining depth when the respective field is reached.
* This behaves exactly like the maxDepth properties of relationship and upload fields.
*/
maxDepth?: number
}
export const RelationshipFeature = (props?: RelationshipFeatureProps): FeatureProvider => {
return {
feature: () => {
return {
nodes: [
{
node: RelationshipNode,
populationPromises: [relationshipPopulationPromise],
type: RelationshipNode.getType(),
node: RelationshipNode,
populationPromises: [relationshipPopulationPromiseHOC(props)],
// TODO: Add validation similar to upload
},
],
@@ -55,7 +63,7 @@ export const RelationshipFeature = (props?: RelationshipFeatureProps): FeaturePr
position: 'normal',
},
],
props: props,
props,
slashMenu: {
options: [
{

View File

@@ -1,41 +1,50 @@
import type { PopulationPromise } from '../types'
import type { RelationshipFeatureProps } from './index'
import type { SerializedRelationshipNode } from './nodes/RelationshipNode'
import { populate } from '../../../populate/populate'
export const relationshipPopulationPromise: PopulationPromise<SerializedRelationshipNode> = ({
currentDepth,
depth,
draft,
field,
node,
overrideAccess,
req,
showHiddenFields,
}) => {
const promises: Promise<void>[] = []
export const relationshipPopulationPromiseHOC = (
props: RelationshipFeatureProps,
): PopulationPromise<SerializedRelationshipNode> => {
const relationshipPopulationPromise: PopulationPromise<SerializedRelationshipNode> = ({
currentDepth,
depth,
draft,
field,
node,
overrideAccess,
req,
showHiddenFields,
}) => {
const promises: Promise<void>[] = []
if (node?.value?.id) {
const collection = req.payload.collections[node?.relationTo]
if (node?.value?.id) {
const collection = req.payload.collections[node?.relationTo]
if (collection) {
promises.push(
populate({
id: node.value.id,
collection,
currentDepth,
data: node,
depth,
draft,
field,
key: 'value',
overrideAccess,
req,
showHiddenFields,
}),
)
if (collection) {
const populateDepth =
props?.maxDepth !== undefined && props?.maxDepth < depth ? props?.maxDepth : depth
promises.push(
populate({
id: node.value.id,
collection,
currentDepth,
data: node,
depth: populateDepth,
draft,
field,
key: 'value',
overrideAccess,
req,
showHiddenFields,
}),
)
}
}
}
return promises
return promises
}
return relationshipPopulationPromise
}

View File

@@ -18,6 +18,11 @@ export type UploadFeatureProps = {
fields: FieldWithRichTextRequiredEditor[]
}
}
/**
* Sets a maximum population depth for this upload (not the fields for this upload), regardless of the remaining depth when the respective field is reached.
* This behaves exactly like the maxDepth properties of relationship and upload fields.
*/
maxDepth?: number
}
/**

View File

@@ -29,13 +29,16 @@ export const uploadPopulationPromiseHOC = (
const collection = req.payload.collections[node?.relationTo]
if (collection) {
const populateDepth =
props?.maxDepth !== undefined && props?.maxDepth < depth ? props?.maxDepth : depth
promises.push(
populate({
id: node?.value?.id,
collection,
currentDepth,
data: node,
depth,
depth: populateDepth,
draft: false,
field,
key: 'value',

View File

@@ -249,6 +249,7 @@ export {
export { ParagraphFeature } from './field/features/Paragraph'
export { RelationshipFeature } from './field/features/Relationship'
export {
$createRelationshipNode,
$isRelationshipNode,
@@ -283,11 +284,11 @@ export { defaultHTMLConverters } from './field/features/converters/html/converte
export type { HTMLConverter } from './field/features/converters/html/converter/types'
export { consolidateHTMLConverters } from './field/features/converters/html/field'
export { lexicalHTML } from './field/features/converters/html/field'
export { TestRecorderFeature } from './field/features/debug/TestRecorder'
export { TreeViewFeature } from './field/features/debug/TreeView'
export { TreeViewFeature } from './field/features/debug/TreeView'
export { BoldTextFeature } from './field/features/format/Bold'
export { InlineCodeTextFeature } from './field/features/format/InlineCode'
export { ItalicTextFeature } from './field/features/format/Italic'
export { SectionWithEntries as FormatSectionWithEntries } from './field/features/format/common/floatingSelectToolbarSection'
@@ -295,6 +296,7 @@ export { StrikethroughTextFeature } from './field/features/format/strikethrough'
export { SubscriptTextFeature } from './field/features/format/subscript'
export { SuperscriptTextFeature } from './field/features/format/superscript'
export { UnderlineTextFeature } from './field/features/format/underline'
export { HorizontalRuleFeature } from './field/features/horizontalrule'
export { IndentFeature } from './field/features/indent'
export { CheckListFeature } from './field/features/lists/CheckList'
export { OrderedListFeature } from './field/features/lists/OrderedList'