Commit Graph

1411 Commits

Author SHA1 Message Date
Jacob Fletcher
927078c4db fix(ui): uses query provider as single source of truth for where builder (#11476)
The "where" builder maintains its own duplicative state for conditions.
This is problematic when an outside force needs to control the
conditions in some way, but the "where" builder will not receive those
updates.

While it is a requirement of the "where" builder to transform the
"where" query into "and" / "or" format for rendering, it does so in a
way that causes it to become out of sync with the query provider. This
is because we first initialize state from context, then for every change
to conditions, report those updates to contexts—but not the other way
around.

To fix this, we need to completely remove state from the "where" builder
and solely rely on the query context as a single source of truth. This
will allow it to receive automatic updates from query provider without
needing to sync both local state and context simultaneously. Now, we
only ever need to send updates to the query provider and let the
top-down rendering cycle propagate those changes everywhere.
2025-03-01 16:20:00 -05:00
Alessio Gravili
6d8aca5ab3 fix(richtext-lexical): ensure nested forms do not use form element (#11462)
Previously, lexical blocks initialized a new `Form` component that rendered as `<form>` in the DOM. This may lead to React errors, as forms nested within forms is not valid HTML.

This PR changes them to render as `<div>` in the DOM instead.
2025-02-28 19:29:07 -07:00
Said Akhrarov
e75d38ca82 fix(ui): remove stale thumbnails in bulkUpload after partial success (#10651) 2025-02-28 22:18:18 +00:00
Jacob Fletcher
6cbda9e231 fix(ui): bulk editing users throws client-side exception (#11461)
When bulk editing an auth-enabled collection such as users, a
client-side exception is thrown. This is because we're trying to access
the `disableBulkEdit` property on `undefined`. This is due to hidden,
auth-specific fields like `salt` and `hash` lacking an admin config.

No test is explicitly needed for this as `"strictNullChecks": true` will
throw an error at compile time, once enabled.
2025-02-28 21:06:40 +00:00
Mike Newberry
9bb89b7b52 feat(ui): close the nav when the user navigates away on small screens (#10932) 2025-02-28 19:31:57 +00:00
Said Akhrarov
bef98c8d6e fix(ui): scope rah-static and progress-bar styles to payload-default layer (#11442) 2025-02-28 14:05:39 -05:00
Patrik
96d1d90e78 fix(ui): use full image url for upload previews instead of thumbnail url (#11435) 2025-02-28 12:47:02 -05:00
Jessica Chowdhury
428c133033 fix(ui): copyToLocale should not pass id in data, throws error in postgres (#11402) 2025-02-28 12:06:32 -05:00
Jacob Fletcher
3709950d50 feat: maintains column state in url (#11387)
Maintains column state in the URL. This makes it possible to share
direct links to the list view in a specific column order or active
column state, similar to the behavior of filters. This also makes it
possible to change both the filters and columns in the same rendering
cycle, a requirement of the "list presets" feature being worked on here:
#11330.

For example:

```
?columns=%5B"title"%2C"content"%2C"-updatedAt"%2C"createdAt"%2C"id"%5D
```

The `-` prefix denotes that the column is inactive.

This strategy performs a single round trip to the server, ultimately
simplifying the table columns provider as it no longer needs to request
a newly rendered table for itself. Without this change, column state
would need to be replaced first, followed by a change to the filters.
This would make an unnecessary number of requests to the server and
briefly render the UI in a stale state.

This all happens behind an optimistic update, where the state of the
columns is immediately reflected in the UI while the request takes place
in the background.

Technically speaking, an additional database query in performed compared
to the old strategy, whereas before we'd send the data through the
request to avoid this. But this is a necessary tradeoff and doesn't have
huge performance implications. One could argue that this is actually a
good thing, as the data might have changed in the background which would
not have been reflected in the result otherwise.
2025-02-27 20:00:40 -05:00
Alessio Gravili
6ce5e8b83b perf: disable returning of db operations that don't need the return value (#11437)
If the return value of a db operation is not used, we can pass `returning: false` which will result in the query being executed faster.

See https://github.com/payloadcms/payload/pull/11393
2025-02-28 00:53:23 +00:00
Jacob Fletcher
c4bc0ae48a fix(next): disables active nav item (#11434)
When visiting a collection's list view, the nav item corresponding to
that collection correctly appears in an active state, but is still
rendered as an anchor tag. This makes it possible to reload the current
page by simply clicking the link, which is a problem because this
performs an unnecessary server roundtrip. This is especially apparent
when search params exist in the current URL, as the href on the link
does not.

Unrelated: also cleans up leftover code that was missed in this PR:
#11155
2025-02-27 15:21:28 -05:00
Patrik
f7b1cd9d63 fix(ui): duplicate basePath in Logout Button Link (#11432)
This PR resolves an issue where the `href` for the Logout button in the
admin panel included duplicate `basePath` values when `basePath` was set
in `next.config.js`.

The Logout button was recently updated to use `NextLink` (`next/link`),
which automatically applies the `basePath` from the Next.js
configuration. As a result, manually adding the `basePath` to the `href`
is no longer necessary.

Relevant PRs that modified this behavior originally: 
- #9275
- #11155
2025-02-27 13:58:27 -05:00
Alessio Gravili
7118b6418f fix(ui): disable publish button if form is autosaving (#11343)
Fixes https://github.com/payloadcms/payload/issues/6648

This PR introduces a new `useFormBackgroundProcessing` hook and a corresponding `setBackgroundProcessing` function in the `useForm` hook.

Unlike `useFormProcessing` / `setProcessing`, which mark the entire form as read-only, this new approach only disables the Publish button during autosaving, keeping form fields editable for a better user experience.

I named it `backgroundProcessing` because it should run behind the scenes without disrupting the user. You could argue that it is a bit more generic than something like `isAutosaving`, but it signals intent: Background = do not disrupt the user.
2025-02-27 10:28:08 -07:00
Elliot DeNolf
bdf0113b2f chore(release): v3.25.0 [skip ci] 2025-02-27 12:06:03 -05:00
Jacob Fletcher
6aa9da73f8 Revert "feat: simplify column prefs (#11390)" (#11427)
This reverts commit 69c0d09 in #11390.

In order to future proof column prefs, it probably is best to continue
to use the current shape. This change was intended to ensure that as
little transformation to URL params was made as possible for #11387, but
we will likely transform them after all.

This will ensure that we can add support for additional properties over
time, as needed. For example, if we hypothetically wanted to add a
custom `label` or similar feature to columns prefs, it would make more
sense to use explicit properties to identity `accessor` and `active`.

For example:

```ts
[
  {
    accessor: "title",
    active: true,
    label: 'Custom Label' // hypothetical
  }
]
```
2025-02-27 08:39:24 -05:00
Alessio Gravili
2a3682ff68 fix(deps): ensure Next.js 15.2.0 compatibility, upgrade nextjs and @types/react versions in monorepo (#11419)
This bumps next.js to 15.2.0 in our monorepo, as well as all @types/react and @types/react-dom versions. Additionally, it removes the obsolete `peerDependencies` property from our root package.json.

This PR also fixes 2 bugs introduced by Next.js 15.2.0. This highlights why running our test suite against the latest Next.js, to make sure Payload is compatible, version is important.

## 1. handleWhereChange running endlessly

Upgrading to Next.js 15.2.0 caused `handleWhereChange` to be continuously called by a `useEffect` when the list view filters were opened, leading to a React error - I did not investigate why upgrading the Next.js version caused that, but this PR fixes it by making use of the more predictable `useEffectEvent`.

## 2. Custom Block and Array label React key errors

Upgrading to Next.js 15.2.0 caused react key errors when rendering custom block and array row labels on the server. This has been fixed by rendering those with a key

## 3. Table React key errors

When rendering a `Table`, a React key error is thrown since Next.js 15.2.0
2025-02-27 05:56:09 +00:00
Sasha
b540da53ec feat(storage-*): large file uploads on Vercel (#11382)
Currently, usage of Payload on Vercel has a limitation - uploads are
limited by 4.5MB file size.
This PR allows you to pass `clientUploads: true` to all existing storage
adapters
* Storage S3
* Vercel Blob
* Google Cloud Storage
* Uploadthing
* Azure Blob

And then, Payload will do uploads on the client instead. With the S3
Adapter it uses signed URLs and with Vercel Blob it does this -
https://vercel.com/guides/how-to-bypass-vercel-body-size-limit-serverless-functions#step-2:-create-a-client-upload-route.
Note that it doesn't mean that anyone can now upload files to your
storage, it still does auth checks and you can customize that with
`clientUploads.access`


https://github.com/user-attachments/assets/5083c76c-8f5a-43dc-a88c-9ddc4527d91c

Implements https://github.com/payloadcms/payload/discussions/7569
feature request.
2025-02-26 21:59:34 +02:00
Patrik
81fd42ef69 fix(ui): skip bulk upload thumbnail generation on non-image files (#11378)
This PR fixes an issue where bulk upload attempts to generate thumbnails
for non-image files, causing errors on the page.

The fix ensures that thumbnail generation is skipped for non-image
files, preventing unnecessary errors.

Fixes #10428
2025-02-25 16:55:44 -05:00
Jacob Fletcher
69c0d09437 feat: simplify column prefs (#11390)
Transforms how column prefs are stored in the database. This change
reduces the complexity of the `columns` property by removing the
unnecessary `accessor` and `active` keys.

This change is necessary in order to [maintain column state in the
URL](https://github.com/payloadcms/payload/pull/11387), where the state
itself needs to be as concise as possible. Does so in a non-breaking
way, where the old column shape is transformed as needed.

Here's an example:

Before:

```ts
[
  {
    accessor: "title",
    active: true
  }
]
```

After:

```ts
[
  {
    title: true
  }
]
```
2025-02-25 15:18:14 -05:00
Jarrod Flesch
36e152d69d fix(ui): allow json fields to be updated externally (#11371)
### What?
Unable to update json fields externally. For example, calling `setValue`
on a json field would not be reflected in the admin panel UI.

### Why?
JSON fields use the monaco editor to manage state internally, so
programmatically updating the value in state does not change the
internal value.

### How?
Set a ref when the user updates the value and then unset the ref after
the change is complete.

Inside the hook that watches `value`, if the value changed and the
change came from the system (i.e. a programmatic change) refresh the
editor by adjusting its key prop. If the change was made by the user,
there is no need to refresh the editor.

Fixes https://github.com/payloadcms/payload/issues/10819
2025-02-25 09:44:06 -05:00
Patrik
7bb1c9d3c6 fix(ui): bulk upload DiscardWithoutSaving modal styles (#11381)
This PR fixes an issue where the `DiscardWithoutSaving` modal in the
bulk upload process was missing its styles.

The modal now displays correctly with the intended styling.

### Before:
![Screenshot 2025-02-24 at 8 20
52 PM](https://github.com/user-attachments/assets/c83a3119-28ce-4701-bc64-1219adeb2505)

### After:
![Screenshot 2025-02-24 at 8 20
07 PM](https://github.com/user-attachments/assets/62d364c2-b64c-4bd9-bf05-7481d609c6e4)

Fixes #11380
2025-02-25 08:56:42 -05:00
Patrik
f1b005c4f5 fix(ui): object type field labels not displaying in search filter (#11366)
This PR ensures that when `titleField.label` is provided as an object,
it is correctly translated and displayed in the search filter's
placeholder.

Previously, the implementation only supported string values, which could
lead to issues with object type labels. With these changes, object type
labels will now properly show as intended in the search filter.

Fixes #11348
2025-02-24 13:38:21 -05:00
Jacob Fletcher
2477fc6c75 fix(ui): custom block labels stale when reordering blocks (#11367)
When blocks have custom row labels, those row labels become stale when
reordering blocks. After moving a block, for example, the row label will
jump back the original block until form state returns with the proper
rendering order. This is especially evident on slow networks.
2025-02-24 16:52:12 +00:00
Paul
f9121c1a3a fix(ui): link element triggering clicks twice (#11362)
Fixes
https://github.com/payloadcms/payload/issues/11359#issuecomment-2678213414

The link element by using startTransitionRoute and manually calling
router.push would technically cause links to be clicked twice, by not
preventing default browser behaviour.

This caused a problem on clicking /create links as it hit the route
twice. Added a test making sure Create new doesn't lead to abnormally
increased document counts

Changes:
- Added `e.preventDefault()` in our Link element
- Added `preventDefault` as an optional prop to this element so that
people can handle it on their own if needed via a custom `onClick`
2025-02-24 14:49:52 +00:00
Sasha
4224c68002 docs: fix links to react hooks (#11344) 2025-02-22 13:23:00 +00:00
Paul
b014416584 feat: add support for not_like operation (#11326)
This PR adds support for `not_like` as a query operation. Functions just
as a negative to `like`, uses `ilike` in postgres and `like` in sqlite
2025-02-22 00:32:37 +00:00
Jacob Fletcher
d766b1904c feat(ui): threads row data through list drawer onSelect callback (#11339)
When rendering a list drawer, you can pass a custom `onSelect` callback
to execute when the user clicks on the linked cell within the table. The
underlying handler, however, only passes the `docID` and
`collectionSlug` args through the callback, rather than the document
itself. This makes it impossible to perform side-effects that require
the data of the row that was selected.

Instances of this callback were also largely untyped.

Needed for #11330.
2025-02-21 17:08:05 -05:00
Jacob Fletcher
f31568c69c refactor(ui): moves bulk edit controls (#11332)
Bulk edit controls are currently displayed within the search bar of the
list view. This doesn't make sense from a UX perspective, as the current
selection is displayed somewhere else entirely. These controls also take
up a lot of visual real estate which is beginning to get overused
especially after the introduction of "list menu items" in #11230, and
the potential introduction of "saved filters" controls in #11330.

Now, they are rendered contextually _alongside_ the selection count. To
make room for these new controls, they are displayed in plain text and
the entity labels have been removed from the selection count.
2025-02-21 15:06:30 -05:00
Jacob Fletcher
a8bec9a1b2 fix(ui): only show bulk select all when count is less than total (#11329)
It doesn't make sense to display "select all" when bulk editing if your
current selection already contains all records.
2025-02-21 13:42:47 -05:00
Alessio Gravili
845c647ebc perf: ensure fetching and updating preferences doesn't cause transaction errors and is done correctly (#11311)
## getPreferences function caching

Our `getPreferences` function used in the ui package is now wrapped in react cache, to minimize the amount of times it runs on a single request. This mimics the behavior of our other `getPreferences` function in the next package.

## getPreferences  incorrect behavior

The `getPreferences` function in the next package was passing through the incorrect user slug. This would not have been noticeable in projects with just one users collection, but might break in projects with multiple users collections.

## getPreferences performance optimization

This PR adds `pagination: false` to the getPreferences payload.find() call, which will speed up the query.

## upsertPreferences transaction errors

Due to the potential of preference upsert operations running in parallel (e.g. when switching locales), this PR disables transactions in the preferences creation / update calls. This fixes the transaction errors reported in https://github.com/payloadcms/payload/issues/11310
2025-02-21 01:53:56 +00:00
Said Akhrarov
22f61ad79e feat(ui): adds support for block groups (#11239)
<!--

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 the `admin.group` property in block
configs. This property enables blocks to be grouped under a common,
potentially localized, label in the block drawer component. This makes
it easier to sort through large collections of blocks. Previously, all
blocks would be in one common layout.

This PR also encompasses documentation changes and e2e tests to check
for the rendering of group labels.

### Why?
To make it easier to organize many blocks in block fields.

### How?
By introducing a new `admin.group` property in block configs and
assembling them in the blocks drawer component.

Before:

![Editing-Block-Field-Payload--before](https://github.com/user-attachments/assets/fb0c887b-ee47-46a1-a249-c4a4b7a5c13c)

After:

![Editing-Block-Field-Payload--after](https://github.com/user-attachments/assets/046d5a6f-3108-4464-ac69-8b7afcf27094)

Demo:

[Editing---Block-Field---Payload-groups-demo.webm](https://github.com/user-attachments/assets/2b351dc1-0d14-4a5b-ae71-bcd31fbb23df)

Addresses #5609
2025-02-20 19:51:47 +00:00
Jarrod Flesch
460d50baa3 fix(ui): confirmation modal should build off of drawerDepth, instead … (#11305)
When the new ConfirmationModal is used outside of the context of an
EditDepthProvider, it stacks behind currently open modals. This is
apparent when using it in custom views.

The fix is to build the confirm modal's depth off of drawerDepth instead
of editDepth.
2025-02-20 14:40:29 -05:00
Jessica Chowdhury
c05f10abbc chore: passes allowCreate into list drawer and adds test (#11284)
### What?
We had an `allowCreate` prop for the list drawer that doesn't do
anything. This PR passes the prop through so it can be used.

### How?
Passes `allowCreate` down to the list view and ties it with
`hasCreatePermission`

#### Testing
- Use `admin` test suite and `withListDrawer` collection.
- Test added to the `admin/e2e/list-view`.

Fixes #11246
2025-02-20 12:31:36 +00:00
Elliot DeNolf
f3161f9405 chore(release): v3.24.0 [skip ci] 2025-02-19 13:37:26 -05:00
Paul
e83318b156 fix(ui): minor issues with tabs and publish buttons when in RTL (#11282)
Fixes https://github.com/payloadcms/payload/issues/11162

Our tabs had wrong spacing in RTL.

The publish button with its dropdown had its borders and border radiuses
on the wrong side for RTL and fixed a minor issue in website template
around RTL margins.

Now publish button looks as expected in RTL:

![image](https://github.com/user-attachments/assets/023d27c9-dc14-4aa1-a5e7-b48f498921fd)
2025-02-19 17:18:01 +00:00
Sasha
009e9085fc fix(ui): turbopack with the latest next.js canary [skip lint] (#11280)
Fixes https://github.com/payloadcms/payload/issues/11211

Disables prepending `"use client"` to `.map` files
2025-02-19 18:55:04 +02:00
Dan Ribbens
9fc1cd0d24 fix(ui): disabledLocalStrategy.enableFields missing email/username fields (#11232)
When using `disabledLocalStrategy.enableFields`, it was impossible to
create a user from the admin panel because the username or email field
was missing.

![Screenshot 2025-02-17
133851](https://github.com/user-attachments/assets/f84ac74e-a3ce-4428-81b5-7135fc1cb917)

---------

Co-authored-by: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com>
2025-02-19 11:43:40 -05:00
Dan Ribbens
618624e110 fix(ui): unsaved changes allows for scheduled publish missing changes (#11001)
### What?
When you first edit a document and then open the Schedule publish
drawer, you can schedule publish changes but the current changes made to
the form won't be included.

### Why?
The UX does not make it clear that the changes you have in the form are
not actually going to be published.

### How?
Instead of allowing that we just disable the Schedule Publish drawer
toggler so that users are forced to save a draft first.

In addition to the above, this change also passes a defaultType so that
an already published document will default the radio type have
"Unpublish" selected.
2025-02-19 10:10:29 -05:00
Paul
8b0ae902e7 fix(ui): timezone issue related to date only fields in Pacific timezones (#11203)
Fixes https://github.com/payloadcms/payload/issues/10962

This fix addresses fields with timezones enabled specifically for not
time pickers. If all you want to do is pick a date such as 14th Feb, it
would store the incorrect version and display a date in the future for
people in the Pacific.

This is because Auckland is +12 offset, but +13 with Daylight Savings
Time. In our date picker we try to normalise date pickers with no time
to 12pm and so half the year we ended up pushing dates visually to the
next day for people in the pacific only. Other regions were not affected
by this because their offset would be less than 12.

This PR fixes this by ensuring that our dates are always normalised to
selected timezone's 12pm date to UTC.

There's also additional tests for these two fields from 3 main locations
to cover a wider range of possible timezones.
2025-02-19 14:46:05 +00:00
Fredrik
80b33adf6b feat(ui): enable specific css selectors on the localizer per locale
Adds a `locale-${localeCode}` data attribute to the localizer label and buttons.
2025-02-19 14:41:01 +00:00
Jacob Fletcher
af5554981c refactor(ui): simplifies confirmation modal callback (#11278)
Removes unnecessary callback args from the `onConfirm` callback in the
new `ConfirmationModal` component. Now, the component will close and
reset `isConfirming` state for itself.
2025-02-19 09:18:37 -05:00
Jacob Fletcher
bd8ced1b60 feat(ui): confirmation modal (#11271)
There are nearly a dozen independent implementations of the same modal
spread throughout the admin panel and various plugins. These modals are
used to confirm or cancel an action, such as deleting a document, bulk
publishing, etc. Each of these instances is nearly identical, leading to
unnecessary development efforts when creating them, inconsistent UI, and
duplicative stylesheets.

Everything is now standardized behind a new `ConfirmationModal`
component. This modal comes with a standard API that is flexible enough
to replace nearly every instance. This component has also been exported
for reuse.

Here is a basic example of how to use it:

```tsx
'use client'
import { ConfirmationModal, useModal } from '@payloadcms/ui'
import React, { Fragment } from 'react'

const modalSlug = 'my-confirmation-modal'

export function MyComponent() {
  const { openModal } = useModal()

  return (
    <Fragment>
      <button
        onClick={() => {
          openModal(modalSlug)
        }}
        type="button"
      >
        Do something
      </button>
      <ConfirmationModal
        heading="Are you sure?"
        body="Confirm or cancel before proceeding."
        modalSlug={modalSlug}
        onConfirm={({ closeConfirmationModal, setConfirming }) => {
          // do something
          setConfirming(false)
          closeConfirmationModal()
        }}
      />
    </Fragment>
  )
}
```
2025-02-19 02:27:03 -05:00
Alessio Gravili
132852290a fix(ui): database errors when running autosave and ensure autosave doesn't run unnecessarily (#11270)
## Change 1 - database errors when running autosave

The previous autosave implementation allowed multiple autosave fetch
calls (=> save document draft) to run in parallel. While the
AbortController aborted previous autosave calls if a new one comes in in
order to only process the latest one, this had one flaw:

Using the AbortController to abort the autosave call only aborted the
`fetch` call - it did not however abort the database operation that may
have started as part of this fetch call. If you then started a new
autosave call, this will start yet another database operation on the
backend, resulting in two database operations that would be running at
the same time.

This has caused a lot of transaction errors that were only noticeable
when connected to a slower, remote database. This PR removes the
AbortController and ensures that the previous autosave operation is
properly awaited before starting a new one, while still discarding
outdated autosave requests from the queue **that have not started yet**.

Additionally, it cleans up the AutoSave component to make it more
readable.

## Change 2 - ensure autosave doesn't run unnecessarily

If connected to a slower backend or database, one change in a document
may trigger two autosave operations instead of just one. This is how it
could happen:

1. Type something => formstate changes => autosave is triggered
2. 200ms later: form state request is triggered. Autosave is still
processing
3. 100ms later: form state comes back from server => local form state is
updated => another autosave is triggered
4. First autosave is aborted - this lead to a browser error. This PR
ensures that that error is no longer surfaced to the user
5. Another autosave is started

This PR adds additional checks to ONLY trigger an autosave if the form
DATA (not the entire form state itself) changes. Previously, it ran
every time the object reference of the form state changes. This includes
changes that do not affect the form data, like `field.valid`. =>
Basically every time form state comes back from the server, we were
triggering another, unnecessary autosave
2025-02-19 03:38:32 +00:00
Alessio Gravili
7f5aaad6a5 fix(ui): do not pass req in handleFormStateLocking (#11269)
Not passing through `req` ensures that the db operations in
`handleFormStateLocking` run independently, preventing them from being
part of the same transaction. Since locked document operations don't
really require transactional consistency, this change helps avoid
unnecessary transaction errors that have previously occurred here.
2025-02-19 02:43:20 +00:00
Sasha
6d36a28cdc feat: join field across many collections (#10919)
This feature allows you to specify `collection` for the join field as
array.
This can be useful for example to describe relationship linking like
this:
```ts
{
  slug: 'folders',
  fields: [
    {
      type: 'join',
      on: 'folder',
      collection: ['files', 'documents', 'folders'],
      name: 'children',
    },
    {
      type: 'relationship',
      relationTo: 'folders',
      name: 'folder',
    },
  ],
},
{
  slug: 'files',
  upload: true,
  fields: [
    {
      type: 'relationship',
      relationTo: 'folders',
      name: 'folder',
    },
  ],
},
{
  slug: 'documents',
  fields: [
    {
      type: 'relationship',
      relationTo: 'folders',
      name: 'folder',
    },
  ],
},
```

Documents and files can be placed to folders and folders themselves can
be nested to other folders (root folders just have `folder` as `null`).

Output type of `Folder`:
```ts
export interface Folder {
  id: string;
  children?: {
    docs?:
      | (
          | {
              relationTo?: 'files';
              value: string | File;
            }
          | {
              relationTo?: 'documents';
              value: string | Document;
            }
          | {
              relationTo?: 'folders';
              value: string | Folder;
            }
        )[]
      | null;
    hasNextPage?: boolean | null;
  } | null;
  folder?: (string | null) | Folder;
  updatedAt: string;
  createdAt: string;
}
```

While you could instead have many join fields (for example
`childrenFolders`, `childrenFiles`) etc - this doesn't allow you to
sort/filter and paginate things across many collections, which isn't
trivial. With SQL we use `UNION ALL` query to achieve that.

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2025-02-18 21:53:45 +02:00
Paul
06debf5e14 fix(ui): issues with prevent leave and autosave when the form is submitted but invalid (#11233)
Fixes https://github.com/payloadcms/payload/issues/11224
Fixes https://github.com/payloadcms/payload/issues/10492

This PR fixes a few weird behaviours when `validate: true` is set on drafts:
- when autosave is on and you submit an invalid form it would get stuck in an infinite loop
- PreventLeave would not trigger for submitted but invalid forms leading to potential data loss

Changes:
- Adds e2e tests for the above scenarios
- Adds a new `isValid` flag on the `Form` context provider to signal globally if the form is in a valid or invalid state
  - Components like Autosave will manage this internally since it manages its own submission flow as well
- Adds PreventLeave to Autosave too for when form is invalid meaning data hasn't been actually saved so we want to prevent the user accidentally losing data by reloading or closing the page


The following tests have been added
![image](https://github.com/user-attachments/assets/db208aa4-6ed6-4287-b200-59575cd3c9d0)
2025-02-18 12:12:41 -07:00
Paul
1c4eba41b7 fix(ui): allow selectinputs to reset to their initial values if theres no provided value (#11252)
When reusing the SelectInput component from the UI package, if you set
value to `''` it will continue to display the previously selected value
instead of clearing out the field as expected.

The ReactSelect component doesn't behave in this way and instead will
clear out the field.

This fix addresses this difference by resetting `valueToRender` inside
the SelectInput to null.
2025-02-18 16:40:29 +00:00
Patrik
5817b81289 fix(ui): selection status not updating after toggleAll in useSelection hook (#11218)
### What?

After clicking "Select all" `toggleAll(true)`, manually deselecting an
item does not update the overall selection status.

The bulk actions remain visible, and `selectAll` incorrectly stays as
`AllAvailable`.

### How?

Updated `setSelection()` logic to adjust `selectAll` when deselecting an
item if it was previously set to `AllAvailable`.

This ensures that the selection state updates correctly without altering
the effect logic.

`selectAll` switches to Some when an item is deselected after selecting
all.

Bulk actions now hide correctly if no items are selected.

Fixes #10836
2025-02-18 10:28:54 -05:00
Jessica Chowdhury
8a2b712287 feat(ui): adds admin.components.listMenuItems option (#11230)
### What?
Adds new option `admin.components.listMenuItems` to allow custom
components to be injected after the existing list controls in the
collection list view.

### Why?
Needed to facilitate import/export plugin.

#### Testing

Use `pnpm dev admin` to see example component and see test added to
`test/admin/e2e/list-view`.


## Update since feature was reverted
The custom list controls and now rendered with no surrounding padding or
border radius.

<img width="596" alt="Screenshot 2025-02-17 at 5 06 44 PM"
src="https://github.com/user-attachments/assets/57209367-5433-4a4c-8797-0f9671da15c8"
/>

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2025-02-18 09:35:27 -05:00
Dan Ribbens
daaaa5f1be feat(ui): add hideFileInputOnCreate and hideRemoveFile to collection upload config (#11217)
### What?

Two new configuration properties added for upload enabled collections.
- *hideFileInputOnCreate* - Set to `true` to prevent the admin UI from
showing file inputs during document creation, useful for programmatic
file generation.
- *hideRemoveFile* - Set to `true` to prevent the admin UI having a way
to remove an existing file while editing.

### Why?

When using file uploads that get created programmatically in
`beforeOperation` hooks or files created using `jobs`, or when
`filesRequiredOnCreate` is false, you may want to use these new flags to
prevent users from interacting with these controls.

### How?

The new properties only impact the admin UI components to dial in the UX
for various use cases.

Screenshot showing that the upload controls are not available on create:

![image](https://github.com/user-attachments/assets/5560b9ac-271d-4ee0-8bcf-6080012ff75f)

Screenshot showing hideRemoveFile has removed the ability to remove the
existing file:

![image](https://github.com/user-attachments/assets/71c562dd-c425-40e6-b980-f65895979885)

Prerequisite for https://github.com/payloadcms/payload/pull/10795
2025-02-17 16:36:38 -05:00