Commit Graph

13624 Commits

Author SHA1 Message Date
Germán Jabloñski
f2b54b5b43 fix(richtext-lexical, ui): opening relationship field with appearance: "drawer" inside rich text inline block (#12529)
To reproduce this bug, insert the following feature into the richtext
editor:


```ts
BlocksFeature({
  inlineBlocks: [
    {
      slug: 'inline-media',
      fields: [
        {
          name: 'media',
          type: 'relationship',
          relationTo: ['media'],
          admin: {
            appearance: 'drawer',
          },
        },
      ],
    },
  ],
}),
```

Then try opening the relationship field drawer. The inline block drawer
will close.

Note: Interestingly, at least in Chrome, this only happens with DevTools
closed. It worked fine with DevTools open. It probably has to do with
capturing events like focus.
The current solution is a 50ms delay. I couldn't test it with CPU
throttle because it disappears when I close the devtools. If you
encounter this bug, please open an issue so we can increase the delay
or, better yet, find a more elegant solution.
2025-05-28 11:31:28 -03:00
Jarrod Flesch
4a41369a00 chore: updates bug template (#12587) 2025-05-28 10:18:25 -04:00
Sean Zubrickas
7fa879c3a0 docs: typos and links (#12484)
- update SantizeCollection to SanitizedCollection in TypeScript section

- fix new issue link in Multi-Tenant plugin section

- correct You can disabled to disable in Core Features

- fix duplicate section links for MongoDB and Postgres in Migrations
section
2025-05-28 06:47:51 -07:00
Jarrod Flesch
166dafe05e fix(ui): filtering on hasMany fields (#12579) 2025-05-28 09:45:22 -04:00
Jessica Rynkar
68ba24d91f fix(templates): update template/plugin and fix import map issue (#12305)
### What?
1. Adds logic to automatically update the `importMap.js` file with the
project name provided by the user.
2. Adds an updated version of the `README.md` file that we had when this
template existed outside of the monorepo
([here](https://github.com/payloadcms/plugin-template/blob/main/README.md))
to provide clear instructions of required steps.

### Why?
1. The plugin template when installed via `npx create-payload-app` asks
the user for a project name, however the exports from `importMap.js` do
not get updated to the provided name. This throws errors when running
the project and prevents it from building.

2. The `/dev` folder requires the `.env.example` to be copied and
renamed to `.env` - the project will not run until this is done. The
template lacks instructions that this is a required step.

### How?
1. Updates
`packages/create-payload-app/src/lib/configure-plugin-project.ts` to
read the `importMap.js` file and replace the placeholder plugin name
with the name provided by the users. Adds a test to
`packages/create-payload-app/src/lib/create-project.spec.ts` to verify
that this file gets updated correctly.
2. Adds instructions on using this template to the `README.md` file,
ensuring key steps (like adding the `.env` file) are clearly stated.

Additional housekeeping updates:
- Removed Jest and replaced it with Vitest for testing
- Updated the base test approach to use Vitest instead of Jest
- Removed `NextRESTClient` in favor of directly creating Request objects
- Abstracted `getCustomEndpointHandler` function
- Added ensureIndexes: true to the mongooseAdapter configuration
- Removed the custom server from the dev folder
- Updated the pnpm dev script to "dev": "next dev dev --turbo"
- Removed `admin.autoLogin`

Fixes #12198
2025-05-27 21:33:23 +00:00
Patrik
20f7017758 feat: show nested fields in named tabs as separate columns in the list view (#12530)
### What

Continuation of #7355 by extending the functionality to named tabs.

Updates `flattenFields` to hoist nested fields inside named tabs to the
top-level field array when `moveSubFieldsToTop` is enabled.

Also fixes an issue where group fields with custom cells were being
flattened out.

Now, group fields with a custom cell components remain available as
top-level columns.

Fixes #12563
2025-05-27 14:15:47 -07:00
Jacob Fletcher
0204f0dcbc feat: filter query preset constraints (#12485)
You can now specify exactly who can change the constraints within a
query preset.

For example, you want to ensure that only "admins" are allowed to set a
preset to "everyone".

To do this, you can use the new `queryPresets.filterConstraints`
property. When a user lacks the permission to change a constraint, the
option will either be hidden from them or disabled if it is already set.

```ts
import { buildConfig } from 'payload'

const config = buildConfig({
  // ...
  queryPresets: {
    // ...
    filterConstraints: ({ req, options }) =>
      !req.user?.roles?.includes('admin')
        ? options.filter(
            (option) =>
              (typeof option === 'string' ? option : option.value) !==
              'everyone',
          )
        : options,
  },
})
```

The `filterConstraints` functions takes the same arguments as
`reduceOptions` property on select fields introduced in #12487.
2025-05-27 16:55:37 -04:00
Said Akhrarov
032375b016 fix(ui): prevent textarea description overlapping fields and not honoring rows attribute (#12406) 2025-05-27 16:27:00 -04:00
Jarrod Flesch
8448e5b6b6 fix(ui): cloudfront removing X-HTTP-Method-Override header (#12571) 2025-05-27 15:48:51 -04:00
Jacob Fletcher
d6f6b05d77 fix(examples): update live-preview example to ESM (#12570)
Partial fix for #12551.

The Live Preview example was unable to boot because it was running
CommonJS instead of ESM.
2025-05-27 14:30:39 -04:00
Jessica Rynkar
feb7e082af chore(ui): finish adding folders e2e tests (#12524) 2025-05-27 13:00:56 -04:00
Jarrod Flesch
dfa0974894 fix(ui): live-preview-tab should show beforeDocumentControls (#12568) 2025-05-27 11:30:02 -04:00
Jarrod Flesch
f2b6c4a707 fix(db-mongodb): exists query on checkbox fields (#12567) 2025-05-27 11:19:09 -04:00
Sasha
b61ef13481 fix(storage-vercel-blob): client uploads with a prefix (#12559)
Fixes https://github.com/payloadcms/payload/issues/12544
2025-05-26 22:42:25 +03:00
Paul
1731dd7c36 fix: improve translation script prompt and fix some incorrectly used terms in spanish and dutch (#12548)
The translations would sometimes be using the wrong meanings in other
languages, for example Locale becoming "location" or "region" depending
on the phrase or translation.

Some words were also not being used consistently across the UI which
could cause some confusion if they're interchanged.

I've fixed these instances for locale specifically in dutch and spanish.

I've also updated the prompt with more context around what's being
translated and some examples, over time we should add to the examples so
that translations are better guarded against changing meanings.

---------

Co-authored-by: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com>
2025-05-26 11:07:13 -03:00
Anders Semb Hermansen
bd2571c68f fix(translations): correct Norwegian terms for “locale” and language labels (#12557)
The translation engine previously rendered the English term locale as
“lokalitet” or “steder” in Norwegian, which in practice refers to a
geographic location rather than a language variant. This has been
changed throughout. I have also made some other small improvements to
the Norwegian translations.
2025-05-26 13:59:31 +00:00
Anyu Jiang
e2f7889d72 docs: fix typos, duplicated words, wrong property names etc. (#12480)
### What?
fix typos in doc
### Why?
because they are typos
### How?
checked manually with the help of AI
2025-05-25 10:58:26 -07:00
Jarrod Flesch
c010d51543 fix: browseByFolder route should be optional (#12527) 2025-05-23 15:45:03 -04:00
Jarrod Flesch
293cdc1b50 fix(ui): safari css rendering issues with table and folder cards (#12531) 2025-05-23 15:43:39 -04:00
Dan Ribbens
06fbc0705c chore: fixes monorepo dev plugin-import-export (#12528) 2025-05-23 18:42:50 +00:00
Jarrod Flesch
5a758810aa fix(ui): only and files/folders to the grid/list if they were added to the current folder (#12525) 2025-05-23 14:04:57 -04:00
Jarrod Flesch
64443d83ec fix: thread req into interal folder payload operations (#12523) 2025-05-23 12:19:57 -04:00
Jarrod Flesch
feeee19407 fix(ui): replaces css fn with css calc (#12520) 2025-05-23 11:09:15 -04:00
Jarrod Flesch
e9cda1e121 fix(ui): index based ids without useAsTitle breaks folders (#12519) 2025-05-23 10:37:40 -04:00
Ricardo Tavares
842d1845e1 fix: infinite loop in findUp utility when a result is not found (#12457)
### What?
Fixes an infinite loop that may occur when invoking the findUp() utility
to search for a file by name and no result is found.

### Why?
If triggered, the infinite loop will hang the entire application. For
example, this occurs when trying to boot Payload from a Cloudflare
Worker, as reported in #12327

### How?
By checking whether it has reached the root directory before analysing
the parent folder
2025-05-23 03:27:09 -07:00
Said Akhrarov
11a4a20f0f perf: folder views download only images and get best fit from image sizes (#12514) 2025-05-22 20:29:48 -04:00
Jarrod Flesch
bc43982cfc fix(next): folder redirects not working (#12509) 2025-05-22 16:21:58 -04:00
Jarrod Flesch
d83b2bf3fa chore: moves collections folders property to the top level (#12508) 2025-05-22 16:01:33 -04:00
Jacob Fletcher
f75d62c79b feat: select field filter options (#12487)
It is a common pattern to dynamically show and validate a select field's
options based on various criteria such as the current user or underlying
document.

Some examples of this might include:
- Restricting options based on a user's role, e.g. admin-only options
- Displaying different options based on the value of another field, e.g.
a city/state selector
 
While this is already possible to do with a custom `validate` function,
the user can still view and select the forbidden option...unless you
_also_ wired up a custom component.

Now, you can define `filterOptions` on select fields.

This behaves similarly to the existing `filterOptions` property on
relationship and upload fields, except the return value of this function
is simply an array of options, not a query constraint. The result of
this function will determine what is shown to the user and what is
validated on the server.

Here's an example:

```ts
{
  name: 'select',
  type: 'select',
  options: [
    {
      label: 'One',
      value: 'one',
    },
    {
      label: 'Two',
      value: 'two',
    },
    {
      label: 'Three',
      value: 'three',
    },
  ],
  filterOptions: ({ options, data }) =>
    data.disallowOption1
      ? options.filter(
          (option) => (typeof option === 'string' ? options : option.value) !== 'one',
        )
      : options,
}
```
2025-05-22 15:54:12 -04:00
Sasha
45f4c5c22c fix: delete subfolders hook with relational databases (#12507)
* Adds integration tests for folder view hooks
* Fixes deleting subfolders with Postgres / SQLite by changing
`afterDelete` to `beforeDelete`.
2025-05-22 19:44:14 +00:00
Jake Grella
071c61fe49 chore(examples): remove unused imports from custom server example (#12467)
Removed `express` imports that were not being utilized.

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2025-05-22 18:20:47 +00:00
Rémy
cceb793257 chore(examples): fix read permission in auth example (#12403)
The return value of the `adminsAndUser` method was not a proper Query to
limit the read scope of the read access. So users could read all user
data of the system.

Alongside I streamlined the type imports (fixes #12323) and fixed some
typescript typings. And aligned the export of the mentioned to align
with the other access methods.
2025-05-22 17:46:27 +00:00
Sasha
1b1e36e2df fix(db-*): migrate:reset executes in a wrong order (#12445)
fixes https://github.com/payloadcms/payload/issues/12442
2025-05-22 13:30:29 -04:00
Elliot DeNolf
6b6948f92c templates: bump for v3.39.1 (#12504)
🤖 Automated bump of templates for v3.39.1

Triggered by user: @denolfe

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-22 11:51:05 -04:00
Elliot DeNolf
9ef51a7cf3 chore(release): v3.39.1 [skip ci] v3.39.1 2025-05-22 11:37:58 -04:00
Elliot DeNolf
0f7dc38012 fix: update folders export paths (#12501)
Fixes issues with folder exports after generating import map

Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
2025-05-22 11:35:00 -04:00
Dan Ribbens
c720ce3c08 docs: folders beta (#12500) 2025-05-22 11:25:56 -04:00
Elliot DeNolf
3a73a67ef4 templates: include ui package (#12499)
Folder view needed to have `@payloadcms/ui` explicitly installed.
Including this in the templates.
2025-05-22 11:19:49 -04:00
Elliot DeNolf
4c6fde0e89 templates: bump for v3.39.0 (#12498)
🤖 Automated bump of templates for v3.39.0

Triggered by user: @denolfe

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-22 10:32:52 -04:00
Elliot DeNolf
c1c0db3b01 chore(release): v3.39.0 [skip ci] v3.39.0 2025-05-22 10:18:04 -04:00
Jarrod Flesch
00667faf8d feat: folders (#10030) 2025-05-22 10:04:45 -04:00
Paul
898e97ed17 fix(cpa): ensure it always installs the latest version of the templates (#12488)
CPA would previously install an outdated version of the templates based
on the git tag, this is now set to the `main` branch ensuring that the
latest version is always installed.
2025-05-22 09:55:42 -04:00
Jarrod Flesch
8142a00da6 chore: simplifies buildColumnState functions (#12496) 2025-05-22 09:54:50 -04:00
Anders Semb Hermansen
08a3dfbbcb chore(live-preview): load schemaJSON from proper client config in integration tests (#12167)
### What?

The integration tests in live-preview has been using the
`fieldSchemaToJSON` method with wrong params/types.

It's defined as
```
export const fieldSchemaToJSON = (fields: ClientField[], config: ClientConfig): FieldSchemaJSON
```

In the test setup
`fields` was set to `Pages.fields` which was `Field[]`, not the expected
`ClientField[]`
`config` was set to `config` which was `Promise<SanitizedConfig>` not
the expected `ClientConfig`

### Why?

I'm working on some other changes to live-preview where I need the
proper values wired up correctly to properly add integration tests.

The test has worked up until now because Field is very similar to
ClientField. But it should test with the correct type.

### How?

By creating the clientConfig and using the correct types/params when
calling fieldSchemaToJSON in the test setup.

**Note:** Removed test "Collections - Live Preview › merges data", the
test worked before because **id** field is not part of Field, but part
of ClientField. So test code does not behave like this in real scenario
when real ClientField is used. There are lots of real tests for correct
data, removed this one which seems very simple and not correct.
2025-05-22 07:44:03 -03:00
Germán Jabloñski
fc83823e5d feat(richtext-lexical): add TextStateFeature (allows applying styles such as color and background color to text) (#9667)
Originally this PR was going to introduce a `TextColorFeature`, but it
ended up becoming a more general-purpose `TextStateFeature`.

## Example of use:
```ts
import { defaultColors, TextStateFeature } from '@payloadcms/richtext-lexical'

TextStateFeature({
  // prettier-ignore
  state: {
    color: {
      ...defaultColors,
      // fancy gradients!
      galaxy: { label: 'Galaxy', css: { background: 'linear-gradient(to right, #0000ff, #ff0000)', color: 'white' } },
      sunset: { label: 'Sunset', css: { background: 'linear-gradient(to top, #ff5f6d, #6a3093)' } },
    },
    // You can have both colored and underlined text at the same time. 
    // If you don't want that, you should group them within the same key.
    // (just like I did with defaultColors and my fancy gradients)
    underline: {
      'solid': { label: 'Solid', css: { 'text-decoration': 'underline', 'text-underline-offset': '4px' } },
       // You'll probably want to use the CSS light-dark() utility.
      'yellow-dashed': { label: 'Yellow Dashed', css: { 'text-decoration': 'underline dashed', 'text-decoration-color': 'light-dark(#EAB308,yellow)', 'text-underline-offset': '4px' } },
    },
  },
}),

```

Which will result in the following:


![image](https://github.com/user-attachments/assets/ed29b30b-8efd-4265-a1b9-125c97ac5fce)


## Challenges & Considerations
Adding colors or styles in general to the Lexical editor is not as
simple as it seems.

1. **Extending TextNode isn't ideal**
- While possible, it's verbose, error-prone, and not composable. If
multiple features extend the same node, conflicts arise.
- That’s why we collaborated with the Lexical team to introduce [the new
State API](https://lexical.dev/docs/concepts/node-replacement)
([PR](https://github.com/facebook/lexical/pull/7117)).
2. **Issues with patchStyles**
- Some community plugins use `patchStyles`, but storing CSS in the
editor’s JSON has drawbacks:
- Style adaptability: Users may want different styles per scenario
(dark/light mode, mobile/web, etc.).
- Migration challenges: Hardcoded colors (e.g., #FF0000) make updates
difficult. Using tokens (e.g., "red") allows flexibility.
      - Larger JSON footprint increases DB size.
3. **Managing overlapping styles**
- Some users may want both text and background colors on the same node,
while others may prefer mutual exclusivity.
    - This approach allows either:
        - Using a single "color" state (e.g., "bg-red" + "text-red").
- Defining separate "bg-color" and "text-color" states for independent
styling.
4. **Good light and dark modes by default**
- Many major editors (Google Docs, OneNote, Word) treat dark mode as an
afterthought, leading to poor UX.
- We provide a well-balanced default palette that looks great in both
themes, serving as a strong foundation for customization.
5. **Feature name. Why TextState?**
- Other names considered were `TextFormatFeature` and
`TextStylesFeature`. The term `format` in Lexical and Payload is already
used to refer to something else (italic, bold, etc.). The term `style`
could be misleading since it is never attached to the editorState.
    - State seems appropriate because:
      - Lexical's new state API is used under the hood.
- Perhaps in the future we'll want to make state features for other
nodes, such as `ElementStateFeature` or `RootStateFeature`.

Note: There's a bug in Lexical's `forEachSelectedTextNode`. When the
selection includes a textNode partially on the left, all state for that
node is removed instead of splitting it along the selection edge.
2025-05-21 23:58:17 +00:00
Anders Semb Hermansen
2a41d3fbb1 feat: show fields inside groups as separate columns in the list view (#7355)
## Description

Group fields are shown as one column, this PR changes this so that the
individual field is now shown separately.

Before change:
<img width="1227" alt="before change"
src="https://github.com/user-attachments/assets/dfae58fd-8ad2-4329-84fd-ed1d4eb20854">

After change:
<img width="1229" alt="after change"
src="https://github.com/user-attachments/assets/d4fd78bb-c474-436e-a0f5-cac4638b91a4">

- [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
- [ ] I have made corresponding changes to the documentation

---------

Co-authored-by: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com>
2025-05-21 16:25:34 -04:00
Patrik
c772a3207c fix(ui): set gap to 0 in sort column buttons to remove unneeded spacing (#12481)
### What

This PR adjusts the `gap` between buttons in the `SortColumn` component.
The previous spacing (`calc(var(--base) / 4)`) caused too much visual
separation between the sort buttons. It has been replaced with `gap: 0`
to tighten their alignment.

#### Before:
![Screenshot 2025-05-21 at 1 33
17 PM](https://github.com/user-attachments/assets/a5f759fc-647a-46e3-8dac-e3e100fc7b98)

#### After:
![Screenshot 2025-05-21 at 1 34
04 PM](https://github.com/user-attachments/assets/29572620-bd62-4e3e-80b7-d32ed4c81911)
2025-05-21 11:33:14 -07:00
Germán Jabloñski
c701dd41a9 docs: update rich text to HTML conversion documentation (#12465)
Fixes #8168, #8277

The fact that `lexicalHTMLField` doesn't work with live preview was
already clarified at the beginning of the page. I mentioned it again in
the dedicated section because it seems there was still confusion.

Also, I reordered and hierarchized the headings correctly. The
introduction said there were two ways to convert to HTML, but there were
four headings with the same level. I also made the headings a little
shorter to make the table of contents easier to parse.
2025-05-21 15:24:31 -03:00
Paul
4dfb2d24bb feat(plugin-form-builder): add new date field (#12416)
Adds a new date field to take submission values for.

It can help form serialisers render the right input for this kind of
field as the submissions themselves don't do any validation right now.

Disabled by default as to not cause any conflicts with existing projects
potentially inserting their own date blocks.

Can be enabled like this

```ts
formBuilderPlugin({
   fields: {
     date: true
   }
})
```
2025-05-21 17:34:21 +00:00
Sasha
230128b92e fix(db-mongodb): remove limit from nested querying (#12464)
Fixes https://github.com/payloadcms/payload/issues/12456
2025-05-21 20:22:28 +03:00