This PR comes with a bunch of improvements to our template generation
script that makes it safer and more reliable
- bumps all our templates
- Using `latest` as payload version in our templates has proven to be
unreliable. This updates the gen-templates script to pin all payload
packages to the latest version
- adds the missing `website` entry for our template variations, thus
ensuring its lockfile gets updated
- adds importmap generation to the gen-templates script
- adds new `script:gen-templates:build` script to verify that all
templates still build correctly
**BREAKING CHANGE:**
This bumps the **minimum required Next.js** version from 15.0.0 to
15.2.3. This update is necessary due to a critical security
vulnerability found in earlier Next.js versions, which requires an
exception to our standard semantic versioning process.
Additionally, this bumps all templates to the latest Next.js and Payload
versions.
- Adds support for numeric canary versions ie. `3.28.0-canary.0`,
subsequent prereleases will increment accordingly (like Next.js)
- _Our old way of doing canary releases_ is still available but will now
be tagged as `internal` ex. `3.28.0-internal.shorthash`
- Releases are triggered via workflow dispatch in Actions. Triggers off
of main will be released as `canary`, all others will be `internal`.
Imports https://github.com/payloadcms/payload-admin-bar into the Payload
monorepo. This package will now be regularly maintained directly
alongside all Payload packages and now includes its own test suite.
A few changes minor have been made between v1.0.7 and latest:
1. The package name has changed from `payload-admin-bar` to
`@payloadcms/admin-bar`.
```diff
- import { PayloadAdminBar } from 'payload-admin-bar'
+ import { PayloadAdminBar } from '@payloadcms/admin-bar'
```
2. The `collection` prop has been renamed to `collectionSlug`
3. The `authCollection` prop has been renamed to `authCollectionSlug`
Here's a screenshot of the admin bar in use within the Website Template:
<img width="1057" alt="Screenshot 2025-03-05 at 1 20 04 PM"
src="https://github.com/user-attachments/assets/2597a8fd-da75-4b2f-8979-4fc8132999e8"
/>
---------
Co-authored-by: Kalon Robson <kalon.robson@outlook.com>
Adds new plugin-import-export initial version.
Allows for direct download and creation of downloadable collection data
stored to a json or csv uses the access control of the user creating the
request to make the file.
config options:
```ts
/**
* Collections to include the Import/Export controls in
* Defaults to all collections
*/
collections?: string[]
/**
* Enable to force the export to run synchronously
*/
disableJobsQueue?: boolean
/**
* This function takes the default export collection configured in the plugin and allows you to override it by modifying and returning it
* @param collection
* @returns collection
*/
overrideExportCollection?: (collection: CollectionOverride) => CollectionOverride
// payload.config.ts:
plugins: [
importExportPlugin({
collections: ['pages', 'users'],
overrideExportCollection: (collection) => {
collection.admin.group = 'System'
collection.upload.staticDir = path.resolve(dirname, 'uploads')
return collection
},
disableJobsQueue: true,
}),
],
```
---------
Co-authored-by: Jessica Chowdhury <jessica@trbl.design>
Co-authored-by: Kendell Joseph <kendelljoseph@gmail.com>
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
Having the `scripts` dir re-use all packages from the top-level was
getting quite unwieldy. Created new `tools` directory that is part of
the workspace. Packages are exported with the `@tools` package
namespace.
Bumps the following dependencies:
- next
- typescript
- http-status
- nodemailer
- Payload & next versions in all templates
- Monorepo only: playwright and dotenv
Removes unused dependencies:
- ts-jest
- jest-environment-jsdom
- resend (we don't use their sdk, we only use their rest API)
### Multi Tenant Plugin
This PR adds a `@payloadcms/plugin-multi-tenant` package. The goal is to
consolidate a source of truth for multi-tenancy. Currently we are
maintaining different implementations for clients, users in discord and
our examples repo. When updates or new paradigms arise we need to
communicate this with everyone and update code examples which is hard to
maintain.
### What does it do?
- adds a tenant selector to the sidebar, above the nav links
- adds a hidden tenant field to every collection that you specify
- adds an array field to your users collection, allowing you to assign
users to tenants
- by default combines the access control (to enabled collections) that
you define, with access control based on the tenants assigned to user on
the request
- by default adds a baseListFilter that filters the documents shown in
the list view with the selected tenant in the admin panel
### What does it not do?
- it does not implement multi-tenancy for your frontend. You will need
to query data for specific tenants to build your website/application
- it does not add a tenants collection, you **NEED** to add a tenants
collection, where you can define what types of fields you would like on
it
### The plugin config
Most of the options listed below are _optional_, but it is easier to
just lay out all of the configuration options.
**TS Type**
```ts
type MultiTenantPluginConfig<ConfigTypes = unknown> = {
/**
* After a tenant is deleted, the plugin will attempt to clean up related documents
* - removing documents with the tenant ID
* - removing the tenant from users
*
* @default true
*/
cleanupAfterTenantDelete?: boolean
/**
* Automatically
*/
collections: {
[key in CollectionSlug]?: {
/**
* Set to `true` if you want the collection to behave as a global
*
* @default false
*/
isGlobal?: boolean
/**
* Set to `false` if you want to manually apply the baseListFilter
*
* @default true
*/
useBaseListFilter?: boolean
/**
* Set to `false` if you want to handle collection access manually without the multi-tenant constraints applied
*
* @default true
*/
useTenantAccess?: boolean
}
}
/**
* Enables debug mode
* - Makes the tenant field visible in the admin UI within applicable collections
*
* @default false
*/
debug?: boolean
/**
* Enables the multi-tenant plugin
*
* @default true
*/
enabled?: boolean
/**
* Field configuration for the field added to all tenant enabled collections
*/
tenantField?: {
access?: RelationshipField['access']
/**
* The name of the field added to all tenant enabled collections
*
* @default 'tenant'
*/
name?: string
}
/**
* Field configuration for the field added to the users collection
*
* If `includeDefaultField` is `false`, you must include the field on your users collection manually
* This is useful if you want to customize the field or place the field in a specific location
*/
tenantsArrayField?:
| {
/**
* Access configuration for the array field
*/
arrayFieldAccess?: ArrayField['access']
/**
* When `includeDefaultField` is `true`, the field will be added to the users collection automatically
*/
includeDefaultField?: true
/**
* Additional fields to include on the tenants array field
*/
rowFields?: Field[]
/**
* Access configuration for the tenant field
*/
tenantFieldAccess?: RelationshipField['access']
}
| {
arrayFieldAccess?: never
/**
* When `includeDefaultField` is `false`, you must include the field on your users collection manually
*/
includeDefaultField?: false
rowFields?: never
tenantFieldAccess?: never
}
/**
* The slug for the tenant collection
*
* @default 'tenants'
*/
tenantsSlug?: string
/**
* Function that determines if a user has access to _all_ tenants
*
* Useful for super-admin type users
*/
userHasAccessToAllTenants?: (
user: ConfigTypes extends { user: User } ? ConfigTypes['user'] : User,
) => boolean
}
```
**Example usage**
```ts
import type { Config } from './payload-types'
import { buildConfig } from 'payload'
export default buildConfig({
plugins: [
multiTenantPlugin<Config>({
collections: {
pages: {},
},
userHasAccessToAllTenants: (user) => isSuperAdmin(user),
}),
],
})
```
### How to configure Collections as Globals for multi-tenant
When using multi-tenant, globals need to actually be configured as
collections so the content can be specific per tenant.
To do that, you can mark a collection with `isGlobal` and it will behave
like a global and users will not see the list view.
```ts
multiTenantPlugin({
collections: {
navigation: {
isGlobal: true,
},
},
})
```
Bumps Next.js to the latest version `15.1.3`. This affects only internal
`package.json` files (in the root dir and test)
Fixes errors from here https://github.com/payloadcms/payload/pull/10209