Commit Graph

471 Commits

Author SHA1 Message Date
Alessio Gravili 86fdad0bb8 chore: significantly improve eslint performance, lint and prettier everything 2024-08-29 21:25:50 -04:00
James Mikrut 538b7ee616 feat!: auto-removes localized property from localized fields within other localized fields (#7933)
## Description

Payload localization works on a field-by-field basis. As you can nest
fields within other fields, you could potentially nest a localized field
within a localized field—but this would be redundant and unnecessary.
There would be no reason to define a localized field within a localized
parent field, given that the entire data structure from the parent field
onward would be localized.

Up until this point, Payload would _allow_ you to nest a localized field
within another localized field, and this might have worked in MongoDB
but it will throw errors in Postgres.

Now, Payload will automatically remove the `localized: true` property
from sub-fields within `sanitizeFields` if a parent field is localized.

This could potentially be a breaking change if you have a configuration
with MongoDB that nests localized fields within localized fields.

## Migrating

You probably only need to migrate if you are using MongoDB, as there,
you may not have noticed any problems. But in Postgres or SQLite, this
would have caused issues so it's unlikely that you've made it too far
without experiencing issues due to a nested localized fields config.

In the event you would like to keep existing data in this fashion, we
have added a `compatibility.allowLocalizedWithinLocalized` flag to the
Payload config, which you can set to `true`, and Payload will then
disable this new sanitization step.

Set this compatibility flag to `true` only if you have an existing
Payload MongoDB database from pre-3.0, and you have nested localized
fields that you would like to maintain without migrating.
2024-08-29 01:56:17 +00:00
Jacob Fletcher 3a91deb0a4 feat: threads field config through components and strictly types props (#7754)
## Description

Threads the field config to all "field subcomponents" through props,
i.e. field label, description, error, etc. This way, the field config
that controls any particular component is easily accessible and strongly
typed, i.e. `props.field.maxLength`. This is true for both server and
client components, whose server-side props are now also contextually
typed. This behavior was temporarily removed in #7474 due to bloating
HTML, but has since been resolved in #7620. This PR also makes
significant improvements to component types by exporting explicit types
for _every component of every field_, each with its own client/server
variation. Now, a custom component can look something like this:

```tsx
import type { TextFieldLabelServerComponent } from 'payload'

import React from 'react'

export const CustomLabel: TextFieldLabelServerComponent = (props) => {
  return (
    <div>{`The max length of this field is: ${props?.field?.maxLength}`}</div>
  )
}
```

The following types are now available:

```ts
import type {
  TextFieldClientComponent,
  TextFieldServerComponent,
  TextFieldLabelClientComponent,
  TextFieldLabelServerComponent,
  TextFieldDescriptionClientComponent,
  TextFieldDescriptionServerComponent,
  TextFieldErrorClientComponent,
  TextFieldErrorServerComponent,
  // ...and so one for each field
} from 'payload'
```

BREAKING CHANGES:

In order to strictly type these components, a few breaking changes have
been made _solely to type definitions_. This only effects you if you are
heavily using custom components.

Old
```ts
import type { ErrorComponent, LabelComponent, DescriptionComponent } from 'payload'
```

New:
```ts
import type {
  FieldErrorClientComponent,
  FieldErrorServerComponent,
  FieldLabelClientComponent,
  FieldLabelServerComponent,
  FieldDescriptionClientComponent,
  FieldDescriptionServerComponent,
  // Note: these are the generic, underlying types of the more stricter types described above ^
  // For example, you should use the type that is explicit for your particular field and environment
  // i.e. `TextFieldLabelClientComponent` and not simply `FieldLabelClientComponent`
} from 'payload'
```

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
2024-08-20 04:25:10 +00:00
Jacob Fletcher a526c7becd feat: custom view and document-level metadata (#7716) 2024-08-18 23:22:38 -04:00
Alessio Gravili 49a2d70fbb feat: allow passing false as PayloadComponent which signals that the component should not be rendered (#7682)
If it's undefined/null => Fallback Component may be rendered
If it's false => No component should be rendered - as if an empty
component was passed in

This ensures that the user does not have to install `@payloadcms/ui`
anymore, which previously exported an empty component to be used in
component paths
2024-08-14 22:31:58 +00:00
Alessio Gravili 90b7b20699 feat!: beta-next (#7620)
This PR makes three major changes to the codebase:

1. [Component Paths](#component-paths)
Instead of importing custom components into your config directly, they
are now defined as file paths and rendered only when needed. That way
the Payload config will be significantly more lightweight, and ensures
that the Payload config is 100% server-only and Node-safe. Related
discussion: https://github.com/payloadcms/payload/discussions/6938

2. [Client Config](#client-config)
Deprecates the component map by merging its logic into the client
config. The main goal of this change is for performance and
simplification. There was no need to deeply iterate over the Payload
config twice, once for the component map, and another for the client
config. Instead, we can do everything in the client config one time.
This has also dramatically simplified the client side prop drilling
through the UI library. Now, all components can share the same client
config which matches the exact shape of their Payload config (with the
exception of non-serializable props and mapped custom components).

3. [Custom client component are no longer
server-rendered](#custom-client-components-are-no-longer-server-rendered)
Previously, custom components would be server-rendered, no matter if
they are server or client components. Now, only server components are
rendered on the server. Client components are automatically detected,
and simply get passed through as `MappedComponent` to be rendered fully
client-side.

## Component Paths

Instead of importing custom components into your config directly, they
are now defined as file paths and rendered only when needed. That way
the Payload config will be significantly more lightweight, and ensures
that the Payload config is 100% server-only and Node-safe. Related
discussion: https://github.com/payloadcms/payload/discussions/6938

In order to reference any custom components in the Payload config, you
now have to specify a string path to the component instead of importing
it.

Old:

```ts
import { MyComponent2} from './MyComponent2.js'

admin: {
  components: {
    Label: MyComponent2
  },
},
```

New:

```ts
admin: {
  components: {
    Label: '/collections/Posts/MyComponent2.js#MyComponent2', // <= has to be a relative path based on a baseDir configured in the Payload config - NOT relative based on the importing file
  },
},
```

### Local API within Next.js routes

Previously, if you used the Payload Local API within Next.js pages, all
the client-side modules are being added to the bundle for that specific
page, even if you only need server-side functionality.

This `/test` route, which uses the Payload local API, was previously 460
kb. It is now down to 91 kb and does not bundle the Payload client-side
admin panel anymore.

All tests done
[here](https://github.com/payloadcms/payload-3.0-demo/tree/feat/path-test)
with beta.67/PR, db-mongodb and default richtext-lexical:

**dev /admin before:**
![CleanShot 2024-07-29 at 22 49
12@2x](https://github.com/user-attachments/assets/4428e766-b368-4bcf-8c18-d0187ab64f3e)

**dev /admin after:**
![CleanShot 2024-07-29 at 22 50
49@2x](https://github.com/user-attachments/assets/f494c848-7247-4b02-a650-a3fab4000de6)

---

**dev /test before:**
![CleanShot 2024-07-29 at 22 56
18@2x](https://github.com/user-attachments/assets/1a7e9500-b859-4761-bf63-abbcdac6f8d6)

**dev /test after:**
![CleanShot 2024-07-29 at 22 47
45@2x](https://github.com/user-attachments/assets/f89aa76d-f2d5-4572-9753-2267f034a45a)

---

**build before:**
![CleanShot 2024-07-29 at 22 57
14@2x](https://github.com/user-attachments/assets/5f8f7281-2a4a-40a5-a788-c30ddcdd51b5)

**build after::**
![CleanShot 2024-07-29 at 22 56
39@2x](https://github.com/user-attachments/assets/ea8772fd-512f-4db0-9a81-4b014715a1b7)

### Usage of the Payload Local API / config outside of Next.js

This will make it a lot easier to use the Payload config / local API in
other, server-side contexts. Previously, you might encounter errors due
to client files (like .scss files) not being allowed to be imported.

## Client Config

Deprecates the component map by merging its logic into the client
config. The main goal of this change is for performance and
simplification. There was no need to deeply iterate over the Payload
config twice, once for the component map, and another for the client
config. Instead, we can do everything in the client config one time.
This has also dramatically simplified the client side prop drilling
through the UI library. Now, all components can share the same client
config which matches the exact shape of their Payload config (with the
exception of non-serializable props and mapped custom components).

This is breaking change. The `useComponentMap` hook no longer exists,
and most component props have changed (for the better):

```ts
const { componentMap } = useComponentMap() // old
const { config } = useConfig() // new
```

The `useConfig` hook has also changed in shape, `config` is now a
property _within_ the context obj:

```ts
const config = useConfig() // old
const { config } = useConfig() // new
```

## Custom Client Components are no longer server rendered

Previously, custom components would be server-rendered, no matter if
they are server or client components. Now, only server components are
rendered on the server. Client components are automatically detected,
and simply get passed through as `MappedComponent` to be rendered fully
client-side.

The benefit of this change:

Custom client components can now receive props. Previously, the only way
for them to receive dynamic props from a parent client component was to
use hooks, e.g. `useFieldProps()`. Now, we do have the option of passing
in props to the custom components directly, if they are client
components. This will be simpler than having to look for the correct
hook.

This makes rendering them on the client a little bit more complex, as
you now have to check if that component is a server component (=>
already has been rendered) or a client component (=> not rendered yet,
has to be rendered here). However, this added complexity has been
alleviated through the easy-to-use `<RenderMappedComponent />` helper.

This helper now also handles rendering arrays of custom components (e.g.
beforeList, beforeLogin ...), which actually makes rendering custom
components easier in some cases.

## Misc improvements

This PR includes misc, breaking changes. For example, we previously
allowed unions between components and config object for the same
property. E.g. for the custom view property, you were allowed to pass in
a custom component or an object with other properties, alongside a
custom component.

Those union types are now gone. You can now either pass an object, or a
component. The previous `{ View: MyViewComponent}` is now `{ View: {
Component: MyViewComponent} }` or `{ View: { Default: { Component:
MyViewComponent} } }`.

This dramatically simplifies the way we read & process those properties,
especially in buildComponentMap. We can now simply check for the
existence of one specific property, which always has to be a component,
instead of running cursed runtime checks on a shared union property
which could contain a component, but could also contain functions or
objects.

![CleanShot 2024-07-29 at 23 07
07@2x](https://github.com/user-attachments/assets/1e75aa4c-7a4c-419f-9070-216bb7b9a5e5)

![CleanShot 2024-07-29 at 23 09
40@2x](https://github.com/user-attachments/assets/b4c96450-6b7e-496c-a4f7-59126bfd0991)

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

---------

Co-authored-by: PatrikKozak <patrik@payloadcms.com>
Co-authored-by: Paul <paul@payloadcms.com>
Co-authored-by: Paul Popus <paul@nouance.io>
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Co-authored-by: James <james@trbl.design>
2024-08-13 12:54:33 -04:00
Jarrod Flesch 442189ec48 fix: email and username fields rendering in drawers (#7520)
Fixes https://github.com/payloadcms/payload/issues/7428

Now email and username fields are rendered with the RenderFields
component, making them behave similarly to other fields. They now appear
and can respect doc permissions, readOnly settings, etc.
2024-08-05 20:18:32 -04:00
Patrik 62666a9897 fix(ui): properly handles ID field component type based on payload.db.defaultIDType (#7416)
## Description

Fixes #7354 

Since the `defaultIDType` for IDs in `postgres` are of type `number` -
the `contains` operator should be available in the filter options.

This PR checks the `defaultIDType` of ID and properly outputs the
correct component type for IDs

I.e if ID is of type `number` - the filter operators for ID should
correspond to the the operators of type number as well

The `contains` operator only belongs on fields of type string, aka of
component type `text`

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] Existing test suite passes locally with my changes
2024-08-05 16:39:27 -04:00
Jarrod Flesch 1ebd54b315 feat: allows loginWithUsername to not require username (#7480)
Allows username to be optional when using the new loginWithUsername
feature. This can be done by the following:

```ts
auth: {
  loginWithUsername: {
    requireUsername: false, // <-- new property, default true
    requireEmail: false, // default: false
    allowEmailLogin: true, // default false
  },
},
```
2024-08-05 11:35:01 -04:00
Alessio Gravili 995f51d941 fix: too many RSC props were being passed, inflating initial HTML size (#7474)
The following config caused the html size to grow to 500mb:

```ts
import type { ArrayField, Block, CollectionConfig } from 'payload'

import { BlocksFeature, lexicalEditor } from '@payloadcms/richtext-lexical'

const richTextLayoutBlockGridBoxes2: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [],
    },
  ],
}

const richTextLayoutBlock2: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes2],
}

const richTextBlock2: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock2] }),
        ],
      }),
    },
  ],
}

const richTextLayoutBlockGridBoxes1: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock2],
    },
  ],
}

const richTextLayoutBlock1: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes1],
}

const richTextBlock1: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock1] }),
        ],
      }),
    },
  ],
}

const richTextLayoutBlockGridBoxes: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock1],
    },
  ],
}

const richTextLayoutBlock: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes],
}

const richTextBlock: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock] }),
        ],
      }),
    },
  ],
}

const layoutBlockGridBoxes2: ArrayField = {
  name: 'gridBx',
  label: 'Grid Boxes',
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock],
    },
  ],
}

const layoutBlock2: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes2],
}

const layoutBlockGridBoxes1: ArrayField = {
  name: 'gridBx',
  label: 'Grid Boxes',
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [layoutBlock2, richTextBlock],
    },
  ],
}

const layoutBlock1: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes1],
}

const layoutBlockGridBoxes: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [layoutBlock1, richTextBlock],
    },
  ],
}

const layoutBlock: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes],
}

export const Pages: CollectionConfig = {
  slug: 'pages',
  fields: [
    {
      name: 'content',
      type: 'blocks',
      blocks: [layoutBlock],
    },
  ],
}
```

---------

Co-authored-by: James <james@trbl.design>
2024-08-02 13:17:56 +00:00
Radosław Kłos 4d19e64961 feat: adds upload's relationship thumbnail (#7473)
## Description
https://github.com/payloadcms/payload/pull/5015 's version for beta
branch. @JessChowdhury

- [X] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

<!-- Please delete options that are not relevant. -->

- [X] New feature (non-breaking change which adds functionality)
- [X] This change requires a documentation update

## Checklist:

- [X] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [X] I have made corresponding changes to the documentation
2024-08-02 14:03:12 +01:00
Jacob Fletcher 97837f0708 feat(ui)!: passes field props to custom components (#7360)
## Description

Currently, there is no way to read field props from within a custom
field component, i.e. `admin.components.Description`. For example, if
you set `maxLength: 100` on your field, your custom description
component cannot read it from `props.maxLength` or any other methods.
Because these components are rendered on the server, there is also no
way of using `admin.component.Field` to inject custom props yourself,
either. To support this, we can simply pass the base component props
into these components on the server, as expected. This has also led to
custom field component props becoming more strictly typed within the
config.

This change is considered breaking only because the types have changed.
This only affects you if you were previously importing the following
types into your own custom components. To migrate, simply change the
import paths for that type.

Old:
```ts
import type {
  ArrayFieldProps,
  ReducedBlock,
  BlocksFieldProps,
  CheckboxFieldProps,
  CodeFieldProps,
  CollapsibleFieldProps,
  DateFieldProps,
  EmailFieldProps,
  GroupFieldProps,
  HiddenFieldProps,
  JSONFieldProps,
  NumberFieldProps,
  PointFieldProps,
  RadioFieldProps,
  RelationshipFieldProps,
  RichTextComponentProps,
  RowFieldProps,
  SelectFieldProps,
  TabsFieldProps,
  TextFieldProps,
  TextareaFieldProps,
  UploadFieldProps,
  ErrorProps,
  FormFieldBase, 
  FieldComponentProps,
  FieldMap,
  MappedField,
  MappedTab,
  ReducedBlock,
} from '@payloadcms/ui'
```

New:
```ts
import type {
  FormFieldBase, 
  // etc.
} from 'payload'
```

Custom field components are now much more strongly typed. To make this
happen, an explicit type for every custom component has been generated
for every field type. The convention is to append
`DescriptionComponent`, `LabelComponent`, and `ErrorComponent` onto the
end of the field name, i.e. `TextFieldDescriptionComponent`. Here's an
example:

```ts
import type { TextFieldDescriptionComponent } from 'payload'

import React from 'react'

export const CustomDescription: TextFieldDescriptionComponent = (props) => {
  return (
    <div id="custom-field-description">{`The max length of this field is: ${props?.maxLength}`}</div>
  )
}
```

Here's the full list of all new types:

Label Components:

```ts
import type {
  ArrayFieldLabelComponent,
  BlocksFieldLabelComponent,
  CheckboxFieldLabelComponent,
  CodeFieldLabelComponent,
  CollapsibleFieldLabelComponent,
  DateFieldLabelComponent,
  EmailFieldLabelComponent,
  GroupFieldLabelComponent,
  HiddenFieldLabelComponent,
  JSONFieldLabelComponent,
  NumberFieldLabelComponent,
  PointFieldLabelComponent,
  RadioFieldLabelComponent,
  RelationshipFieldLabelComponent,
  RichTextFieldLabelComponent,
  RowFieldLabelComponent,
  SelectFieldLabelComponent,
  TabsFieldLabelComponent,
  TextFieldLabelComponent,
  TextareaFieldLabelComponent,
  UploadFieldLabelComponent
} from 'payload'
```

Error Components:

```tsx
import type {
  ArrayFieldErrorComponent,
  BlocksFieldErrorComponent,
  CheckboxFieldErrorComponent,
  CodeFieldErrorComponent,
  CollapsibleFieldErrorComponent,
  DateFieldErrorComponent,
  EmailFieldErrorComponent,
  GroupFieldErrorComponent,
  HiddenFieldErrorComponent,
  JSONFieldErrorComponent,
  NumberFieldErrorComponent,
  PointFieldErrorComponent,
  RadioFieldErrorComponent,
  RelationshipFieldErrorComponent,
  RichTextFieldErrorComponent,
  RowFieldErrorComponent,
  SelectFieldErrorComponent,
  TabsFieldErrorComponent,
  TextFieldErrorComponent,
  TextareaFieldErrorComponent,
  UploadFieldErrorComponent
} from 'payload'
```

Description Components:

```tsx
import type {
  ArrayFieldDescriptionComponent,
  BlocksFieldDescriptionComponent,
  CheckboxFieldDescriptionComponent,
  CodeFieldDescriptionComponent,
  CollapsibleFieldDescriptionComponent,
  DateFieldDescriptionComponent,
  EmailFieldDescriptionComponent,
  GroupFieldDescriptionComponent,
  HiddenFieldDescriptionComponent,
  JSONFieldDescriptionComponent,
  NumberFieldDescriptionComponent,
  PointFieldDescriptionComponent,
  RadioFieldDescriptionComponent,
  RelationshipFieldDescriptionComponent,
  RichTextFieldDescriptionComponent,
  RowFieldDescriptionComponent,
  SelectFieldDescriptionComponent,
  TabsFieldDescriptionComponent,
  TextFieldDescriptionComponent,
  TextareaFieldDescriptionComponent,
  UploadFieldDescriptionComponent
} from 'payload'
```

This PR also:
- Standardizes the `FieldBase['label']` type with a new `LabelStatic`
type. This makes type usage much more consistent across components.
- Simplifies some of the typings in the field component map, removes
unneeded `<Omit>`, etc.
- Fixes misc. linting issues around voiding promises

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-07-26 14:03:25 -04:00
Alessio Gravili c45fbb9149 feat!: 700% faster deepCopyObject, refactor deep merging and deep copying, type improvements (#7272)
**BREAKING:**
- The `deepMerge` exported from payload now handles more complex data and
is slower. The old, simple deepMerge is now exported as `deepMergeSimple`
- `combineMerge` is no longer exported. You can use
`deepMergeWithCombinedArrays` instead
- The behavior of the exported `deepCopyObject` and `isPlainObject` may
be different and more reliable, as the underlying algorithm has changed
2024-07-22 13:01:52 -04:00
Alessio Gravili 83fd4c6622 chore: run lint and prettier on entire codebase 2024-07-11 15:27:01 -04:00
Jarrod Flesch 0711f880ff chore!: simplify api handler (#6910)
Removes PayloadRequestWithData in favour of just PayloadRequest with
optional types for `data` and `locale`

`addDataAndFileToRequest` and `addLocalesToRequestFromData` now takes in
a single argument instead of an object

```ts
// before
await addDataAndFileToRequest({ request: req })
addLocalesToRequestFromData({ request: req })

// current
await addDataAndFileToRequest(req)
addLocalesToRequestFromData(req)
```

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-07-02 09:47:03 -04:00
Jarrod Flesch d8d5a44895 feat: ability to add custom upload component (#6927) 2024-06-26 09:37:22 -04:00
Alessio Gravili e7159c033e fix(ui,richtext-*): path from context should always have precedence over path from props, even if it's an empty string (#6782) 2024-06-15 05:42:16 +00:00
Alessio Gravili 628749573e fix(ui): properly type Select element onChange type, as well as any components using it (#6785) 2024-06-14 22:28:59 -04:00
Jarrod Flesch 082650c0e2 fix: attempt to use user locale preference when not set as query param (#6761)
Fixes https://github.com/payloadcms/payload/issues/6619

Attempt to use user preference if available when loading view data instead of always relying on query param when loading view data.
2024-06-13 11:22:28 -04:00
Alessio Gravili 4e127054ca feat(richtext-lexical)!: sub-field hooks and localization support (#6591)
## BREAKING
- Our internal field hook methods now have new required `schemaPath` and
path `props`. This affects the following functions, if you are using
those: `afterChangeTraverseFields`, `afterReadTraverseFields`,
`beforeChangeTraverseFields`, `beforeValidateTraverseFields`,
`afterReadPromise`
- The afterChange field hook's `value` is now the value AFTER the
previous hooks were run. Previously, this was the original value, which
I believe is a bug
- Only relevant if you have built your own richText adapter: the
richText adapter `populationPromises` property has been renamed to
`graphQLPopulationPromises` and is now only run for graphQL. Previously,
it was run for graphQL AND the rest API. To migrate, use
`hooks.afterRead` to run population for the rest API
- Only relevant if you have built your own lexical features: The
`populationPromises` server feature property has been renamed to
`graphQLPopulationPromises` and is now only run for graphQL. Previously,
it was run for graphQL AND the rest API. To migrate, use
`hooks.afterRead` to run population for the rest API
- Serialized lexical link and upload nodes now have a new `id` property.
While not breaking, localization / hooks will not work for their fields
until you have migrated to that. Re-saving the old document on the new
version will automatically add the `id` property for you. You will also
get a bunch of console logs for every lexical node which is not migrated
2024-06-12 13:33:08 -04:00
Alessio Gravili 5cb49c3307 fix(richtext-*): fix client features were not loaded properly, improve performance of LexicalProvider, slate cell component was non-functional, support richtext adapter Cell RSCs (#6573) 2024-05-30 16:26:06 -04:00
Jacob Fletcher 92f458dad2 feat(next,ui): improves loading states (#6434) 2024-05-29 14:01:13 -04:00
Alessio Gravili c383f391e3 feat(richtext-lexical): i18n support (#6524) 2024-05-28 09:10:39 -04:00
Alessio Gravili 79f4907cb3 feat!: add missing server-only props to custom RSCs, improve req.user type, clean-up ui imports (#6355) 2024-05-14 17:27:15 -04:00
Alessio Gravili f716122eab feat!: typed i18n (#6343) 2024-05-14 11:10:31 -04:00
Alessio Gravili cfeac79b99 feat!: fix non-functional custom RSC component handling, separate label and description props, fix non-functional label function handling (#6264)
Breaking Changes:

- Globals config: `admin.description` no longer accepts a custom component. You will have to move it to `admin.components.elements.Description`
- Collections config: `admin.description` no longer accepts a custom component. You will have to move it to `admin.components.edit.Description`
- All Fields: `field.admin.description` no longer accepts a custom component. You will have to move it to `field.admin.components.Description`
- Collapsible Field: `field.label` no longer accepts a custom component. You will have to move it to `field.admin.components.RowLabel`
- Array Field: `field.admin.components.RowLabel` no longer accepts strings or records
- If you are using our exported field components in your own app, their `labelProps` property has been stripped down and no longer contains the `label` and `required` prop. Those can now only be configured at the top-level
2024-05-09 17:12:01 -04:00
Alessio Gravili 8e55a2a866 feat(richtext-lexical)!: strongly typed PluginComponent types, remove LexicalBlocks, improve exports, fix e2e (#6255)
**BREAKING:**
- Narrows the type of the `plugins` prop of lexical features. Client props are now also automatically provided to the plugin components. To migrate, type your plugin as either `PluginComponent` or PluginComponentWithAnchor.
- `BlockQuoteFeature` has been renamed to `BlockquoteFeature`
- `createClientComponent` is now exported only from /components
- The `LexicalBlocks` and `FieldWithRichTextRequiredEditor` types have been removed in favor of just `Blocks` & `Fields`, as well as improved validation.
2024-05-07 16:26:28 -04:00
Jarrod Flesch 51149c75ff fix: threads draft arg through for child resolvers in GraphQL queries (#6196) 2024-05-04 16:43:17 -04:00
Alessio Gravili d9bb51fdc7 feat(richtext-lexical)!: initialize lexical during sanitization (#6119)
BREAKING:

- sanitizeFields is now an async function
- the richText adapters now return a function instead of returning the adapter directly
2024-04-30 15:09:32 -04:00
Jacob Fletcher 2d089a7bae chore: threads permissions through document tab conditions 2024-04-26 17:38:59 -04:00
Jarrod Flesch 22c53392a3 chore: improves types for payloadRequest (#6012) 2024-04-25 10:23:03 -04:00
Alessio Gravili 39ba39c237 feat(richtext-lexical)!: rework how population works and saves data, improve node typing 2024-04-17 11:46:47 -04:00
Jacob Fletcher 1275c70187 feat(ui): provides payload as prop to all custom server components (#5775) 2024-04-11 11:16:15 -04:00
James 69e884f5b7 chore: dynamically loads date-fns locales 2024-04-08 22:12:05 -04:00
James 30948ab545 chore: dynamically loads translations 2024-04-08 16:25:21 -04:00
Jacob Fletcher 91f9973c6c fix(next): properly types locale in live preview url 2024-04-05 13:37:07 -04:00
Jacob Fletcher ecf40cc747 fix(ui): renders field description functions 2024-04-03 13:18:49 -04:00
Jacob Fletcher 799370f753 fix(next): establishes pattern for preview urls (#5581) 2024-04-01 17:30:49 -04:00
Jacob Fletcher b6ad218126 fix(ui): establishes pattern for hidden entities (#5546) 2024-03-29 10:32:09 -04:00
Jarrod Flesch 8636685252 fix: simplifies field error paths (#5504) 2024-03-28 13:15:44 -04:00
Alessio Gravili db8e805a96 fix: improve error path merging from server, make sure no new or removed rows/values coming from the server are being considered outside addFieldRow 2024-03-27 15:55:19 -04:00
Jacob Fletcher 20b4585666 chore: properly types cell components (#5474) 2024-03-26 12:08:33 -04:00
Paul 9c7e7ed8d4 fix(ui): custom buttons and e2e refresh permissions test (#5458)
* moved refresh permissions test suite to access control

* support for custom Save, SaveDraft and Publish buttons in admin config for collections and globals

* moved navigation content to client side so that permissions can be refreshed from active state
2024-03-26 11:48:00 -03:00
Jacob Fletcher 072a903351 Merge pull request #5461 from payloadcms/fix/misc-views
Fix/misc views
2024-03-25 23:35:15 -04:00
Jacob Fletcher 1c1847f63c fix(next): dynamic params for custom collection and global views 2024-03-25 22:56:19 -04:00
Jarrod Flesch 5266612bb3 chore: get correct labels for unnamed fields in list view (#5454) 2024-03-25 15:31:23 -04:00
Jacob Fletcher 5de1883390 fix(ui): ensures row label context exists for collapsible fields (#5416) 2024-03-21 16:41:35 -04:00
Jacob Fletcher 64d6163f13 chore(ui): consolidates field label, error, and description components 2024-03-21 12:08:20 -04:00
Patrik cb5d005e68 test: passing array fields test suite (#5383)
* test: array tests passing except bulk update

* test: passing array fields test suite
2024-03-20 12:00:56 -04:00
Jacob Fletcher 06cd13aef2 chore(ui): types mapped rich text field props 2024-03-19 23:37:50 -04:00