Commit Graph

4537 Commits

Author SHA1 Message Date
Alessio Gravili
4345820bbd Merge remote-tracking branch 'origin/main' into feat/plugin-seo-placeholders-lexical 2024-12-13 11:55:14 -07:00
Alessio Gravili
62ba27b3bf plugin-seo with placeholders and lexical 2024-12-13 11:55:00 -07:00
Elliot DeNolf
4c3e41beb1 chore(release): v3.7.0 [skip ci] 2024-12-13 12:06:46 -05:00
Jessica Chowdhury
50e7c24b17 fix(plugin-nested-docs): publishing parent doc should not publish child doc (#9958)
## Bug Fix

### Issue
Draft children documents get overwritten when the parent document is
published.

### Fix
Correctly retrieve all documents, including drafts, during the resave
process. Add test to ensure parent documents can be published without
impacting the state of any children docs.
2024-12-13 12:04:07 -05:00
Jacob Fletcher
796df37461 fix(ui): awaits form state before rendering conditional fields (#9933)
When a condition exists on a field and it resolves to `false`, it
currently "blinks" in and out when rendered within an array or block
row. This is because when add rows to form state, we iterate over the
_fields_ of that row and render their respective components. Then when
conditions are checked for that field, we're expecting `passesCondition`
to be explicitly `false`, ultimately _rendering_ the field for a brief
moment before form state returns with evaluated conditions. The fix is
to set these fields into local form state with a new `isLoading: true`
prop, then display a loader within the row until form state returns with
its proper conditions.
2024-12-13 16:42:52 +00:00
Elliot DeNolf
9c8cdea4b3 test: mock nodemailer network calls (#9957)
In tests, nodemailer was making network calls to create test accounts
using ethereal.email. This mocks them appropriately.
2024-12-13 11:31:24 -05:00
Elliot DeNolf
4334940755 chore(payload-cloud): improve error log of staticHandler (#9934)
Improve error logging of staticHandler.

Before:
`Error getting file from cloud storage`

After:
`Error getting file from cloud storage: some-file.png` and additional
params.
2024-12-13 11:10:41 -05:00
Sasha
b101feca7a feat: expose pagination: false to REST / GraphQL (#9952)
Exposes `pagination: false` to REST / GraphQL to improve performance on
large collections by avoiding count query.
This will also be nice for our SDK
https://github.com/payloadcms/payload/pull/9463 to have the same
properties.
2024-12-13 16:23:43 +02:00
Alessio Gravili
0d07ce22e8 feat: add waitUntil property to payload.jobs.queue (#9950) 2024-12-13 00:39:05 +00:00
Patrik
a582431a36 fix(ui): properly passes readOnly prop to email & username auth fields (#9938)
### What?

The `readOnly` prop was not being passed down to the `email` &
`username` auth fields.

Resulting in these fields not being disabled properly if `update` access
was restricted.

### How?

Passes the `readOnly` prop through to the fields and now properly
disables these fields if `update` access is restricted.
2024-12-12 17:40:23 -05:00
Patrik
7a8b46484b fix: updates username validation to allow for all special character usage (#9946)
### What?

Previously, only `.` & `-` special chars were allowed in usernames

### How?

Now - all special chars are accepted during username creating like `@`
2024-12-12 22:21:31 +00:00
Germán Jabloñski
6fffbdb27a chore(translations): improve password reset message (#9931)
It is still not indicated whether the email exists or not for security
reasons, but:
1. It is indicated that it is a possibility (if the email exists, the
email will be sent).
2. The user is advised to check the spam and junk mail folders.
2024-12-12 20:19:15 +00:00
Dan Ribbens
5af71fb8d0 fix: join collection read access (#9930)
Respect read access control through the join field collections for GraphQL and admin UI

fixes #9922 and #9865
2024-12-12 12:01:03 -05:00
Alessio Gravili
d4d79c1141 feat: allow loading predefined migrations from proper exports (#9872)
Currently, predefined migrations can only be loaded if they are part of
one of our db adapters.

With this PR, plugins will be able to export their own predefined
migrations that can be created like this:

`pnpm payload migrate:create --file
@payloadcms/plugin-someplugin/someMigration`

with the plugin exporting it in their package.json:

```json
  "exports": {
    "./someMigration": {
      "import": "./someMigration.mjs",
      "types": "./someMigration.mjs",
      "default": "./someMigration.mjs"
    }
  },
```
2024-12-12 09:39:20 -07:00
Germán Jabloñski
9d324ff207 docs: update Lexical to JSX documentation for RichText component (#9926) 2024-12-12 13:21:59 +00:00
Alessio Gravili
fffab668c9 chore: export JobLog and importHandlerPath, add missing id type to JobLog (#9921)
Requirement for https://github.com/payloadcms/payload/pull/9645
2024-12-12 06:58:47 +00:00
Alessio Gravili
bae2fe535e feat(ui): allow customizing min height of code editor (#9920)
Requirement for https://github.com/payloadcms/payload/pull/9645.

Dynamic code field resizing currently is broken for line-breaks - need
to address that in a future PR.
2024-12-12 06:31:39 +00:00
Alessio Gravili
c8046cade7 chore(ui): export SearchFilter, EditUpload, FileDetails, PreviewSizes, PreviewButton, ErrorIcon, InfoIcon, SuccessIcon, WarningIcon (#9919)
Fixes https://github.com/payloadcms/payload/issues/9794
2024-12-12 06:23:26 +00:00
Sasha
5e3963482e fix(db-postgres): payload.db.upsert inserts new rows instead of updating existing ones (#9916)
### What?
`payload.db.updateOne` (and so `payload.db.upsert`) with drizzle
adapters used incoming `where` incorrectly and worked properly only
either if you passed `id` or some where query path required table joins
(like `where: { 'array.title'`) which is also the reason why `upsert`
_worked_ with user preferences specifically, because we need to join the
`preferences_rels` table to query by `user.relationTo` and `user.value`

Fixes https://github.com/payloadcms/payload/issues/9915

This was found here - https://github.com/payloadcms/payload/pull/9913,
the database KV adapter uses `upsert` with `where` by unique fields.
2024-12-12 03:53:57 +02:00
Patrik
d9efd192e7 fix(ui): truncates richtext fields when displaying within a joins field (#9911)
### What?

Previously, `richtext` fields were not properly truncated when displayed
in a `joins` field.

`Before`:

![Screenshot 2024-12-11 at 3 42
13 PM](https://github.com/user-attachments/assets/a6f44248-8cb9-4a38-a74c-eaa88b739601)

### How?

Now - we've added proper css styling to truncate extended `richtext`
elements inside a `joins` table.

`After`:

![Screenshot 2024-12-11 at 3 41
53 PM](https://github.com/user-attachments/assets/ae846c50-2e29-411f-b056-20e4caf3ef20)
2024-12-11 17:03:27 -05:00
Jacob Fletcher
4c57df69ca refactor(ui): migrates away from React.forwardRef (#9907)
As of React 19, `ref` can now be accessed directly from props and no
longer require the use of `React.forwardRef`.
2024-12-11 21:09:05 +00:00
Marwin Hormiz
821bd35578 fix(translations): capitalized swedish 'collapseAll' translation (#9908)
Co-authored-by: Marwin Hormiz <marwinhormiz@duobit.se>
2024-12-11 20:42:40 +00:00
Alessio Gravili
00d438e91f refactor(ui): export TableColumnsProvider, documentDrawerBaseClass and SelectMany (#9899) 2024-12-11 18:34:58 +00:00
Patrik
b1d92c2bad feat: allows excluding entities from the nav sidebar / dashboard without disabling its routes (#9897)
### What?

Previously, the `admin.group` property on `collection` / `global`
configs allowed for a custom group and the `admin.hidden` property would
not only hide the entity from the nav sidebar / dashboard but also
disable its routes.

### Why?

There was not a simple way to hide an entity from the nav sidebar /
dashboard but still keep the entities routes.

### How?

Now - we've added the `false` type to the `admin.group` field to account
for this.

Passing `false` to `admin.group` will hide the entity from the sidebar
nav and dashboard but keep the routes available to navigate.

I.e

```
admin: {
  group: false,
},
```
2024-12-11 13:31:12 -05:00
Elliot DeNolf
45d20643df chore(release): v3.6.0 [skip ci] 2024-12-11 13:05:47 -05:00
Alessio Gravili
91e8acc871 fix: cannot pass function to client error when defining server-only props in custom field components (#9898)
Fixes https://github.com/payloadcms/payload/issues/9895

We were still including field custom components in the ClientConfig,
which will throw an error if actual server-only properties were passed
to `PayloadComponent.serverProps`. This PR removes them from the
ClientConfig
2024-12-11 18:00:09 +00:00
Alessio Gravili
b83ea8494e refactor(richtext-lexical): export useBlockComponentContext and useInlineBlockComponentContext (#9896) 2024-12-11 10:46:57 -07:00
Sasha
b73fc586b8 feat: expose session, db in migrations to use the active transaction with the database directly (#9849)
This PR adds a feature which fixes another issue with migrations in
Postgres and does few refactors that significantly reduce code
duplication.

Previously, if you needed to use the underlying database directly in
migrations with the active transaction (for example to execute raw SQL),
created from `payload create:migration`, as `req` doesn't work there you
had to do something like this:
```ts
// Postgres
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
  const db = payload.db.sessions?.[await req.transactionID!].db ?? payload.db
  const { rows: posts } = await db.execute(sql`SELECT * from posts`)
}

// MongoDB
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
  const session = payload.db.sessions?.[await req.transactionID!]
  const posts = await payload.db.collections.posts.collection.find({ session }).toArray()
}
```

Which was:
1. Awkward to write
2. Not documented anywhere

Now, we expose `session` and `db` to `up` and `down` functions for you:

#### MongoDB:
```ts
import { type MigrateUpArgs } from '@payloadcms/db-mongodb'

export async function up({ session, payload, req }: MigrateUpArgs): Promise<void> {
  const posts = await payload.db.collections.posts.collection.find({ session }).toArray()
}
```
#### Postgres:
```ts
import { type MigrateUpArgs, sql } from '@payloadcms/db-postgres'

export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
  const { rows: posts } = await db.execute(sql`SELECT * from posts`)
}
```

#### SQLite:
```ts
import { type MigrateUpArgs, sql } from '@payloadcms/db-sqlite'

export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
  const { rows: posts } = await db.run(sql`SELECT * from posts`)
}
```
This actually was a thing with Postgres migrations, we already were
passing `db`, but:
1. Only for `up` and when running `payload migrate`, not for example
with `payload migrate:fresh`
2. Not documented neither in TypeScript or docs.

By ensuring we use `db`, this also fixes an issue that affects all
Postgres/SQLite migrations:

Currently, if we run `payload migration:create` with the postgres
adapter we get a file like this:

```ts
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'

export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
  await payload.db.drizzle.execute(sql`
   CREATE TABLE IF NOT EXISTS "users" (
  	"id" serial PRIMARY KEY NOT NULL,
  );
```
Looks good?
Not exactly!
`payload.db.drizzle.execute()` doesn't really use the current
transaction which can lead to some problems.
Instead, it should use the `db` from `payload.db.sessions?.[await
req.transactionID!].db` because that's where we store our Drizzle
instance with the transaction.

But now, if we generate `payload migrate:create` we get:
```ts
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'

export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
  await db.execute(sql`
   CREATE TABLE IF NOT EXISTS "users" (
  	"id" serial PRIMARY KEY NOT NULL,
  );
```

Which is what we want, as the `db` is passed correctly here:

76428373e4/packages/drizzle/src/migrate.ts (L88-L90)

```ts
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
  const dbWithTransaction = payload.db.sessions?.[await req.transactionID!].db
  payload.logger.info({ one: db === dbWithTransaction })
  payload.logger.info({ two: db === payload.db.drizzle })
```
<img width="336" alt="image"
src="https://github.com/user-attachments/assets/f9fab5a9-44c2-44a9-95dd-8e5cf267f027">

Additionally, this PR refactors:
* `createMigration` with Drizzle - now we have sharable
`buildCreateMigration` in `@payloadcms/drizzle` to reduce copy-pasting
of the same logic.
* the `v2-v3` relationships migration for Postgres is now shared between
`db-postgres` and `db-vercel-postgres`, again to reduce copy-paste.
2024-12-11 12:23:12 -05:00
Said Akhrarov
0303b78d62 fix(next): thread default ServerProps to view actions and other components that were missing (#9868)
This PR threads default `serverProps` to Edit and List view action slots, as well as other various components that were missing them.

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-12-11 17:19:37 +00:00
James Mikrut
a0f0316534 fix: ensures autosave only runs sequentially (#9892)
Previously, Autosave could trigger 2 parallel fetches where the second
could outpace the first, leading to inconsistent results.

Now, we use a simple queue-based system where we can push multiple
autosave events into a queue, and only the latest autosave will be
performed.

This also prevents multiple autosaves from ever running in parallel.
2024-12-11 09:33:48 -06:00
Patrik
522399095c feat(next): adds suppressHydrationWarning property to payload config admin options (#9867)
### What?

There are scenarios where the server-rendered HTML might intentionally
differ from the client-rendered DOM causing `Hydration` errors in the
DOM.

### How?

Added a new prop to the payload config `admin` object called
`suppressHydrationWarning` that allows control to display these warnings
or not.

If you set `suppressHydrationWarning` to `true`, React will not warn you
about mismatches in the attributes and the content of that element.

Defaults to `false` - so if there is a mismatch and this prop is not
defined in your config, the hydration errors will show.

```
admin: {
  suppressHydrationWarning: true // will suppress the errors if there is a mismatch
}
```
2024-12-11 10:24:56 -05:00
Dan Ribbens
306b5d2300 fix: forgotPassword set expiration time (#9871)
The logic for creating a timestamp for use in resetPassword was not
correctly returning a valid date.

---------

Co-authored-by: Patrik Kozak <patrik@payloadcms.com>
2024-12-11 08:43:22 -05:00
Jarrod Flesch
ca52a50dd9 feat: consolidates create and duplicate operations (#9866) 2024-12-10 21:44:47 -05:00
Alessio Gravili
5bfc92d71d fix(next): next.js 15.1.0 compatibility by not importing isRedirectError from next/dist (#9878)
Fixes https://github.com/payloadcms/payload/issues/9876

The import path has changed in Next.js 15.1.0
2024-12-11 01:00:53 +00:00
Alessio Gravili
b1ef28dd39 feat: allow where in payload.jobs.run (#9877)
Example:

```ts
  await payload.jobs.queue({
        task: 'MyTask',
        input: {
          message: `secret`,
        },
 })

await payload.jobs.run({ where: { 'input.message':  { equals: 'secret' } } })
```
2024-12-11 00:33:53 +00:00
Alessio Gravili
09246a45e0 feat: add payload.jobs.runByID (#9875) 2024-12-10 23:37:06 +00:00
Jacob Fletcher
da6bc55b19 fix(ui): ensures admin.disableListFilter is disabled despite url search params (#9874)
Continuation of #9846 and partial fix for #9774. When setting
`admin.disableListFilter` retroactively, it remains active within the
list filter controls. Same for when the URL search query contains one of
these fields, except this will actually display the _wrong_ field,
falling back to the _first_ field from the config. The fix is to
properly disable the condition for this field if it's an active filter,
while still preventing it from ever rendering as an option within the
field selector itself.
2024-12-10 17:37:52 -05:00
Jacob Fletcher
f7172b5b2c fix(ui): refreshes column state during hmr and respects admin.disableListColumn despite preferences (#9846)
Partial fix for #9774. When `admin.disableListColumn` is set
retroactively, it continues to appear in column state, but shouldn't.
This was because the table column context was not refreshing after HMR
runs, and would instead hold onto these stale columns until the page
itself refreshes. Similarly, this was also a problem when the user had
saved any of these columns to their list preferences, where those prefs
would take precedence despite these properties being set on the
underlying fields. The fix is to filter these columns from all requests
that send them, and ensure local component state properly refreshes
itself.
2024-12-10 15:11:44 -05:00
Patrik
563694d930 fix(ui): prevents unwanted data overrides when bulk editing (#9842)
### What?

It became possible for fields to reset to a defined `defaultValue` when
bulk editing from the `edit-many` drawer.

### Why?

The form-state of all fields were being considered during a bulk edit -
this also meant using their initial states - this meant any fields with
default values or nested fields (`arrays`) would be overwritten with
their initial states

I.e. empty values or default values.

### How?

Now - we only send through the form data of the fields specifically
being edited in the edit-many drawer and ignore all other fields.

Leaving all other fields stay their current values.

Fixes #9590

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-12-10 11:39:15 -05:00
Jarrod Flesch
fee17448e7 chore: better default for useAsTitle with custom auth collections (#9841)
### What?
Custom auth collections default `useAsTitle` to `id`.

### Why?
It is more expected for auth collections to search on email or username.

### How?
Defaults useAsTitle to `username` if loginWithUsername is used, else
`email`. Can still be overridden by setting a custom `admin.useAsTitle`
property.
2024-12-10 08:42:23 -05:00
Jayce Pulsipher
1e5364ff34 fix: upgrade pg snapshot during v3 upgrade if needed (#9837)
### What?

Upgrade PG snapshot if needed during v3 migration

### Why?

I'm unable to run the v3 migration as my PG snapshot is on version 5
instead the required 7

### How?

Copy code from typical migrations to upgrade PG snapshot as needed:
https://github.com/payloadcms/payload/blob/main/packages/drizzle/src/postgres/createMigration.ts#L64

Co-authored-by: Jayce Pulsipher <jpulsipher@nav.com>
2024-12-09 15:46:54 -05:00
Jacob Fletcher
e095222a9c fix(next): does not format top-level domains within admin.preview or livePreview.url functions (#9831)
Fixes #9830. Continuation of #9755 and #9746. Instead of automatically
appending TLDs to the `admin.preview` and the `livePreview.url` URLs, we
should instead ensure that `req` is passed through these functions, so
that you can have full control over the format of this URL without
Payload imposing any of its own formatting.
2024-12-09 11:54:20 -05:00
Elliot DeNolf
e746d7afd8 test: properly mock nodemailer verify in unit test (#9832)
If nodemailer was down, this unit test would fail. Verify function
should now be properly mock and not make a network call.
2024-12-09 14:58:18 +00:00
Riley Pearce
d791db24bd fix(richtext-lexical): lexical-html export (#9793)
### What?

`@lexical-html` is missing from the `lexical-proxy` exports.

### Why?

To allow `@lexical-html` functionality to be used without needing to
install the package separately.

### How?

Adds `@lexical-html` to the `lexical-proxy` exports.

Fixes #9792
2024-12-09 08:51:38 -03:00
Alessio Gravili
60ceeb0dc1 fix(richtext-*): field errors and descriptions were not displayed (#9824) 2024-12-08 23:46:26 +00:00
Alessio Gravili
dc741bb140 chore(deps): upgrade dataloader dependency from 2.2.2 to 2.2.3 (#9823) 2024-12-08 21:03:59 +00:00
Alessio Gravili
7599ede41d refactor(richtext-lexical): export JSXConverter type (#9815) 2024-12-08 07:33:57 +00:00
Elliot DeNolf
ff62017cf2 chore(release): v3.5.0 [skip ci] 2024-12-06 14:58:41 -05:00
Alessio Gravili
8f3f44922e feat: upgrade to React 19 stable and Next.js 15.0.4 (#9801)
No need for those ugly @types/react overrides anymore!
2024-12-06 14:53:36 -05:00
Patrik
1aa23d3ea3 chore(cpa): updates .env.example env vars along side .env vars based on selected DB (#9757)
### What?

Previously, the create-payload-app install would properly update the env
vars in the new created `.env` file but kept outdated env vars in the
`.env.example` file.

I.e

If selecting a `postgres` DB for the blank or website template:

`.env` --> `DATABASE_URI` -->
`postgres://postgres:<password>@127.0.0.1:5432/test-cpa`

`.env.example` --> `DATABASE_URI` -->
`mongodb://127.0.0.1/payload-template-blank-3-0`

### Now

`.env` --> `DATABASE_URI` -->
`postgres://postgres:<password>@127.0.0.1:5432/test-cpa`

`.env.example` --> `DATABASE_URI` -->
`postgres://postgres:<password>@127.0.0.1:5432/test-cpa`
2024-12-06 14:52:11 -05:00