Commit Graph

1616 Commits

Author SHA1 Message Date
Said Akhrarov
1d6ffcb80e feat(ui): adds support for copy pasting complex fields (#11513)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR introduces support for copy + pasting complex fields such as
Arrays and Blocks. These changes introduce a new `ClipboardAction`
component that houses logic for copy + pasting to and from the clipboard
to supported fields. I've scoped this PR to include only Blocks &
Arrays, however the structure of the components introduced lend
themselves to be easily extended to other field types. I've limited the
scope because there may be design & functional blockers that make it
unclear how to add actions to particular fields.

Supported fields:
- Arrays
([Demo](https://github.com/user-attachments/assets/523916f6-77d0-43e2-9a11-a6a9d8c1b71c))
- Array Rows
([Demo](https://github.com/user-attachments/assets/0cd01a1f-3e5e-4fea-ac83-8c0bba8d1aac))
- Blocks
([Demo](https://github.com/user-attachments/assets/4c55ac2b-55f4-4793-9b53-309b2e090dd9))
- Block Rows
([Demo](https://github.com/user-attachments/assets/1b4d2bea-981a-485b-a6c4-c59a77a50567))

Fields that may be supported in the future with minimal effort by
adopting the changes introduced here:
- Tabs
- Groups
- Collapsible
- Relationships

This PR also encompasses e2e tests that check both field and row-level
copy/pasting.

### Why?
To make it simpler and faster to copy complex fields over between
documents and rows within those docs.

### How?
Introduces a new `ClipboardAction` component with helper utilities to
aid in copy/pasting and validating field data.

Addresses #2977 & #10703

Notes:
- There seems to be an issue with Blocks & Arrays that contain RichText
fields where the RichText field dissappears from the dom upon replacing
form state. These fields are resurfaced after either saving the data or
dragging/dropping the row containing them.
- Copying a Row and then pasting it at the field-level will overwrite
the field to include only that one row. This is intended however can be
changed if requested.
- Clipboard permissions are required to use this feature. [See Clipboard
API caniuse](https://caniuse.com/async-clipboard).

#### TODO
- [x] ~~I forgot BlockReferences~~
- [x] ~~Fix tests failing due to new buttons causing locator conflicts~~
- [x] ~~Ensure deeply nested structures work~~
- [x] ~~Add missing translations~~
- [x] ~~Implement local storage instead of clipboard api~~
- [x] ~~Improve tests~~

---------

Co-authored-by: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com>
2025-07-09 13:59:22 +00:00
Jacob Fletcher
0b88466de6 fix(next): prevent live preview url functions from firing unnecessarily (#13088)
Ensures Live Preview url functions aren't fired during create or on
collections that do not have Live Preview enabled.

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210743577153852
2025-07-08 13:02:54 -04:00
Dani Calero
4c25357831 fix(ui): improve alignment of clear and dropdown indicator buttons in select based fields (#12995) 2025-07-08 07:06:46 -04:00
Jessica Rynkar
8a5cb27463 fix(ui): prevent error crashing UI when relationship assigned as useAsTitle (#12981)
### What?

- Updates the `RenderTitle` component to check that the `title` is a
string before returning it.
- Adds note to docs that **Relationship** and **Join** fields cannot be
assigned to `useAsTitle`, a **virtual** field should be used instead.

### Why?
When autosave is enabled and the `useAsTitle` points to a relationship
field, the autosave process returns an `object` for the title, this gets
passed to the `RenderTitle` component and throws an error which crashes
the UI.

### How?
Safely checks that `title` is a string before rendering it in
`RenderTitle` and updates docs to clarify that Relationship/Joins are
not compatible with `useAsTitle`.

Fixes #12960
2025-07-08 10:55:04 +01:00
Elliot DeNolf
14612b4db8 chore(release): v3.46.0 [skip ci] 2025-07-07 16:10:10 -04:00
Alessio Gravili
af9837de44 ci: analyze bundle size (#13071)
This adds a new `analyze` step to our CI that analyzes the bundle size
for our `payload`, `@payloadcms/ui`, `@payloadcms/next` and
`@payloadcms/richtext-lexical` packages.

It does so using a new `build:bundle-for-analysis` script that packages
can add if the normal build step does not output an esbuild-bundled
version suitable for analyzing. For example, `ui` already runs esbuild,
but we run it again using `build:bundle-for-analysis` because we do not
want to split the bundle.

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210692087147570
2025-07-07 20:00:02 +00:00
Germán Jabloñski
2650eb7d44 fix(ui): increase timeout for opening list drawer in RelationshipInput (#13031)
As stated in #12529, the setTimeout was defined through trial and error
as it wasn't possible to reproduce the bug with the devtools open and
therefore with the CPU throttled. One user reported still experiencing
the bug.

I'm increasing the timeout to 100ms, which seems acceptable enough to
keep postponing a better fix, considering the bug isn't that critical.

If we find it keeps happening, we'll probably need to investigate the
root cause.
2025-07-07 09:30:09 -04:00
Jacob Fletcher
f49eeb1a63 fix(next): respect collection-level live preview config (#13036)
Fixes #13035.

We broke collection-level live preview configs in #12860.
2025-07-03 21:47:16 +00:00
Jarrod Flesch
1d9ad6f2f1 fix(ui): change password button is hidden when user has full field access (#12988) 2025-07-03 13:59:22 -04:00
Elliot DeNolf
1ccd7ef074 chore(release): v3.45.0 [skip ci] 2025-07-03 09:23:23 -04:00
Germán Jabloñski
babcd599da fix(ui): save nested richtext inside inlineBlock (#12773)
Removing the `setTimeout` not only doesn't break any tests, but it also
fixes the linked issue.

The long comment above the if statement was added in
https://github.com/payloadcms/payload/pull/5460 and explains why the if
statement is necessary GIVEN the existence of the `setTimeout`, but the
`setTimeout` was introduced [earlier because the button apparently
didn't work](https://github.com/payloadcms/payload/issues/1414).

It seems to work now without the `setTimeout`, because otherwise the
tests wouldn't even pass. I also tested it manually, and it works fine.


Fixes #12687
2025-07-02 19:43:48 +00:00
Jacob Fletcher
b40c581a27 fix(ui): autosave infinite loop within document drawer (#13007)
Required for #13005.

Opening an autosave-enabled document within a drawer triggers an
infinite loop when the root document is also autosave-enabled.

This was for two reasons:

1. Autosave would run and change the `updatedAt` timestamp. This would
trigger another run of autosave, and so on. The timestamp is now removed
before comparison to ensure that sequential autosave runs are skipped.

2. The `dequal()` call was not being given the `.current` property off
the ref object. This meant that is was never evaluate to `true` and
therefore never skip unnecessary autosaves to begin with.

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210697235723932
2025-07-02 15:11:38 -04:00
Jarrod Flesch
9ba740e472 fix(ui): field bulk upload showing stale data (#13006) 2025-07-02 10:11:51 -04:00
Jacob Fletcher
c80b6e92c4 fix(ui): prevent document drawer from remounting on save (#13005)
Supersedes #12992. Partially closes #12975.

Right now autosave-enabled documents opened within a drawer will
unnecessarily remount on every autosave interval, causing loss of input
focus, etc. This makes it nearly impossible to edit these documents,
especially if the interval is very short.

But the same is true for non-autosave documents when "manually" saving,
e.g. pressing the "save draft" or "publish changes" buttons. This has
gone largely unnoticed, however, as the user has already lost focus of
the form to interact with these controls, and they somewhat expect this
behavior or at least accept it.

Now, the form remains mounted across autosave events and the user's
cursor never loses focus. Much better.

Before:


https://github.com/user-attachments/assets/a159cdc0-21e8-45f6-a14d-6256e53bc3df

After:


https://github.com/user-attachments/assets/cd697439-1cd3-4033-8330-a5642f7810e8

Related: #12842

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210689077645986
2025-07-02 09:07:08 -04:00
Jarrod Flesch
a9ad7c771e fix(ui): bulk upload redirecting to relationship documents when added (#13001)
Fixes https://github.com/payloadcms/payload/issues/12786
2025-07-01 15:23:11 -04:00
Patrik
7a40a9fc06 fix(ui): skip disabled fields when adding OR filter conditions in list view (#13004)
### What?

Fixes a bug where adding an additional OR filter condition in the list
view selects a field with `admin.disableListFilter: true`, causing all
filter fields to appear disabled.

### Why?

When the first field in a collection has `disableListFilter` set to
`true`, adding a second OR condition defaults to using that field. This
leads to a broken filter UI where no valid fields are selectable.

### How?

Replaces the hardcoded usage of `reducedFields[0]` with a call to
`reducedFields.find(...) `that skips fields with `disableListFilter:
true`, consistent with the logic already used when adding the first
filter condition.

Fixes #12993
2025-07-01 11:35:48 -07:00
Patrik
b1ae749311 fix(ui): render preview sizes button when adjustments are disabled but image sizes are defined (#12999)
### What?

The "Preview Sizes" button in the file upload UI was not showing up if:
- `crop` and `focalPoint` were both `false`
- No `customUploadActions` were provided
- But image sizes were configured

### Why?

This happened because `UploadActions` wasn’t rendered at all unless
adjustments or custom actions were present.

### How?

Update the conditional in `StaticFileDetails` to also render
`UploadActions` when:
- `hasImageSizes` is `true` and the document has a `filename`

Fixes #12832
2025-07-01 07:44:48 -07:00
Jacob Fletcher
3f30a2e300 fix(ui): block rows unexpectedly collapse and array rows not collapsed on init (#12987) 2025-06-30 21:12:26 -04:00
Alessio Gravili
4458f74cef ci: template errors not being caught due. fix: error due to updated generated-types User type (#12973)
This PR consists of two separate changes. One change cannot pass CI
without the other, so both are included in this single PR.


## CI - ensure types are generated

Our website template is currently failing to build due to a type error.
This error was introduced by a change in our generated types.

Our CI did not catch this issue because it wasn't generating types /
import map before attempting to build the templates. This PR updates the
CI to generate types first.

It also updates some CI step names for improved clarity.

## Fix: type error

![Screenshot 2025-06-29 at 12 53
49@2x](https://github.com/user-attachments/assets/962f1513-bc6c-4e12-9b74-9b891c49900b)


This fixes the type error by ensuring we consistently use the _same_
generated `TypedUser` object within payload, instead of `BaseUser`.
Previously, we sometimes used the generated-types user and sometimes the
base user, which was causing type conflicts depending on what the
generated user type was.

It also deprecates the `User` type (which was essentially just
`BaseUser`), as consumers should use `TypedUser` instead. `TypedUser`
will automatically fall back to `BaseUser` if no generated types exists,
but will accept passing it a generated-types User.

Without this change, additional properties added to the user via
generated-types may cause the user object to not be accepted by
functions that only accept a `User` instead of a `TypedUser`, which is
what failed here.

## Templates: re-generate templates to update generated types

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210668927737258
2025-06-29 14:27:50 -07:00
Jacob Fletcher
f2213e5c5c feat: mount live preview to document root (#12860)
Mounts live preview to `../:id` instead `../:id/preview`.

This is a huge win for both UX and a maintainability standpoint.

Here are just a few of those wins:

1. If you edit a document, _then_ decide you want to preview those
changes, you are currently presented with the `LeaveWithoutSaving` modal
and are forced to either save your edits or clear them. This is because
you are being navigated to an entirely new page with it's own form
context. Instead, you should be able to freely navigate back and forth
between the two.
2. If you are an editor who most often uses Live Preview, or you are
editing a collection that typically requires it, you likely want it to
automatically enter live preview mode when you open a document.
Currently, the user has to navigate to the document _first_, then use
the live preview tab. Instead, you should be able to set a preference
and avoid this extra step.
3. Since the inception of Live Preview, we've been maintaining largely
the same code across the default edit view and the live preview view,
which often became out of sync and inconsistent—but they're essentially
doing the same thing. While we could abstract a lot of this out, it is
no longer necessary if the two views are combined into one.

This change does also include some small modifications to UI. The "Live
Preview" tab no longer exists, and instead has been replaced with a
button placed next to the document controls (subject to change).

Before:


https://github.com/user-attachments/assets/48518b02-87ba-4750-ba7b-b21b5c75240a

After:


https://github.com/user-attachments/assets/a8ec8657-a6d6-4ee1-b9a7-3c1173bcfa96
2025-06-27 11:58:00 -04:00
Jessica Rynkar
6f6d305f9d fix(ui): prevent error if rows is undefined in mergeServerFormState (#12962)
### What? 
Adds optional chaining when accessing `rows` in `mergeServerFormState`
to prevent error crashing the UI.

### Why? 
When an array field is populated in a `beforeChange` hook and was
previously empty, it crashes `mergeServerFormState.ts` on this line
because no `rows` exist:

```ts 
const indexInCurrentState = currentState[path].rows.findIndex
``` 

The line after this checks `if (indexInCurrentState > -1)` so returning
undefined here will not affect the subsequent code.

### How? 
Added optional chaining to the access of `rows`, which prevents the
error being thrown.

Fixes #12944
2025-06-27 15:57:48 +00:00
Elliot DeNolf
c66e5ca823 chore(release): v3.44.0 [skip ci] 2025-06-27 09:23:04 -04:00
Jacob Fletcher
c8b72141e4 feat: collection-level preferences (#12909)
Needed for #12860.

The new live preview pattern requires collection-level preferences, a
pattern that does not yet exist.

Instead of creating a new record for these types of preferences, we can
simply reuse `<collectionSlug>-list` under a more general key:
`collection-<slug>`. This way other relevant properties can be attached
in the future that might not specifically apply to the list view.

This will also match the conventions already estalished by
document-level preferences in `collection-<slug>-<id>` and
`global-<slug>`.

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210628212784050
2025-06-27 09:08:47 -04:00
Jesper We
c3c1614fa6 fix(ui): usePreventLeave should not show alert for exceptions (#12722)
When using 3rd party custom components in an edit form there exists a
possibility that a non-navigational click event will propagate through
to payload.

In this case the `findClosestAnchor` function in `usePreventLeave` may
find an anchor without href, resulting in the `newUrlObj = new
URL(newUrl)` in `isAnchorOfCurrentUrl` throwing the exception:

> TypeError: URL constructor:  is not a valid URL.

As a result a native alert is shown to the user, with no real
explanation as to what is going on. This is not a good experience.

I suggest moving it to a console log which is less "in your face" for
users who do not know what to do about it anyway.

I discovered this while using a data grid component with a context menu.
Clicking on menu items (which are `<a>` tags without href in this
component) triggers the error.

(Another on-liner fix would ofc be to not attempt to create an URL
object if there is no href `if (anchor?.href) {`, but I opted for this
version since using `alert()` in production code is not a preferred
practice anyway)

<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
2025-06-27 07:00:04 -04:00
Sam Wheeler
0e9865c564 fix(ui): vertically align table headers to the middle (#12699)
This fixes a small ui bug where the items in the table header were not
vertically aligned when they don't contain the SortColumn component. The
SortColumn component handles vertical alignment with a nested flexbox.
The PR adds vertical-align: middle directly to the th element so that
the text in the header is vertically aligned even when there isn't a
nested flexbox

Before:
<img width="719" alt="Screenshot 2025-06-05 at 10 24 19 AM"
src="https://github.com/user-attachments/assets/3962517e-3b22-452a-af04-8397549c4ed9"
/>

After:
<img width="719" alt="Screenshot 2025-06-05 at 10 30 39 AM"
src="https://github.com/user-attachments/assets/0c5a0847-8ee2-4439-981e-f3538908e920"
/>
2025-06-27 06:43:41 -04:00
Said Akhrarov
a1822d21d0 fix(ui): properly render create new button in polymorphic joins (#12930)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes an issue where the bottom "Create new ..." button would
cause a runtime error due to not accounting for a polymorphic join
setup.

### Why?
To prevent a runtime error and allow users the ability to add new
documents to the join as expected even in a polymorphic setup.

### How?
Creation of a new `AddNewButton` which handles all of the add new button
instances in the `RelationshipTable` component.

Addresses
https://github.com/payloadcms/payload/issues/12913#issuecomment-3001475438

Before:


[join-polymorphic-runtime-error--Payload.webm](https://github.com/user-attachments/assets/fad3a1ba-c51c-4731-84cc-c27adbaac1d9)


After:

[polymorphic-after-Editing---Multiple-Collections-Parent---Payload
(1).webm](https://github.com/user-attachments/assets/e3baf902-1b2b-4f19-8b6d-838edd6fef80)
2025-06-27 05:47:36 -04:00
Dani Calero 🚀
4b9566f8b8 fix(ui): render DateTime label as <label> instead of <span> (#12949)
## What / Why
Date & Time fields were rendering their field label as a `<span>` while
every other field type uses a proper `<label>` with a matching
`htmlFor`.

Because the element was a span it broke styles and made 'field-label'
have different styles from the rest of 'field-label's.

**Root cause:** DateTimeField failed to pass its `path` (or an explicit
`htmlFor`) to `FieldLabel`. When `FieldLabel` receives no `htmlFor`, it
intentionally downgrades to a `<span>`.

## Screenshots

### Before

![image](https://github.com/user-attachments/assets/edecfce7-0326-4f3e-af76-d7b37158343a)
*DateTime label rendered as `<span>`, causing style inconsistencies*

### After  

![image](https://github.com/user-attachments/assets/d9fb06c2-1ca0-4f8d-803d-15c6c6355d1e)
*DateTime label now rendered as proper `<label>` element*

## Changes introduced
- `packages/ui/src/fields/DateTime/index.tsx`
  - Added `path={path}` prop to `FieldLabel` component

## Behavior after the fix
- Date-time labels are now real `<label>` elements with `for="field-…"`
- Visual alignment now matches every other field type  

## How to test manually
1. Run `pnpm dev fields`
2. Inspect the DateTime field markup – label is now `<label>` 
3. Observe that vertical spacing matches other types of fields
2025-06-27 05:34:28 -04:00
Jarrod Flesch
d62d9b4b8e fix(ui): bulk upload losing state when adding additional files (#12946)
Fixes an issue where adding additional upload files would clear the
state of the originally uploaded files.
2025-06-26 15:23:38 -04:00
Paul
87c7952558 feat(templates): added int and e2e tests to blank and website templates (#12866)
This PR adds int tests with vitest and e2e tests with playwright
directly into our templates.

The following are also updated:
- bumps core turbo to 2.5.4 in monorepo
- blank and website templates moved up to be part of the monorepo
workspace
- this means we now have thes templates filtered out in pnpm commands in
package.json
- they will now by default use workspace packages which we can use for
manual testing and int and e2e tests
  - note that turbo doesnt work with these for dev in monorepo context
- CPA script will fetch latest version and then replace `workspace:*` or
the pinned version in the package.json before installation
- blank template no longer uses _template as a base, this is to simplify
management for workspace
- updated the generate template variations script
2025-06-26 13:55:28 -04:00
Said Akhrarov
9f17db8a7b fix(ui): toggle list selections off on successful bulk action (#12861)
### What?
This PR threads an onSuccess callback to bulk actions which get called
after a successful action. In this case, the callback toggles the list
selections off after a successful edit many, publish many, or unpublish
many.

### Why?
To ensure list selections are toggled off after a successful action.

### How?
By threading a new onSuccess callback through the actions' props.

Fixes #12855

Before


[12855-before.mp4](https://private-user-images.githubusercontent.com/65888/456602476-b327f0ba-c140-46be-8c71-7f6bfa74fd67.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTAyODQxMDEsIm5iZiI6MTc1MDI4MzgwMSwicGF0aCI6Ii82NTg4OC80NTY2MDI0NzYtYjMyN2YwYmEtYzE0MC00NmJlLThjNzEtN2Y2YmZhNzRmZDY3Lm1wND9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA2MTglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwNjE4VDIxNTY0MVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTA0YTE4OTE5MjliZWQxNDM1OTU0ODlhMmY5ZjliNjhlODAyODU5ZmU3ODkzMjI1ODhiOTQyNmY0YzMyMGM0ZmQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.hzTLtuzltcpQUAIHYz7JoZ5x7JT4dPP9f-3c-GDf0Zc)

After


[Draft-Posts---Payload.webm](https://github.com/user-attachments/assets/474fbd9f-c7b3-46f4-ae31-5246cb22b86d)
2025-06-25 17:06:44 -04:00
Jessica Rynkar
c094b0e520 fix(ui): align caret on error tooltip for checkbox field (#12917)
### What?
Aligns the caret on the error message tooltip to the left when using a
checkbox field.

### Why?
All field error message tooltips have a right-aligned caret - when using
a checkbox field, this results in the caret pointing to open space (see
screenshots).

### How?
Left aligns the tooltip caret just for the checkbox field.

**Before:**
![Screenshot 2025-06-24 at 2 45
38 PM](https://github.com/user-attachments/assets/923f6a06-1f24-468d-88d8-12e3f0f0d27f)

**After:**
![Screenshot 2025-06-24 at 2 46
47 PM](https://github.com/user-attachments/assets/a2ebbe6a-2095-4295-9e94-320a1b943a6d)


#### Reported by client
2025-06-25 15:48:49 +00:00
Jessica Rynkar
1845669e68 fix(ui): updates auth fields UI to reflect access control (#12745)
### What?
Reflects any access control restrictions applied to Auth fields in the
UI. I.e. if `email` has `update: () => false` the field should be
displayed as read-only.

### Why?
Currently any access control that is applied to auth fields is
functional but is not matched within the UI.

For example:
- `password` that does not have read access will not return data, but
the field will still be shown when it should be hidden
- `email` that does not have update access, updating the field and
saving the doc will **not** update the data, but it should be displayed
as read-only so nothing can be filled out and the updating restriction
is made clear

### How?
Passes field permissions through to the Auth fields UI and adds docs
with instructions on how to override auth field access.

#### Testing
Use `access-control` test suite and `auth` collection. Tests added to
`access-control` e2e.

Fixes #11569
2025-06-25 14:55:07 +01:00
Jarrod Flesch
0d50799b79 fix(ui): folder server function must reference exports dir (#12898) 2025-06-25 09:52:39 -04:00
Jessica Rynkar
37c945b95b fix(ui): custom row labels on arrays should not be removed on field duplication (#12895)
### What?
This fix prevents custom row labels being removed when duplicating array
items.

### Why?
Currently, when you have an array with custom row labels, if you create
a new array item by duplicating an existing item, the new item will have
no custom row label until you refresh the page.

### How?
During the `duplicate` process, we remove any react components from the
field state. This change intentionally re-adds the `RowLabel` if one
exists.

#### Reported by client
2025-06-25 09:44:00 -04:00
Jacob Fletcher
20bbbcfca2 fix(ui): date format of useAsTitle lost after changing value (#12928)
When a collection's `admin.useAsTitle` property points to a date field,
the date format is lost after making a change to the field's value.

Before:


https://github.com/user-attachments/assets/10e61517-3245-4645-be4c-33017bfc860c

After:


https://github.com/user-attachments/assets/d3d62d2e-364e-48a2-91c1-2ce4b0962fe5

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210632330039313
2025-06-25 09:15:55 -04:00
Anatoly Kopyl
c03e9c1724 fix(ui): properly differentiate between DOM events and raw values in setValue (#12892)
Because of this check, if a JSON with a property `target` was saved it
would become malformed.

For example trying to save a JSON field:

```json
{
  "target": {
    "value": {
      "foo": "bar"
    }
  }
}
```

would result in:

```json
{
  "foo": "bar"
}
```

And trying to save:

```json
{
  "target": "foo"
}
```

would just not save anything:

```json
null
```

I went through all of the field types and did not find a single one that
would rely on this ternary. Seems like it always defaulted to `const val
= e`, except the unexpected case described previously.

Fixes #12873

Added test may be overkill, will remove if so.




---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210628466702813

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2025-06-24 14:30:52 -04:00
Sasha
a5ec55c02a feat: collection-level disableBulkEdit (#12850) 2025-06-19 09:18:29 +00:00
Jessica Rynkar
25e3902242 fix(ui): should select document after creation from relationship field (#12842)
### What?
After creating a new document from a relationship field, this doc should
automatically become the selected document for that relationship field.
This is the expected and current behavior. However, when the
relationship ties to a collection with autosave enabled, this does not
happen.

### Why?
This is expected behavior and should still happen when the relationship
is using an autosave enabled collection.

### How?
1. The logic in `addNewRelation` contained an `if` statement that
checked for `operation === 'create'` - however when autosave is enabled,
the `create` operation runs on the first data update and subsequently it
is a `update` operation.
2. The `onSave` from the document drawer provider was not being run as
part of the autosave workflow.

#### Reported by client.
2025-06-18 11:42:36 +01:00
Patrik
dffdee89d8 fix(ui): support react node content in ConfirmationModal heading and body (#12841)
### What?

This update improves the flexibility of the ConfirmationModal by
allowing the `heading` and `body` prop to accept either a string or a
React node.

If the `heading` or `body` is a string, it will be wrapped in its
respective tags for consistent styling.

If it's already a React element, it will be rendered as-is. This
prevents layout issues when passing JSX content like lists, links, or
formatted elements into the modal heading and body.
2025-06-17 11:19:55 -07:00
Elliot DeNolf
810869f3fa chore(release): v3.43.0 [skip ci] 2025-06-16 16:09:14 -04:00
Alessio Gravili
4e2e4d2aed feat(next): version view overhaul (#12027)
#11769 improved the lexical version view diff component. This PR
improves the rest of the version view.

## What changed

- Column layout when selecting a version:
	- Previously: Selected version on the left, latest version on the left
- Now: Previous version on the left, previous version on the right
(mimics behavior of GitHub)
- Locale selector now displayed in pill selector, rather than
react-select
- Smoother, more reliable locale, modifiedOnly and version selection.
Now uses clean event callbacks rather than useEffects
- React-diff-viewer-continued has been replaced with the html differ we
use in lexical
- Updated Design for all field diffs
- Version columns now have a clearly defined separator line
- Fixed collapsibles showing in version view despite having no modified
fields if modifiedOnly is true
- New, redesigned header
	

## Screenshots

### Before

![CleanShot 2025-04-11 at 20 10
03@2x](https://github.com/user-attachments/assets/a93a500a-3cdd-4cf0-84dd-cf5481aac2b3)

![CleanShot 2025-04-11 at 20 10
28@2x](https://github.com/user-attachments/assets/59bc5885-cbaf-49ea-8d1d-8d145463fd80)

### After

![Screenshot 2025-06-09 at 17 43
49@2x](https://github.com/user-attachments/assets/f6ff0369-76c9-4c1c-9aa7-cbd88806ddc1)

![Screenshot 2025-06-09 at 17 44
50@2x](https://github.com/user-attachments/assets/db93a3db-48d6-4e5d-b080-86a34fff5d22)

![Screenshot 2025-06-09 at 17 45
19@2x](https://github.com/user-attachments/assets/27b6c720-05fe-4957-85af-1305d6b65cfd)

![Screenshot 2025-06-09 at 17 45
34@2x](https://github.com/user-attachments/assets/6d42f458-515a-4611-b27a-f4d6bafbf555)
2025-06-16 07:58:03 -04:00
Kendell Joseph
f2e04222f4 feat: admin upload controls (#11615)
### What?
Adds the ability to add additional components to the file upload
component.

```ts
export const Media: CollectionConfig = {
  slug: 'media',
  upload: {
    admin: {
      components: {
        controls: [
          '/collections/components/Control/index.js#UploadControl',
        ],
      },
    },
  },
  fields: [],
}
```

![image](https://github.com/user-attachments/assets/4706e05b-4e95-4f15-8444-a279c589074e)

### Provider
Use the `useUploadControls` provider to either `setUploadControlFile`
passing a file object, or set the file by url using
`setUploadControlFileUrl`.

```tsx
'use client'
import { Button, useUploadControls } from '@payloadcms/ui'
import React, { useCallback } from 'react'

export const UploadControl = () => {
  const { setUploadControlFile, setUploadControlFileUrl } = useUploadControls()

  const loadFromFile = useCallback(async () => {
    const response = await fetch('https://payloadcms.com/images/universal-truth.jpg')
    const blob = await response.blob()
    const file = new File([blob], 'universal-truth.jpg', { type: 'image/jpeg' })
    setUploadControlFile(file)
  }, [setUploadControlFile])

  const loadFromUrl = useCallback(() => {
    setUploadControlFileUrl('https://payloadcms.com/images/universal-truth.jpg')
  }, [setUploadControlFileUrl])

  return (
    <div>
      <Button id="load-from-file-upload-button" onClick={loadFromFile}>
        Load from File
      </Button>
      <br />
      <Button id="load-from-url-upload-button" onClick={loadFromUrl}>
        Load from URL
      </Button>
    </div>
  )
}
```


### Why?
Add the ability to use a custom component to select a document to
upload.
2025-06-13 12:47:46 -04:00
Sasha
e60db0750a fix(ui): reordering with a join field inside a group (#12803)
Fixes https://github.com/payloadcms/payload/issues/12802
2025-06-13 12:31:07 -04:00
Patrik
77f380544f fix(ui): adjust alignment of list header actions (#12793)
### Before
![Screenshot 2025-06-12 at 11 54
58 AM](https://github.com/user-attachments/assets/82ecfe5a-b483-43da-abb7-1a2b1b548807)

### After
![Screenshot 2025-06-12 at 11 55
12 AM](https://github.com/user-attachments/assets/7b017ec3-f31a-4985-905f-951cface0c5c)


---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210535479281746
2025-06-12 10:03:06 -07:00
Jarrod Flesch
e7b5884ec2 fix(ui): not showing hyphenated field values in table (#12791) 2025-06-12 12:36:24 -04:00
Patrick Roelofs
d0e647a992 fix(plugin-redirects): add missing optional chaining (#12753)
### What?
Updates the redirects plugin types to make collections a required type

### Why?
Currently not including the collections object when importing the plugin
causes an error to occur when going to the page in the UI, also it
cannot generate types. Likely due to it unable to make a reference to a
collection.

### How?
Makes collections required

Fixes #12709

---------

Co-authored-by: Patrick Roelofs <patrick.roelofs@iquality.nl>
Co-authored-by: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com>
2025-06-12 16:29:49 +00:00
Jessica Rynkar
9364d51f4b fix(ui): inconsistent pill sizes across admin panel (#12788)
### What?
Fixes inconsistent `pill` sizes across the Admin Panel.

### How?
Pills without a specified size default to **medium**. In the folders
[PR](https://github.com/payloadcms/payload/pull/10030), additional
padding was to the medium size. As a result, any pills without an
explicit size now appear larger than intended.

This PR fixes that by updating any pills that should be small to
explicitly set `size="small"`.

Fixes #12752
2025-06-12 15:43:00 +01:00
Alessio Gravili
cb3f9bb3e9 perf(ui): do not re-animate drawer on re-render, reduce useEffects (#12743)
Previously, every time the drawer re-rendered a new entry animation may
be triggered. This PR fixes this by setting the open state to
`modalState[slug]?.isOpen` instead of `false`.

Additionally, I was able to simplify this component while maintaining
functionality. Got rid of one `useEffect` and one `useState` call. The
remaining useEffect also runs less often (previously, it ran every time
`modalState` changed => it re-ran if _any_ modal opened or closed, not
just the current one)
2025-06-10 17:14:58 -04:00
Jarrod Flesch
a43d1a685f feat(ui): moves folder rendering from the client to the server (#12710) 2025-06-10 11:56:28 -04:00
Anyu Jiang
9d2817e647 fix: ensure redirect route is correctly formatted for "Copy to locale" (#12560) 2025-06-10 10:10:55 -04:00