Compare commits

...

19 Commits

Author SHA1 Message Date
Elliot DeNolf
96d99cb361 chore(release): v3.0.0-beta.110 [skip ci] 2024-09-30 13:19:32 -04:00
Dan Ribbens
3f375cc6ee feat: join field on upload fields (#8379)
This PR makes it possible to use the new `join` field in connection with
an `upload` field. Previously `join` was reserved only for
relationships.
2024-09-30 13:12:30 -04:00
Dan Ribbens
3847428f0a fix(db-*): make db.begintransactions required (#8419)
Changing the transcations functions on the db so that projects using
typescript `strict: true` do not need to type narrow before using it.
2024-09-30 13:12:07 -04:00
Sasha
7b6a760e97 fix(db-mongodb): duplicate versions with parent string ids (#8487)
Fixes https://github.com/payloadcms/payload/issues/8441

we may want to add a predifined migration that changes all what's needed
to ObjectIDs @DanRibbens
2024-09-30 13:06:48 -04:00
James Mikrut
0c1004537d fix: draft status access control checks (#8486) 2024-09-30 16:41:54 +00:00
Sasha
e765a5e866 fix: reset password link extra slash and thread admin.routes.reset property (#8448)
Removes extra slash
from: 
`http://host/admin//reset/token`
to:
`http://host/admin/reset/token`

Threads `admin.routes.reset`:
```ts
const config: Config = {
  admin: {
    routes: {
      reset: '/custom-reset',
    },
  },
}
```
2024-09-30 19:06:19 +03:00
Ante
f543e8963e chore(translations): croatian translation improvements (#7413)
Croatian translation is improved for better choice of words in given
context, typos, extra whitespaces and consistency of formal pronouns
use.
2024-09-30 12:04:34 -04:00
Alessio Gravili
163f3c0692 feat(richtext-lexical): export $createInlineBlockNode, $isInlineBlockNode and InlineBlockNode (#8480) 2024-09-30 13:42:49 +00:00
Dan Ribbens
4241811fa9 fix: sorting by id incorrectly orders by version.id (#8442)
fixes #7187
2024-09-30 09:16:41 -04:00
Patrik
8110cb9956 fix(db-mongodb): properly filters out number field values with the exists operator filter (#8416)
V2 PR [here](https://github.com/payloadcms/payload/pull/8415)
2024-09-30 08:59:58 -04:00
Paul
e5ca476d7f fix(ui): RTL not applying for localised textarea fields (#8474) 2024-09-29 19:25:09 +00:00
Alessio Gravili
161749bde9 chore: fix build by adding missing translation keys (#8471) 2024-09-29 10:56:36 +00:00
Mike Bailey
22f120dc85 feat(translations): add danish translations (#7809)
Added Danish (da-DK) translations for Beta
2024-09-28 18:13:31 -04:00
Alessio Gravili
e7b44dc545 chore: add workaround for unsettled top-level await script failures (#8467)
currently only for pnpm dev
2024-09-28 17:53:45 +00:00
Germán Jabloñski
8b44676b0d feat(richtext-lexical)!: upgrade lexical from 0.17.0 to 0.18.0, make tables more reliable (#8444)
This PR

- Introduces multiline markdown transformers / mdx support
- Introduce `shouldMergeAdjacentLines` option in
`$convertFromMarkdownString`. If true, merges adjacent lines as per
commonmark spec. This would allow to close:
https://github.com/payloadcms/payload/issues/8049
- Many new features and bug fixes!
- Ports over changes from the lexical playground. Most notably:
  - add support for enabling table row stripping
  - make table resizing & table cell selection more reliable

**BREAKING**: This upgrades lexical from 0.17.0 to 0.18.0. If you have
any lexical packages installed in your project, please update them
accordingly. Additionally, if you depend on the lexical APIs, please
consult their changelog, as lexical may introduce breaking changes:
https://github.com/facebook/lexical/releases/tag/v0.18.0

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-09-28 13:10:44 -04:00
Sasha
613d3b090e fix(drizzle): hasMany / poly relationships nested to localized fields / nested blocks to localized fields (#8456)
fixes https://github.com/payloadcms/payload/issues/8455 and
https://github.com/payloadcms/payload/issues/8462

- Builds the `_locale` column for the `_rels` when it's inside of a
localized group / tab
- Properly builds `sanitizedPath` for blocks in the transform-read
function when it's inside of a localized field. This fixes with fields
inside that have its own table (like `_rels`, select `hasMany: true`
etc)

Adds _more_ tests!
2024-09-28 17:33:50 +03:00
Paul
fb603448d8 feat(templates): add search functionality to the website template (#8454)
- adds a /search and search plugin example to website template
- adds an additional check for valid paths on /preview
- fixes a few bugs around the site
2024-09-27 18:01:58 -06:00
Germán Jabloñski
f50174f5b8 fix(richtext-lexical): match the indentation spacing of paragraphs and lists (#8437)
Before this, indented paragraphs, un/ordered list-items, and checkbox
list-items had 3 different sizes.

This PR unifies all 3 to match.

Related:
- https://github.com/payloadcms/payload/pull/8138
- https://github.com/facebook/lexical/pull/4025

List-items were using a custom indentation size, instead of the
browser's default. The reason I'm adapting list-items to this default
size and not the paragraphs to list-items, is because when
importing/exporting html in contexts where our CSS isn't present, visual
consistency is maintained.

Also, the browsers' default looks fine to me.

Note: Lexical's detection of whether the checkbox is clicked is a bit
hacky. I've made sure it doesn't break and added an explanatory comment
to prevent anyone from breaking it in the future.

## Before


![image](https://github.com/user-attachments/assets/7195a592-a695-4131-af1a-df016c215758)

## After


![image](https://github.com/user-attachments/assets/ef3b708f-2ce6-4bf0-951e-15c550cdcc65)
2024-09-27 13:28:36 -03:00
Germán Jabloñski
17e0547db3 feat(payload, ui): add admin.allowEdit relationship field (#8398)
This PR adds a new property `allowEdit` to the admin of the relationship
field. It is very similar to the existing `allowCreate`, only in this
case it hides the edit icon:

<img width="796" alt="image"
src="https://github.com/user-attachments/assets/bbe79bb2-db06-4ec4-b023-2f1c53330fcb">
2024-09-27 09:22:03 -04:00
126 changed files with 12628 additions and 610 deletions

View File

@@ -6,8 +6,8 @@ desc: The Join field provides the ability to work on related documents. Learn ho
keywords: join, relationship, junction, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Join Field is used to make Relationship fields in the opposite direction. It is used to show the relationship from
the other side. The field itself acts as a virtual field, in that no new data is stored on the collection with a Join
The Join Field is used to make Relationship and Upload fields available in the opposite direction. With a Join you can edit and view collections
having reference to a specific collection document. The field itself acts as a virtual field, in that no new data is stored on the collection with a Join
field. Instead, the Admin UI surfaces the related documents for a better editing experience and is surfaced by Payload's
APIs.
@@ -16,6 +16,7 @@ The Join field is useful in scenarios including:
- To surface `Order`s for a given `Product`
- To view and edit `Posts` belonging to a `Category`
- To work with any bi-directional relationship data
- Displaying where a document or upload is used in other documents
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/join.png"
@@ -24,8 +25,8 @@ The Join field is useful in scenarios including:
caption="Admin Panel screenshot of Join field"
/>
For the Join field to work, you must have an existing [relationship](./relationship) field in the collection you are
joining. This will reference the collection and path of the field of the related documents.
For the Join field to work, you must have an existing [relationship](./relationship) or [upload](./upload) field in the
collection you are joining. This will reference the collection and path of the field of the related documents.
To add a Relationship Field, set the `type` to `join` in your [Field Config](./overview):
```ts
@@ -122,7 +123,7 @@ complete control over any type of relational architecture in Payload, all wrappe
|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`name`** \* | To be used as the property name when retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`collection`** \* | The `slug`s having the relationship field. |
| **`on`** \* | The relationship field name of the field that relates to collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`on`** \* | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/getting-started/concepts#field-level-max-depth) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |

View File

@@ -90,6 +90,7 @@ The Relationship Field inherits all of the default options from the base [Field
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **`isSortable`** | Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop (only works when `hasMany` is set to `true`). |
| **`allowCreate`** | Set to `false` if you'd like to disable the ability to create new documents from within the relationship field. |
| **`allowEdit`** | Set to `false` if you'd like to disable the ability to edit documents from within the relationship field. |
| **`sortOptions`** | Define a default sorting order for the options within a Relationship field's dropdown. [More](#sortOptions) |
### Sort Options

View File

@@ -6,7 +6,8 @@ desc: Upload fields will allow a file to be uploaded, only from a collection sup
keywords: upload, images media, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Upload Field allows for the selection of a Document from a Collection supporting [Uploads](../upload/overview), and formats the selection as a thumbnail in the Admin Panel.
The Upload Field allows for the selection of a Document from a Collection supporting [Uploads](../upload/overview), and
formats the selection as a thumbnail in the Admin Panel.
Upload fields are useful for a variety of use cases, such as:
@@ -15,10 +16,10 @@ Upload fields are useful for a variety of use cases, such as:
- To give a layout building block the ability to feature a background image
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/upload.png"
srcDark="https://payloadcms.com/images/docs/fields/upload-dark.png"
alt="Shows an upload field in the Payload Admin Panel"
caption="Admin Panel screenshot of an Upload field"
srcLight="https://payloadcms.com/images/docs/fields/upload.png"
srcDark="https://payloadcms.com/images/docs/fields/upload-dark.png"
alt="Shows an upload field in the Payload Admin Panel"
caption="Admin Panel screenshot of an Upload field"
/>
To create an Upload Field, set the `type` to `upload` in your [Field Config](./overview):
@@ -43,7 +44,7 @@ export const MyUploadField: Field = {
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`*relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-upload-options). |
@@ -97,7 +98,7 @@ prevent all, or a `Where` query. When using a function, it will be
called with an argument object with the following properties:
| Property | Description |
| ------------- | ----------------------------------------------------------------------------------------------------- |
|---------------|-------------------------------------------------------------------------------------------------------|
| `relationTo` | The collection `slug` to filter against, limited to this field's `relationTo` property |
| `data` | An object containing the full collection or global document currently being edited |
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
@@ -127,3 +128,10 @@ You can learn more about writing queries [here](/docs/queries/overview).
unless you call the default upload field validation function imported from{' '}
<strong>payload/shared</strong> in your validate function.
</Banner>
## Bi-directional relationships
The `upload` field on its own is used to reference documents in an upload collection. This can be considered a "one-way"
relationship. If you wish to allow an editor to visit the upload document and see where it is being used, you may use
the `join` field in the upload enabled collection. Read more about bi-directional relationships using
the [Join field](./join)

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"private": true,
"type": "module",
"scripts": {
@@ -99,7 +99,7 @@
"prettier --write",
"eslint --cache --fix"
],
"templates/website/**/*": "sh -c \"cd templates/website; pnpm install --ignore-workspace; pnpm run lint --fix\"",
"templates/website/**/*": "sh -c \"cd templates/website; pnpm install --no-frozen-lockfile --ignore-workspace; pnpm run lint --fix\"",
"tsconfig.json": "node scripts/reset-tsconfig.js"
},
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "create-payload-app",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The officially supported MongoDB database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,5 +1,4 @@
import ObjectIdImport from 'bson-objectid'
import { isValidObjectId } from 'mongoose'
import mongoose from 'mongoose'
import {
buildVersionCollectionFields,
type CreateVersion,
@@ -12,8 +11,6 @@ import type { MongooseAdapter } from './index.js'
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
import { withSession } from './withSession.js'
const ObjectId = (ObjectIdImport.default ||
ObjectIdImport) as unknown as typeof ObjectIdImport.default
export const createVersion: CreateVersion = async function createVersion(
this: MongooseAdapter,
{
@@ -60,10 +57,10 @@ export const createVersion: CreateVersion = async function createVersion(
},
],
}
if (typeof data.parent === 'string' && isValidObjectId(data.parent)) {
if (data.parent instanceof mongoose.Types.ObjectId) {
parentQuery.$or.push({
parent: {
$eq: ObjectId(data.parent),
$eq: data.parent.toString(),
},
})
}

View File

@@ -6,7 +6,7 @@ import type { BaseDatabaseAdapter, DatabaseAdapterObj, Payload, UpdateOneArgs }
import fs from 'fs'
import mongoose from 'mongoose'
import path from 'path'
import { createDatabaseAdapter } from 'payload'
import { createDatabaseAdapter, defaultBeginTransaction } from 'payload'
import type { CollectionModel, GlobalModel, MigrateDownArgs, MigrateUpArgs } from './types.js'
@@ -163,7 +163,7 @@ export function mongooseAdapter({
url,
versions: {},
// DatabaseAdapter
beginTransaction: transactionOptions ? beginTransaction : undefined,
beginTransaction: transactionOptions === false ? defaultBeginTransaction() : beginTransaction,
commitTransaction,
connect,
create,

View File

@@ -12,6 +12,30 @@ type SanitizeQueryValueArgs = {
val: any
}
const buildExistsQuery = (formattedValue, path) => {
if (formattedValue) {
return {
rawQuery: {
$and: [
{ [path]: { $exists: true } },
{ [path]: { $ne: null } },
{ [path]: { $ne: '' } }, // Exclude null and empty string
],
},
}
} else {
return {
rawQuery: {
$or: [
{ [path]: { $exists: false } },
{ [path]: { $eq: null } },
{ [path]: { $eq: '' } }, // Treat empty string as null / undefined
],
},
}
}
}
const ObjectId = (ObjectIdImport.default ||
ObjectIdImport) as unknown as typeof ObjectIdImport.default
export const sanitizeQueryValue = ({
@@ -93,8 +117,16 @@ export const sanitizeQueryValue = ({
}
}
if (field.type === 'number' && typeof formattedValue === 'string') {
formattedValue = Number(val)
if (field.type === 'number') {
if (typeof formattedValue === 'string' && operator !== 'exists') {
formattedValue = Number(val)
}
if (operator === 'exists') {
formattedValue = val === 'true' ? true : val === 'false' ? false : Boolean(val)
return buildExistsQuery(formattedValue, path)
}
}
if (field.type === 'date' && typeof val === 'string' && operator !== 'exists') {
@@ -206,27 +238,7 @@ export const sanitizeQueryValue = ({
if (operator === 'exists') {
formattedValue = formattedValue === 'true' || formattedValue === true
if (formattedValue) {
return {
rawQuery: {
$and: [
{ [path]: { $exists: true } },
{ [path]: { $ne: null } },
{ [path]: { $ne: '' } },
],
},
}
} else {
return {
rawQuery: {
$or: [
{ [path]: { $exists: false } },
{ [path]: { $eq: null } },
{ [path]: { $eq: '' } }, // Treat empty string as null / undefined
],
},
}
}
return buildExistsQuery(formattedValue, path)
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The officially supported Postgres database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -47,7 +47,7 @@ import {
requireDrizzleKit,
} from '@payloadcms/drizzle/postgres'
import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'
import { createDatabaseAdapter } from 'payload'
import { createDatabaseAdapter, defaultBeginTransaction } from 'payload'
import type { Args, PostgresAdapter } from './types.js'
@@ -107,7 +107,8 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
versionsSuffix: args.versionsSuffix || '_v',
// DatabaseAdapter
beginTransaction: args.transactionOptions === false ? undefined : beginTransaction,
beginTransaction:
args.transactionOptions === false ? defaultBeginTransaction() : beginTransaction,
commitTransaction,
connect,
convertPathToJSONTraversal,

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-sqlite",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The officially supported SQLite database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -34,7 +34,7 @@ import {
updateVersion,
} from '@payloadcms/drizzle'
import { like } from 'drizzle-orm'
import { createDatabaseAdapter } from 'payload'
import { createDatabaseAdapter, defaultBeginTransaction } from 'payload'
import type { Args, SQLiteAdapter } from './types.js'
@@ -108,7 +108,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
versionsSuffix: args.versionsSuffix || '_v',
// DatabaseAdapter
beginTransaction: args.transactionOptions ? beginTransaction : undefined,
beginTransaction: args.transactionOptions ? beginTransaction : defaultBeginTransaction(),
commitTransaction,
connect,
convertPathToJSONTraversal,

View File

@@ -711,7 +711,7 @@ export const traverseFields = ({
rootTableIDColType,
rootTableName,
versions,
withinLocalizedArrayOrBlock,
withinLocalizedArrayOrBlock: withinLocalizedArrayOrBlock || field.localized,
})
if (groupHasLocalizedField) {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-vercel-postgres",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Vercel Postgres adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -47,7 +47,7 @@ import {
requireDrizzleKit,
} from '@payloadcms/drizzle/postgres'
import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'
import { createDatabaseAdapter } from 'payload'
import { createDatabaseAdapter, defaultBeginTransaction } from 'payload'
import type { Args, VercelPostgresAdapter } from './types.js'
@@ -107,7 +107,8 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<Verce
versionsSuffix: args.versionsSuffix || '_v',
// DatabaseAdapter
beginTransaction: args.transactionOptions === false ? undefined : beginTransaction,
beginTransaction:
args.transactionOptions === false ? defaultBeginTransaction() : beginTransaction,
commitTransaction,
connect,
convertPathToJSONTraversal,

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/drizzle",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "A library of shared functions used by different payload database adapters",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -721,7 +721,7 @@ export const traverseFields = ({
rootTableIDColType,
rootTableName,
versions,
withinLocalizedArrayOrBlock,
withinLocalizedArrayOrBlock: withinLocalizedArrayOrBlock || field.localized,
})
if (groupHasLocalizedField) {

View File

@@ -237,12 +237,13 @@ export const traverseFields = <T extends Record<string, unknown>>({
if (field.type === 'blocks') {
const blockFieldPath = `${sanitizedPath}${field.name}`
const blocksByPath = blocks[blockFieldPath]
if (Array.isArray(blocks[blockFieldPath])) {
if (Array.isArray(blocksByPath)) {
if (field.localized) {
result[field.name] = {}
blocks[blockFieldPath].forEach((row) => {
blocksByPath.forEach((row) => {
if (row._uuid) {
row.id = row._uuid
delete row._uuid
@@ -285,7 +286,23 @@ export const traverseFields = <T extends Record<string, unknown>>({
})
})
} else {
result[field.name] = blocks[blockFieldPath].reduce((acc, row, i) => {
// Add locale-specific index to have a proper blockFieldPath for current locale
// because blocks can be in the same array for different locales!
if (withinArrayOrBlockLocale && config.localization) {
for (const locale of config.localization.localeCodes) {
let localeIndex = 0
for (let i = 0; i < blocksByPath.length; i++) {
const row = blocksByPath[i]
if (row._locale === locale) {
row._index = localeIndex
localeIndex++
}
}
}
}
result[field.name] = blocksByPath.reduce((acc, row, i) => {
delete row._order
if (row._uuid) {
row.id = row._uuid
@@ -301,6 +318,10 @@ export const traverseFields = <T extends Record<string, unknown>>({
if (row._locale) {
delete row._locale
}
if (typeof row._index === 'number') {
i = row._index
delete row._index
}
acc.push(
traverseFields<T>({
@@ -350,6 +371,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
}
} else {
const relationPathMatch = relationships[`${sanitizedPath}${field.name}`]
if (!relationPathMatch) {
if ('hasMany' in field && field.hasMany) {
if (field.localized && config.localization && config.localization.locales) {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/email-nodemailer",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Payload Nodemailer Email Adapter",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/email-resend",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Payload Resend Email Adapter",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/graphql",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview-react",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The official React SDK for Payload Live Preview",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview-vue",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The official Vue SDK for Payload Live Preview",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The official live preview JavaScript SDK for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/next",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -37,7 +37,10 @@ export const getDocumentPermissions = async (args: {
},
req: {
...req,
data,
data: {
...data,
_status: 'draft',
},
},
})

View File

@@ -139,7 +139,7 @@ export const getViewFromConfig = ({
break
}
case 2: {
if (segmentOne === 'reset') {
if (`/${segmentOne}` === config.admin.routes.reset) {
// --> /reset/:token
ViewToRender = {
Component: ResetPassword,

View File

@@ -85,7 +85,7 @@ export const generatePageMetadata = async ({ config: configPromise, params }: Ar
break
}
case 2: {
if (segmentOne === 'reset') {
if (`/${segmentOne}` === config.admin.routes.reset) {
// --> /reset/:token
meta = await generateResetPasswordMetadata({ config, i18n })
}

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
"keywords": [
"admin panel",

View File

@@ -150,7 +150,7 @@ export const forgotPasswordOperation = async <TSlug extends CollectionSlug>(
: `${protocol}//${req.headers.get('host')}`
let html = `${req.t('authentication:youAreReceivingResetPassword')}
<a href="${serverURL}${config.routes.admin}/${config.admin.routes.reset}/${token}">${serverURL}${config.routes.admin}/${config.admin.routes.reset}/${token}</a>
<a href="${serverURL}${config.routes.admin}${config.admin.routes.reset}/${token}">${serverURL}${config.routes.admin}${config.admin.routes.reset}/${token}</a>
${req.t('authentication:youDidNotRequestPassword')}`
if (typeof collectionConfig.auth.forgotPassword.generateEmailHTML === 'function') {

View File

@@ -0,0 +1,9 @@
import type { BeginTransaction } from './types.js'
/**
* Default implementation of `beginTransaction` that returns a resolved promise of null
*/
export function defaultBeginTransaction(): BeginTransaction {
const promiseSingleton: Promise<null> = Promise.resolve(null)
return () => promiseSingleton
}

View File

@@ -9,11 +9,11 @@ export interface BaseDatabaseAdapter {
* Start a transaction, requiring commitTransaction() to be called for any changes to be made.
* @returns an identifier for the transaction or null if one cannot be established
*/
beginTransaction?: BeginTransaction
beginTransaction: BeginTransaction
/**
* Persist the changes made since the start of the transaction.
*/
commitTransaction?: CommitTransaction
commitTransaction: CommitTransaction
/**
* Open the connection to the database
@@ -116,7 +116,7 @@ export interface BaseDatabaseAdapter {
/**
* Abort any changes since the start of the transaction.
*/
rollbackTransaction?: RollbackTransaction
rollbackTransaction: RollbackTransaction
/**
* A key-value store of all sessions open (used for transactions)
*/

View File

@@ -0,0 +1 @@
export { da } from '@payloadcms/translations/languages/da'

View File

@@ -1,6 +1,6 @@
import type { SanitizedJoins } from '../../collections/config/types.js'
import type { Config } from '../../config/types.js'
import type { JoinField, RelationshipField } from './types.js'
import type { JoinField, RelationshipField, UploadField } from './types.js'
import { APIError } from '../../errors/index.js'
import { InvalidFieldJoin } from '../../errors/InvalidFieldJoin.js'
@@ -33,7 +33,7 @@ export const sanitizeJoinField = ({
if (!joinCollection) {
throw new InvalidFieldJoin(field)
}
let joinRelationship: RelationshipField | undefined
let joinRelationship: RelationshipField | UploadField
const pathSegments = field.on.split('.') // Split the schema path into segments
let currentSegmentIndex = 0
@@ -49,9 +49,10 @@ export const sanitizeJoinField = ({
if ('name' in field && field.name === currentSegment) {
// Check if this is the last segment in the path
if (
currentSegmentIndex === pathSegments.length - 1 &&
'type' in field &&
field.type === 'relationship'
(currentSegmentIndex === pathSegments.length - 1 &&
'type' in field &&
field.type === 'relationship') ||
field.type === 'upload'
) {
joinRelationship = field // Return the matched field
next()

View File

@@ -1125,6 +1125,7 @@ type SharedRelationshipPropertiesClient = FieldBaseClient &
type RelationshipAdmin = {
allowCreate?: boolean
allowEdit?: boolean
components?: {
Error?: CustomComponent<
RelationshipFieldErrorClientComponent | RelationshipFieldErrorServerComponent
@@ -1142,7 +1143,7 @@ type RelationshipAdminClient = {
Label?: MappedComponent
} & AdminClient['components']
} & AdminClient &
Pick<RelationshipAdmin, 'allowCreate' | 'isSortable'>
Pick<RelationshipAdmin, 'allowCreate' | 'allowEdit' | 'isSortable'>
export type PolymorphicRelationshipField = {
admin?: {

View File

@@ -751,6 +751,7 @@ export { sanitizeConfig } from './config/sanitize.js'
export type * from './config/types.js'
export { combineQueries } from './database/combineQueries.js'
export { createDatabaseAdapter } from './database/createDatabaseAdapter.js'
export { defaultBeginTransaction } from './database/defaultBeginTransaction.js'
export { default as flattenWhereToOperators } from './database/flattenWhereToOperators.js'
export { getLocalizedPaths } from './database/getLocalizedPaths.js'
export { createMigration } from './database/migrations/createMigration.js'

View File

@@ -25,8 +25,7 @@ export async function initTransaction(req: PayloadRequest): Promise<boolean> {
return transactionID
})
await req.transactionID
return !!req.transactionID
return !!(await req.transactionID)
}
return false
}

View File

@@ -15,5 +15,9 @@ export const getQueryDraftsSort = (sort: string): string => {
orderBy = sort.substring(1)
}
if (orderBy === 'id') {
return `${direction}parent`
}
return `${direction}version.${orderBy}`
}

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-cloud-storage",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The official cloud storage plugin for Payload CMS",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-cloud",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The official Payload Cloud plugin",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-form-builder",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Form builder plugin for Payload CMS",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The official Nested Docs plugin for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-redirects",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Redirects plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-search",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Search plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-seo",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "SEO plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-stripe",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Stripe plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The officially supported Lexical richtext adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {
@@ -52,22 +52,22 @@
"translateNewKeys": "node --no-deprecation --import @swc-node/register/esm-register scripts/translateNewKeys.ts"
},
"dependencies": {
"@lexical/headless": "0.17.0",
"@lexical/link": "0.17.0",
"@lexical/list": "0.17.0",
"@lexical/mark": "0.17.0",
"@lexical/markdown": "0.17.0",
"@lexical/react": "0.17.0",
"@lexical/rich-text": "0.17.0",
"@lexical/selection": "0.17.0",
"@lexical/utils": "0.17.0",
"@lexical/headless": "0.18.0",
"@lexical/link": "0.18.0",
"@lexical/list": "0.18.0",
"@lexical/mark": "0.18.0",
"@lexical/markdown": "0.18.0",
"@lexical/react": "0.18.0",
"@lexical/rich-text": "0.18.0",
"@lexical/selection": "0.18.0",
"@lexical/utils": "0.18.0",
"@payloadcms/translations": "workspace:*",
"@payloadcms/ui": "workspace:*",
"@types/uuid": "10.0.0",
"bson-objectid": "2.0.4",
"dequal": "2.0.3",
"escape-html": "1.0.3",
"lexical": "0.17.0",
"lexical": "0.18.0",
"react-error-boundary": "4.0.13",
"uuid": "10.0.0"
},
@@ -77,7 +77,7 @@
"@babel/preset-env": "^7.24.5",
"@babel/preset-react": "^7.24.1",
"@babel/preset-typescript": "^7.24.1",
"@lexical/eslint-plugin": "0.17.0",
"@lexical/eslint-plugin": "0.18.0",
"@payloadcms/eslint-config": "workspace:*",
"@types/escape-html": "1.0.4",
"@types/json-schema": "7.0.15",
@@ -95,18 +95,18 @@
"peerDependencies": {
"@faceless-ui/modal": "3.0.0-beta.2",
"@faceless-ui/scroll-info": "2.0.0-beta.0",
"@lexical/headless": "0.17.0",
"@lexical/link": "0.17.0",
"@lexical/list": "0.17.0",
"@lexical/mark": "0.17.0",
"@lexical/markdown": "0.17.0",
"@lexical/react": "0.17.0",
"@lexical/rich-text": "0.17.0",
"@lexical/selection": "0.17.0",
"@lexical/table": "0.17.0",
"@lexical/utils": "0.17.0",
"@lexical/headless": "0.18.0",
"@lexical/link": "0.18.0",
"@lexical/list": "0.18.0",
"@lexical/mark": "0.18.0",
"@lexical/markdown": "0.18.0",
"@lexical/react": "0.18.0",
"@lexical/rich-text": "0.18.0",
"@lexical/selection": "0.18.0",
"@lexical/table": "0.18.0",
"@lexical/utils": "0.18.0",
"@payloadcms/next": "workspace:*",
"lexical": "0.17.0",
"lexical": "0.18.0",
"payload": "workspace:*",
"react": "^19.0.0 || ^19.0.0-rc-5dcb0097-20240918",
"react-dom": "^19.0.0 || ^19.0.0-rc-5dcb0097-20240918"

View File

@@ -122,4 +122,10 @@ export {
BlockNode,
} from '../../features/blocks/client/nodes/BlocksNode.js'
export {
$createInlineBlockNode,
$isInlineBlockNode,
InlineBlockNode,
} from '../../features/blocks/client/nodes/InlineBlocksNode.js'
export { FieldsDrawer } from '../../utilities/fieldsDrawer/Drawer.js'

View File

@@ -56,17 +56,20 @@ export const InlineBlockComponent: React.FC<Props> = (props) => {
const $onDelete = useCallback(
(event: KeyboardEvent) => {
if (isSelected && $isNodeSelection($getSelection())) {
const deleteSelection = $getSelection()
if (isSelected && $isNodeSelection(deleteSelection)) {
event.preventDefault()
const node = $getNodeByKey(nodeKey)
if ($isInlineBlockNode(node)) {
node.remove()
return true
}
editor.update(() => {
deleteSelection.getNodes().forEach((node) => {
if ($isInlineBlockNode(node)) {
node.remove()
}
})
})
}
return false
},
[isSelected, nodeKey],
[editor, isSelected],
)
const onClick = useCallback(
(payload: MouseEvent) => {

View File

@@ -58,47 +58,6 @@ function computeSelectionCount(selection: TableSelection): {
}
}
// This is important when merging cells as there is no good way to re-merge weird shapes (a result
// of selecting merged cells and non-merged)
function isTableSelectionRectangular(selection: TableSelection): boolean {
const nodes = selection.getNodes()
const currentRows: Array<number> = []
let currentRow: null | TableRowNode = null
let expectedColumns: null | number = null
let currentColumns = 0
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if ($isTableCellNode(node)) {
const row = node.getParentOrThrow()
if (!$isTableRowNode(row)) {
throw new Error('Expected CellNode to have a RowNode parent')
}
if (currentRow !== row) {
if (expectedColumns !== null && currentColumns !== expectedColumns) {
return false
}
if (currentRow !== null) {
expectedColumns = currentColumns
}
currentRow = row
currentColumns = 0
}
const colSpan = node.__colSpan
for (let j = 0; j < colSpan; j++) {
if (currentRows[currentColumns + j] === undefined) {
currentRows[currentColumns + j] = 0
}
currentRows[currentColumns + j] += node.__rowSpan
}
currentColumns += colSpan
}
}
return (
(expectedColumns === null || currentColumns === expectedColumns) &&
currentRows.every((v) => v === currentRows[0])
)
}
function $canUnmerge(): boolean {
const selection = $getSelection()
if (
@@ -183,10 +142,8 @@ function TableActionMenu({
if ($isTableSelection(selection)) {
const currentSelectionCounts = computeSelectionCount(selection)
updateSelectionCounts(computeSelectionCount(selection))
setCanMergeCells(
isTableSelectionRectangular(selection) &&
(currentSelectionCounts.columns > 1 || currentSelectionCounts.rows > 1),
)
setCanMergeCells(currentSelectionCounts.columns > 1 || currentSelectionCounts.rows > 1)
}
// Unmerge cell
setCanUnmergeCell($canUnmerge())
@@ -252,9 +209,9 @@ function TableActionMenu({
throw new Error('Expected to find tableElement in DOM')
}
const tableSelection = getTableObserverFromTableElement(tableElement)
if (tableSelection !== null) {
tableSelection.clearHighlight()
const tableObserver = getTableObserverFromTableElement(tableElement)
if (tableObserver !== null) {
tableObserver.clearHighlight()
}
tableNode.markDirty()
@@ -374,12 +331,13 @@ function TableActionMenu({
throw new Error('Expected table row')
}
const newStyle = tableCellNode.getHeaderStyles() ^ TableCellHeaderStates.ROW
tableRow.getChildren().forEach((tableCell) => {
if (!$isTableCellNode(tableCell)) {
throw new Error('Expected table cell')
}
tableCell.toggleHeaderStyle(TableCellHeaderStates.ROW)
tableCell.setHeaderStyles(newStyle, TableCellHeaderStates.ROW)
})
clearTableSelection()
@@ -400,6 +358,7 @@ function TableActionMenu({
throw new Error('Expected table cell to be inside of table row.')
}
const newStyle = tableCellNode.getHeaderStyles() ^ TableCellHeaderStates.COLUMN
for (let r = 0; r < tableRows.length; r++) {
const tableRow = tableRows[r]
@@ -419,7 +378,20 @@ function TableActionMenu({
throw new Error('Expected table cell')
}
tableCell.toggleHeaderStyle(TableCellHeaderStates.COLUMN)
tableCell.setHeaderStyles(newStyle, TableCellHeaderStates.COLUMN)
}
clearTableSelection()
onClose()
})
}, [editor, tableCellNode, clearTableSelection, onClose])
const toggleRowStriping = useCallback(() => {
editor.update(() => {
if (tableCellNode.isAttached()) {
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode)
if (tableNode) {
tableNode.setRowStriping(!tableNode.getRowStriping())
}
}
clearTableSelection()
@@ -470,6 +442,14 @@ function TableActionMenu({
</React.Fragment>
) : null}
<button
className="item"
data-test-id="table-row-striping"
onClick={() => toggleRowStriping()}
type="button"
>
<span className="text">Toggle Row Striping</span>
</button>
<button
className="item"
data-test-id="table-insert-row-above"

View File

@@ -1,6 +1,6 @@
'use client'
import type { TableCellNode, TableDOMCell, TableMapType, TableMapValueType } from '@lexical/table'
import type { TableCellNode, TableDOMCell, TableMapType } from '@lexical/table'
import type { LexicalEditor } from 'lexical'
import type { JSX, MouseEventHandler } from 'react'
@@ -13,6 +13,7 @@ import {
$isTableCellNode,
$isTableRowNode,
getDOMCellFromTarget,
TableNode,
} from '@lexical/table'
import { calculateZoomLevel } from '@lexical/utils'
import { $getNearestNodeFromDOMNode } from 'lexical'
@@ -32,7 +33,7 @@ type MousePosition = {
type MouseDraggingDirection = 'bottom' | 'right'
const MIN_ROW_HEIGHT = 33
const MIN_COLUMN_WIDTH = 50
const MIN_COLUMN_WIDTH = 92
function TableCellResizer({ editor }: { editor: LexicalEditor }): JSX.Element {
const targetRef = useRef<HTMLElement | null>(null)
@@ -59,6 +60,20 @@ function TableCellResizer({ editor }: { editor: LexicalEditor }): JSX.Element {
return (event.buttons & 1) === 1
}
useEffect(() => {
return editor.registerNodeTransform(TableNode, (tableNode) => {
if (tableNode.getColWidths()) {
return tableNode
}
const numColumns = tableNode.getColumnCount()
const columnWidth = MIN_COLUMN_WIDTH
tableNode.setColWidths(Array(numColumns).fill(columnWidth))
return tableNode
})
}, [editor])
useEffect(() => {
const onMouseMove = (event: MouseEvent) => {
setTimeout(() => {
@@ -119,13 +134,12 @@ function TableCellResizer({ editor }: { editor: LexicalEditor }): JSX.Element {
}
const removeRootListener = editor.registerRootListener((rootElement, prevRootElement) => {
rootElement?.addEventListener('mousemove', onMouseMove)
rootElement?.addEventListener('mousedown', onMouseDown)
rootElement?.addEventListener('mouseup', onMouseUp)
prevRootElement?.removeEventListener('mousemove', onMouseMove)
prevRootElement?.removeEventListener('mousedown', onMouseDown)
prevRootElement?.removeEventListener('mouseup', onMouseUp)
rootElement?.addEventListener('mousemove', onMouseMove)
rootElement?.addEventListener('mousedown', onMouseDown)
rootElement?.addEventListener('mouseup', onMouseUp)
})
return () => {
@@ -155,7 +169,8 @@ function TableCellResizer({ editor }: { editor: LexicalEditor }): JSX.Element {
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode)
const tableRowIndex = $getTableRowIndexFromTableCellNode(tableCellNode)
const tableRowIndex =
$getTableRowIndexFromTableCellNode(tableCellNode) + tableCellNode.getRowSpan() - 1
const tableRows = tableNode.getChildren()
@@ -186,27 +201,6 @@ function TableCellResizer({ editor }: { editor: LexicalEditor }): JSX.Element {
[activeCell, editor],
)
const getCellNodeWidth = (
cell: TableCellNode,
activeEditor: LexicalEditor,
): number | undefined => {
const width = cell.getWidth()
if (width !== undefined) {
return width
}
const domCellNode = activeEditor.getElementByKey(cell.getKey())
if (domCellNode == null) {
return undefined
}
const computedStyle = getComputedStyle(domCellNode)
return (
domCellNode.clientWidth -
parseFloat(computedStyle.paddingLeft) -
parseFloat(computedStyle.paddingRight)
)
}
const getCellNodeHeight = (
cell: TableCellNode,
activeEditor: LexicalEditor,
@@ -244,21 +238,18 @@ function TableCellResizer({ editor }: { editor: LexicalEditor }): JSX.Element {
throw new Error('TableCellResizer: Table column not found.')
}
for (let row = 0; row < tableMap.length; row++) {
const cell: TableMapValueType = tableMap[row][columnIndex]
if (
cell.startRow === row &&
(columnIndex === tableMap[row].length - 1 ||
tableMap[row][columnIndex].cell !== tableMap[row][columnIndex + 1].cell)
) {
const width = getCellNodeWidth(cell.cell, editor)
if (width === undefined) {
continue
}
const newWidth = Math.max(width + widthChange, MIN_COLUMN_WIDTH)
cell.cell.setWidth(newWidth)
}
const colWidths = tableNode.getColWidths()
if (!colWidths) {
return
}
const width = colWidths[columnIndex]
if (width === undefined) {
return
}
const newColWidths = [...colWidths]
const newWidth = Math.max(width + widthChange, MIN_COLUMN_WIDTH)
newColWidths[columnIndex] = newWidth
tableNode.setColWidths(newColWidths)
},
{ tag: 'skip-scroll-into-view' },
)

View File

@@ -8,7 +8,7 @@
overflow-y: scroll;
overflow-x: scroll;
table-layout: fixed;
width: max-content;
width: fit-content;
margin: 0 25px 30px 0;
::selection {
@@ -20,13 +20,16 @@
}
}
&__tableRowStriping tr:nth-child(even) {
background-color: var(--theme-elevation-100);
}
&__tableSelected {
outline: 2px solid rgb(60, 132, 244);
}
&__tableCell {
border: 1px solid var(--theme-elevation-200);
min-width: 75px;
vertical-align: top;
text-align: start;
padding: 6px 8px;

View File

@@ -118,7 +118,7 @@ export const TablePlugin: PluginComponent = () => {
COMMAND_PRIORITY_EDITOR,
),
)
}, [cellContext, editor, toggleModal])
}, [cellContext, drawerSlug, editor, toggleModal])
return (
<React.Fragment>

View File

@@ -6,7 +6,6 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection.js'
import { addClassNamesToElement, mergeRegister, removeClassNamesFromElement } from '@lexical/utils'
import {
$getNodeByKey,
$getSelection,
$isNodeSelection,
CLICK_COMMAND,
@@ -31,17 +30,20 @@ export function HorizontalRuleComponent({ nodeKey }: { nodeKey: NodeKey }) {
const $onDelete = useCallback(
(event: KeyboardEvent) => {
if (isSelected && $isNodeSelection($getSelection())) {
const deleteSelection = $getSelection()
if (isSelected && $isNodeSelection(deleteSelection)) {
event.preventDefault()
const node = $getNodeByKey(nodeKey)
if ($isHorizontalRuleNode(node)) {
node.remove()
return true
}
editor.update(() => {
deleteSelection.getNodes().forEach((node) => {
if ($isHorizontalRuleNode(node)) {
node.remove()
}
})
})
}
return false
},
[isSelected, nodeKey],
[editor, isSelected],
)
useEffect(() => {

View File

@@ -99,18 +99,21 @@ const Component: React.FC<Props> = (props) => {
const $onDelete = useCallback(
(payload: KeyboardEvent) => {
if (isSelected && $isNodeSelection($getSelection())) {
const deleteSelection = $getSelection()
if (isSelected && $isNodeSelection(deleteSelection)) {
const event: KeyboardEvent = payload
event.preventDefault()
const node = $getNodeByKey(nodeKey!)
if ($isRelationshipNode(node)) {
node.remove()
return true
}
editor.update(() => {
deleteSelection.getNodes().forEach((node) => {
if ($isRelationshipNode(node)) {
node.remove()
}
})
})
}
return false
},
[isSelected, nodeKey],
[editor, isSelected],
)
const onClick = useCallback(
(payload: MouseEvent) => {

View File

@@ -126,17 +126,20 @@ const Component: React.FC<ElementProps> = (props) => {
const $onDelete = useCallback(
(event: KeyboardEvent) => {
if (isSelected && $isNodeSelection($getSelection())) {
const deleteSelection = $getSelection()
if (isSelected && $isNodeSelection(deleteSelection)) {
event.preventDefault()
const node = $getNodeByKey(nodeKey)
if ($isUploadNode(node)) {
node.remove()
return true
}
editor.update(() => {
deleteSelection.getNodes().forEach((node) => {
if ($isUploadNode(node)) {
node.remove()
}
})
})
}
return false
},
[isSelected, nodeKey],
[editor, isSelected],
)
useEffect(() => {

View File

@@ -61,7 +61,7 @@ export function lexicalEditor(props?: LexicalEditorProps): LexicalRichTextAdapte
'@lexical/selection',
'@lexical/utils',
],
targetVersion: '0.17.0',
targetVersion: '0.18.0',
},
],
})

View File

@@ -221,19 +221,34 @@
&__listItem {
font-size: base(0.8);
margin: 0 0 0.4em base(0.8);
margin: 0 0 0.4em 40px;
}
&__listItem[dir='rtl'] {
margin: 0 40px 0.4em 0;
}
&__listItemChecked,
&__listItemUnchecked {
position: relative;
margin-inline: 0;
padding-left: base(1.2);
padding-right: base(1.2);
// Instead of having margin-left: 40px like other list-items or indented paragraphs,
// we use padding-left: 25px + margin-left: 15px = 40px, so that the click position
// calculation in `CheckListPlugin` matches the checkbox
margin-left: 15px;
padding-left: 25px;
list-style-type: none;
outline: none;
}
// See comment above for why we need this
&__listItemUnchecked[dir='rtl'],
&__listItemChecked[dir='rtl'] {
margin-left: 0;
padding-left: 0;
padding-right: 25px;
margin-right: 15px;
}
&__listItemChecked {
text-decoration: line-through;
}

View File

@@ -92,6 +92,7 @@ export const LexicalEditorTheme: EditorThemeClasses = {
tableCellSelected: 'LexicalEditorTheme__tableCellSelected',
tableCellSortedIndicator: 'LexicalEditorTheme__tableCellSortedIndicator',
tableResizeRuler: 'LexicalEditorTheme__tableCellResizeRuler',
tableRowStriping: 'LexicalEditorTheme__tableRowStriping',
tableSelected: 'LexicalEditorTheme__tableSelected',
text: {
bold: 'LexicalEditorTheme__textBold',

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-slate",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "The officially supported Slate richtext adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-azure",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Payload storage adapter for Azure Blob Storage",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-gcs",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Payload storage adapter for Google Cloud Storage",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-s3",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Payload storage adapter for Amazon S3",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-uploadthing",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Payload storage adapter for uploadthing",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/storage-vercel-blob",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"description": "Payload storage adapter for Vercel Blob Storage",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/translations",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -4,6 +4,7 @@ import { ar } from '../languages/ar.js'
import { az } from '../languages/az.js'
import { bg } from '../languages/bg.js'
import { cs } from '../languages/cs.js'
import { da } from '../languages/da.js'
import { de } from '../languages/de.js'
import { en } from '../languages/en.js'
import { es } from '../languages/es.js'
@@ -38,6 +39,7 @@ export const translations = {
az,
bg,
cs,
da,
de,
en,
es,

View File

@@ -19,6 +19,10 @@ export const importDateFNSLocale = async (locale: string): Promise<Locale> => {
case 'cs':
result = (await import('date-fns/locale/cs')).cs
break
case 'da':
result = (await import('date-fns/locale/da')).da
break
case 'de':
result = (await import('date-fns/locale/de')).de

View File

@@ -0,0 +1,456 @@
import type { DefaultTranslationsObject, Language } from '../types.js'
export const daTranslations: DefaultTranslationsObject = {
authentication: {
account: 'Konto',
accountOfCurrentUser: 'Den nuværende brugers konto',
accountVerified: 'Konto verifieret.',
alreadyActivated: 'Allerede aktiveret',
alreadyLoggedIn: 'Allerede logget ind',
apiKey: 'API nøgle',
authenticated: 'Godkendt',
backToLogin: 'Tilbage til login',
beginCreateFirstUser: 'For at starte, opret en bruger.',
changePassword: 'Skift adgangskode',
checkYourEmailForPasswordReset:
'Tjek din email for at finde linket der vil give adgang til at ændre din adgangskode',
confirmGeneration: 'Bekræft generering',
confirmPassword: 'Bekræft adgangskode',
createFirstUser: 'Opret bruger',
emailNotValid: 'Ugyldig email',
emailOrUsername: 'Email eller brugernavn',
emailSent: 'Email sendt',
emailVerified: 'Email verificeret.',
enableAPIKey: 'Aktiver API nøgle',
failedToUnlock: 'Kunne ikke låse op',
forceUnlock: 'Tving oplåsning',
forgotPassword: 'Glemt adgangskode',
forgotPasswordEmailInstructions:
'Indtast email nedenunder. Du vil modtage en email med instruktioner i hvordan du nulstiller din adgangskode.',
forgotPasswordQuestion: 'Glemt adgangskode?',
forgotPasswordUsernameInstructions:
'Indtast brugernavn nedenunder. Instruktioner i hvordan du nulstiller din adgangskode vil blive sendt til den email der er tilknyttet brugeren.',
generate: 'Generer',
generateNewAPIKey: 'Generer ny API nøgle.',
generatingNewAPIKeyWillInvalidate:
'Generering af en ny API nøgle vil <1>ugyldiggøre</1> den tidligere nøgle. Vil du forsætte?',
lockUntil: 'Lås indtil',
logBackIn: 'Log på igen',
loggedIn: 'For at logge på med en anden bruger, skal du først <0>logge ud</0>.',
loggedInChangePassword: 'For at ændre din adgangskode, gå til <0>konto</0> og ændr den der.',
loggedOutInactivity: 'Du er blevet logget ud grundet inaktivitet.',
loggedOutSuccessfully: 'Du er logget ud.',
loggingOut: 'Logger ud...',
login: 'Login',
loginAttempts: 'Login forsøg',
loginUser: 'Login bruger',
loginWithAnotherUser: 'For at logge på med en anden bruger, skal du først <0>logge ud</0>.',
logOut: 'Log ud',
logout: 'Log ud',
logoutSuccessful: 'Log ud succesfuldt.',
logoutUser: 'Log ud bruger',
newAccountCreated:
'En ny bruger er blevet oprettet. <a href="{{serverURL}}">{{serverURL}}</a> Klik på linket eller kopier URL for at verificere din email: <a href="{{verificationURL}}">{{verificationURL}}</a><br> Efter verificeringen af din email, kan du logge ind.',
newAPIKeyGenerated: 'Ny API nøgle genereret.',
newPassword: 'Ny adgangskode',
passed: 'Godkendt',
passwordResetSuccessfully: 'Adgangskode nulstillet.',
resetPassword: 'Nulstil adgangskode',
resetPasswordExpiration: 'Nulstil udløbsdato for adgangskoden',
resetPasswordToken: 'Nulstil adgangskode token',
resetYourPassword: 'Nulstil din adgangskode',
stayLoggedIn: 'Forbliv logget ind',
successfullyRegisteredFirstUser: 'Bruger registreret.',
successfullyUnlocked: 'Låst op',
tokenRefreshSuccessful: 'Tokenopdatering blev gennemført med succes.',
unableToVerify: 'Kan ikke verificere',
username: 'Brugernavn',
usernameNotValid: 'Brugernavnet er ugyldigt.',
verified: 'Bekræftet',
verifiedSuccessfully: 'Bekræftet succesfuldt',
verify: 'Bekræft',
verifyUser: 'Bekræft bruger',
verifyYourEmail: 'Bekræft din email',
youAreInactive:
'Du har ikke været aktiv i et stykke tid og vil snart blive logget automatisk ud. Vil du forblive logget ind?',
youAreReceivingResetPassword:
'Du modtager dette, fordi du eller en anden har anmodet om at nulstille adgangskoden til din konto. Klik venligst på følgende link, eller indsæt det i din browser for at fuldføre processen:',
youDidNotRequestPassword:
'Hvis du ikke har anmodet om dette, skal du blot ignorere denne e-mail, og din adgangskode vil forblive uændret',
},
error: {
accountAlreadyActivated: 'Denne konto er allerede blevet aktiveret.',
autosaving: 'Der opstod et problem under autosaving af dette dokument.',
correctInvalidFields: 'Venligst korriger ugyldige felter.',
deletingFile: 'Der opstod en fejl under sletning af filen.',
deletingTitle:
'Der opstod en fejl under sletningen {{title}}. Tjek din forbindelse eller prøv igen.',
emailOrPasswordIncorrect: 'Email eller brugernavn er forkert.',
followingFieldsInvalid_one: 'Feltet er ugyldigt:',
followingFieldsInvalid_other: 'Felterne er ugyldige:',
incorrectCollection: 'Forkert samling',
invalidFileType: 'Ugyldig filtype',
invalidFileTypeValue: 'Ugyldig filtype: {{value}}',
loadingDocument: 'Der opstod et problem med at loade dokumentet med ID {{id}}.',
localesNotSaved_one: 'Følgende lokalitet kunne ikke gemmes:',
localesNotSaved_other: 'Følgende lokaliteter kunne ikke gemmes:',
logoutFailed: 'Log ud mislykket.',
missingEmail: 'Mangler email.',
missingIDOfDocument: 'Mangler ID af dokument til opdatering.',
missingIDOfVersion: 'ID for version mangler.',
missingRequiredData: 'Mangler påkrævet data.',
noFilesUploaded: 'Ingen filer blev uploadet.',
noMatchedField: 'Ingen matchende felt fundet for "{{label}}"',
notAllowedToAccessPage: 'Du har ikke adgang til denne side.',
notAllowedToPerformAction: 'Du har ikke adgang til denne handling.',
notFound: 'Den anmodede ressource blev ikke fundet.',
noUser: 'Ingen bruger',
previewing: 'Der opstod et problem med at vise dokumentet.',
problemUploadingFile: 'Der opstod et problem under uploadingen af filen.',
tokenInvalidOrExpired: 'Token er enten ugyldig eller udløbet.',
tokenNotProvided: 'Token ikke angivet.',
unableToDeleteCount: 'Kunne ikke slette {{count}} mangler {{total}} {{label}}.',
unableToUpdateCount: 'Kunne ikke slette {{count}} mangler {{total}} {{label}}.',
unauthorized: 'Uautoriseret, log in for at gennemføre handlingen.',
unknown: 'En ukendt fejl er opstået.',
unPublishingDocument: 'Der opstod et problem med at ophæve udgivelsen af dette dokument.',
unspecific: 'En fejl er opstået.',
userEmailAlreadyRegistered: 'Email allerede registreret.',
userLocked: 'Denne bruger er låst på grund af for mange fejlede loginforsøg',
usernameAlreadyRegistered: 'Brugernavn allerede registeret.',
usernameOrPasswordIncorrect: 'Bruger navn eller adgangskode er forkert.',
valueMustBeUnique: 'Værdien skal være unik',
verificationTokenInvalid: 'Verifikationstoken er ugyldigt.',
},
fields: {
addLabel: 'Tilføj {{label}}',
addLink: 'Tilføj Link',
addNew: 'Tilføj ny',
addNewLabel: 'Tilføj ny {{label}}',
addRelationship: 'Tilføj forhold',
addUpload: 'Tilføj upload',
block: 'blok',
blocks: 'blokke',
blockType: 'Blok type',
chooseBetweenCustomTextOrDocument:
'Vælg mellem at indtaste en brugerdefineret tekst-URL eller linke til et andet dokument.',
chooseDocumentToLink: 'Vælg et dokument at linke til',
chooseFromExisting: 'Vælg fra eksiterende',
chooseLabel: 'Vælg {{label}}',
collapseAll: 'Skjul alt"',
customURL: 'Brugerdefineret URL',
editLabelData: 'Rediger {{label}} data',
editLink: 'Rediger link',
editRelationship: 'Rediger forhold',
enterURL: 'Indtast URL',
internalLink: 'Intern link',
itemsAndMore: '{{items}} og {{count}} mere',
labelRelationship: '{{label}} forhold',
latitude: 'breddegrad',
linkedTo: 'Linket til <0>{{label}}</0>',
linkType: 'Link type',
longitude: 'Længdegrad',
newLabel: 'Ny {{label}}',
openInNewTab: 'Åben i ny fane',
passwordsDoNotMatch: 'Adgangskoder matcher ikke.',
relatedDocument: 'Relateret dokument',
relationTo: 'Relateret til',
removeRelationship: 'Fjern forhold',
removeUpload: 'Fjern upload',
saveChanges: 'Gem ændringer',
searchForBlock: 'Søg efter blok',
selectExistingLabel: 'Vælg eksisterende {{label}}',
selectFieldsToEdit: 'Vælg felter at redigere',
showAll: 'Vis alle',
swapRelationship: 'Byt forhold',
swapUpload: 'Byt upload',
textToDisplay: 'Tekst der skal vises',
toggleBlock: 'Skift blok',
uploadNewLabel: 'Upload ny {{label}}',
},
general: {
aboutToDelete: 'Du er ved at slette {{label}} <1>{{title}}</1>. Er du sikker?',
aboutToDeleteCount_many: 'Du er ved at slette {{count}} {{label}}',
aboutToDeleteCount_one: 'Du er ved at slette {{count}} {{label}}',
aboutToDeleteCount_other: 'Du er ved at slette {{count}} {{label}}',
addBelow: 'Tilføj under',
addFilter: 'Tilføj filter',
adminTheme: 'Admin tema',
and: 'Og',
anotherUserTakenOver: 'En anden bruger har overtaget denne ressource.',
applyChanges: 'Tilføj ændringer',
ascending: 'Stigende',
automatic: 'Automatisk',
backToDashboard: 'Tilbage til dashboard',
cancel: 'Anuller',
changesNotSaved:
'Dine ændringer er ikke blevet gemt. Hvis du forlader siden, vil din ændringer gå tabt.',
clearAll: 'Ryd alt',
close: 'Luk',
collapse: 'Skjul',
collections: 'Samlinger',
columns: 'Kolonner',
columnToSort: 'Kolonne at sortere',
confirm: 'Bekræft',
confirmDeletion: 'Bekræft sletning',
confirmDuplication: 'Bekræft duplikering',
copied: 'Kopieret',
copy: 'Kopier',
create: 'Opret',
created: 'Oprettet',
createdAt: 'Oprettet til',
createNew: 'Opret ny',
createNewLabel: 'Opret ny {{label}}',
creating: 'Opretter',
creatingNewLabel: 'Opretter ny {{label}}',
currentlyEditing: 'Du redigerer i øjeblikket',
custom: 'Tilpasset',
dark: 'Mørk',
dashboard: 'Dashboard',
delete: 'Slet',
deletedCountSuccessfully: 'Slettet {{count}} {{label}}.',
deletedSuccessfully: 'Slettet.',
deleting: 'Sletter...',
depth: 'Dybde',
descending: 'Faldende',
deselectAllRows: 'Fjern markering af alle rækker',
document: 'Dokument',
documentLocked: 'Dette dokument er låst',
documents: 'Dokumenter',
duplicate: 'Duplikér',
duplicateWithoutSaving: 'Dupliker uden at gemme ændringer',
edit: 'Redigere',
editedSince: 'Dette dokument er blevet redigeret siden du startede',
editing: 'Rediger',
editingLabel_many: 'Rediger {{count}} {{label}}',
editingLabel_one: 'Rediger {{count}} {{label}}',
editingLabel_other: 'Rediger {{count}} {{label}}',
editingTakenOver: 'En anden bruger har overtaget redigeringen af dette dokument',
editLabel: 'Redigere {{label}}',
email: 'Email',
emailAddress: 'e-mailadresse',
enterAValue: 'Indtast en værdi',
error: 'Fejl',
errors: 'Fejl',
fallbackToDefaultLocale: 'Tilbagefald til standardlokalitet',
false: 'Falsk',
filter: 'Filter',
filters: 'Filtre',
filterWhere: 'Filter {{label}} hvor',
globals: 'Globale',
goBack: 'Gå tilbage',
isEditing: 'redigerer',
language: 'Sprog',
lastModified: 'Sidst ændret',
leaveAnyway: 'Forlad alligevel',
leaveWithoutSaving: 'Forlad uden at gemme',
light: 'Lys',
livePreview: 'Live-forhåndsvisning',
loading: 'Loader',
locale: 'Lokalitet',
locales: 'Lokaliteter',
menu: 'Menu',
moveDown: 'Ryk ned',
moveUp: 'Ryk op',
newPassword: 'Ny adgangskode',
next: 'Næste',
noFiltersSet: 'Ingen filtre angivet',
noLabel: '<Ingen {{label}}>',
none: 'Ingen',
noOptions: 'Ingen muligheder',
noResults:
'No {{label}} fundet. Enten findes der endnu ingen {{label}}, eller også matcher ingen af de filtre angivet ovenfor.',
notFound: 'Ikke fundet',
nothingFound: 'Intet fundet',
noValue: 'Ingen værdi',
of: 'Af',
only: 'kun',
open: 'Åben',
or: 'Eller',
order: 'Rækkefølge',
pageNotFound: 'Siden blev ikke fundet',
password: 'Adgangskode',
payloadSettings: 'Payload-indstillinger',
perPage: 'Per side: {{limit}}',
previous: 'Tidligere',
remove: 'Fjern',
reset: 'Nulstil',
row: 'Række',
rows: 'Rækker',
save: 'Gem',
saving: 'Gemmer...',
searchBy: 'Søg efter {{label}}',
selectAll: 'Vælg alle {{count}} {{label}}',
selectAllRows: 'Vælg alle rækker',
selectedCount: '{{count}} {{label}} valgt',
selectValue: 'Vælg en værdi',
showAllLabel: 'Vis alle {{label}}',
sorryNotFound: 'Beklager—der er intet, der svarer til din handling.',
sort: 'Sorter',
sortByLabelDirection: 'Sorter efter {{label}} {{direction}}',
stayOnThisPage: 'Forbliv på siden',
submissionSuccessful: 'Indsendt.',
submit: 'Send',
submitting: 'Sender...',
success: 'Succes',
successfullyCreated: '{{label}} oprettet.',
successfullyDuplicated: '{{label}} duplikeret.',
takeOver: 'Overtag',
thisLanguage: 'Dansk',
titleDeleted: '{{label}} "{{title}}" slettet.',
true: 'Sandt',
unauthorized: 'Uautoriseret',
unsavedChangesDuplicate: 'Du har ikke-gemte ændringer. Vil du fortsætte med at duplikere?',
untitled: 'Uden titel',
updatedAt: 'Opdateret ved',
updatedCountSuccessfully: 'Opdateret {{count}} {{label}} successfully.',
updatedSuccessfully: 'Opdateret.',
updating: 'Opdaterer',
uploading: 'Uploader',
user: 'Bruger',
username: 'Brugernavn',
users: 'Brugere',
value: 'Værdi',
viewReadOnly: 'Vis kun-læsning',
welcome: 'Velkommen',
},
operators: {
contains: 'Indeholder',
equals: 'Lig med',
exists: 'Eksisterer',
intersects: 'Intersekterer',
isGreaterThan: 'Er større end',
isGreaterThanOrEqualTo: 'Er større end eller lig med',
isIn: 'Er i',
isLessThan: 'Er mindre end',
isLessThanOrEqualTo: 'Er mindre end eller lig med',
isLike: 'Ligner',
isNotEqualTo: 'Er ikke lig med',
isNotIn: 'Er ikke i',
near: 'Tæt på',
within: 'Inden for',
},
upload: {
addFile: 'Tilføj fil',
addFiles: 'Tilføj Filer',
bulkUpload: 'Masseupload',
crop: 'Beskær',
cropToolDescription:
'Træk i hjørnerne af det valgte område, tegn et nyt område eller juster værdierne nedenfor.',
dragAndDrop: 'Træk og slip en fil',
dragAndDropHere: 'Eller træk og slip en fil her',
editImage: 'Rediger billede',
fileName: 'Filnavn',
fileSize: 'Filstørrelse',
filesToUpload: 'Filer til upload',
fileToUpload: 'Fil til upload',
focalPoint: 'Fokuspunkt',
focalPointDescription:
'Træk fokuspunktet direkte på forhåndsvisningen eller juster værdierne nedenfor.',
height: 'Højde',
lessInfo: 'Mindre info',
moreInfo: 'Mere info',
pasteURL: 'Indsæt URL',
previewSizes: 'Forhåndsvisningsstørrelser',
selectCollectionToBrowse: 'Vælg en samling for at browse',
selectFile: 'Vælg en fil',
setCropArea: 'Indstil beskæringsområde',
setFocalPoint: 'Indstil fokuspunkt',
sizes: 'Størrelse',
sizesFor: 'Størrelse for {{label}}',
width: 'Bredde',
},
validation: {
emailAddress: 'Indtast venligst en gyldig e-mailadresse.',
enterNumber: 'Indtast venligst et gyldigt nummer.',
fieldHasNo: 'Dette felt har ingen {{label}}',
greaterThanMax: '{{value}} er større end det maksimalt tilladte {{label}} of {{max}}.',
invalidInput: 'Dette felt har et ugyldigt indtastning.',
invalidSelection: 'Dette felt har en ugyldig valg.',
invalidSelections: 'Dette felt har følgende ugyldige valg:',
lessThanMin: '{{value}} er mindre end den minimum tilladte {{label}} of {{min}}.',
limitReached: 'Grænse nået, kun {{max}} elementer kan tilføjes.',
longerThanMin: 'Denne værdi skal være længere end den minimale længde på {{minLength}} tegn.',
notValidDate: '"{{value}}" er ikke en gyldig dato.',
required: 'Dette felt er påkrævet.',
requiresAtLeast: 'Dette felt kræver mindst {{count}} {{label}}.',
requiresNoMoreThan: 'Dette felt kræver maks {{count}} {{label}}.',
requiresTwoNumbers: 'Dette felt kræver to numre.',
shorterThanMax: 'Denne værdi skal være kortere end den maksimale længde af {{maxLength}} tegn.',
trueOrFalse: 'Denne værdi kan kun være lig med sandt eller falsk.',
username:
'Indtast et brugernavn. Kan indeholde bogstaver, tal, bindestreger, punktum og underscores.',
validUploadID: 'Dette felt er ikke en gyldig upload-ID.',
},
version: {
type: 'Type',
aboutToPublishSelection:
'Du er ved at offentliggøre alt {{label}} i denne sektion. Er du sikker?',
aboutToRestore:
'Du er ved at gendanne dette {{label}} dokument til den tilstand, det var i den {{versionDate}}.',
aboutToRestoreGlobal:
'Du er ved at gendanne den globale {{label}} til den tilstand, den var i den {{versionDate}}.',
aboutToRevertToPublished:
'Du er ved at tilbagerulle dette dokuments ændringer til dets offentliggjorte tilstand. Er du sikker?',
aboutToUnpublish: 'Du er ved at afpublicere dette dokument. Er du sikker?',
aboutToUnpublishSelection:
'Du er ved at afpublicere alt {{label}} i denne sektion. Er du sikker?',
autosave: 'Autosave',
autosavedSuccessfully: 'Autosaved gennemført.',
autosavedVersion: 'Autosaved version',
changed: 'Ændret',
compareVersion: 'Sammenlign version med:',
confirmPublish: 'Bekræft offentliggørelse',
confirmRevertToSaved: 'Bekræft tilbagerulning til gemt',
confirmUnpublish: 'Bekræft afpublicering',
confirmVersionRestoration: 'Bekræft versionens gendannelse',
currentDocumentStatus: 'Nuværende {{docStatus}} dokument',
currentDraft: 'Nuværende kladde',
currentPublishedVersion: 'Nuværende offentliggjort version',
draft: 'Kladde',
draftSavedSuccessfully: 'Kladde gemt.',
lastSavedAgo: 'Sidst gemt {{distance}}',
noFurtherVersionsFound: 'Ingen yderligere versioner fundet',
noRowsFound: 'Ingen {{label}} fundet',
noRowsSelected: 'Ingen {{label}} valgt',
preview: 'Forhåndsvisning',
previouslyPublished: 'Tidligere offentliggjort',
problemRestoringVersion: 'Der opstod et problem med at gendanne denne version',
publish: 'Offentliggør',
publishChanges: 'Offentliggør ændringer',
published: 'Offentliggjort',
publishIn: 'Offentliggør i',
publishing: 'Offentliggør',
restoreAsDraft: 'Gendan som kladde',
restoredSuccessfully: 'Gendannet.',
restoreThisVersion: 'Gendan denne version',
restoring: 'Gendanner...',
reverting: 'Tilbageruller...',
revertToPublished: 'Tilbagerul til offentliggjort',
saveDraft: 'Gem kladde',
selectLocales: 'Vælg lokaliteter, der skal vises',
selectVersionToCompare: 'Vælg en version til sammenligning',
showingVersionsFor: 'Viser versioner for:',
showLocales: 'Vis lokaliteter:',
status: 'Status',
unpublish: 'Afpublicer',
unpublishing: 'Afpublicerer...',
version: 'Version',
versionCount_many: '{{count}} versioner fundet',
versionCount_none: 'Ingen versioner fundet',
versionCount_one: '{{count}} version fundet',
versionCount_other: '{{count}} version fundet',
versionCreatedOn: '{{version}} oprettet den:',
versionID: 'Versions-ID',
versions: 'Versioner',
viewingVersion: 'Se versionen for {{entityLabel}} {{documentTitle}}',
viewingVersionGlobal: 'Se version for det globale {{entityLabel}}',
viewingVersions: 'Se versioner for {{entityLabel}} {{documentTitle}}',
viewingVersionsGlobal: 'Se versioner for det global {{entityLabel}}',
},
}
export const da: Language = {
dateFNSKey: 'da',
translations: daTranslations,
}

View File

@@ -3,30 +3,30 @@ import type { DefaultTranslationsObject, Language } from '../types.js'
export const hrTranslations: DefaultTranslationsObject = {
authentication: {
account: 'Račun',
accountOfCurrentUser: 'Račun od trenutnog korisnika',
accountOfCurrentUser: 'Račun trenutnog korisnika',
accountVerified: 'Račun je uspješno verificiran.',
alreadyActivated: 'Već aktivirano',
alreadyLoggedIn: 'Već prijavljen',
alreadyLoggedIn: 'Već prijavljeni',
apiKey: 'API ključ',
authenticated: 'Autenticiran',
backToLogin: 'Nazad na prijavu',
beginCreateFirstUser: 'Za početak, kreiraj svog prvog korisnika.',
changePassword: 'Promjeni lozinku',
backToLogin: 'Natrag na prijavu',
beginCreateFirstUser: 'Za početak, izradite prvog korisnika.',
changePassword: 'Promijeni lozinku',
checkYourEmailForPasswordReset:
'Provjerite email s poveznicom koja će Vam omogućiti sigurnu promjenu lozinke.',
confirmGeneration: 'Potvrdi kreiranje',
'Provjerite e-mail s poveznicom koja će Vam omogućiti sigurnu promjenu lozinke.',
confirmGeneration: 'Potvrdi generiranje',
confirmPassword: 'Potvrdi lozinku',
createFirstUser: 'Kreiraj prvog korisnika',
emailNotValid: 'Email nije ispravan',
emailOrUsername: 'E-mail ili Korisničko ime',
emailSent: 'Email poslan',
emailVerified: 'Email uspješno provjeren.',
createFirstUser: 'Izradi prvog korisnika',
emailNotValid: 'E-mail nije ispravan',
emailOrUsername: 'E-mail ili korisničko ime',
emailSent: 'E-mail poslan',
emailVerified: 'E-mail uspješno verificiran.',
enableAPIKey: 'Omogući API ključ',
failedToUnlock: 'Neuspješno otključavanje.',
failedToUnlock: 'Otključavanje nije uspjelo.',
forceUnlock: 'Prisilno otključaj',
forgotPassword: 'Zaboravljena lozinka',
forgotPasswordEmailInstructions:
'Molim unesite svoj email. Primit ćete poruku s uputama za ponovno postavljanje lozinke.',
'Molimo unesite svoju e-mail adresu. Primit ćete poruku s uputama za ponovno postavljanje lozinke.',
forgotPasswordQuestion: 'Zaboravljena lozinka?',
forgotPasswordUsernameInstructions:
'Molimo unesite vaše korisničko ime ispod. Upute o tome kako resetirati vašu lozinku bit će poslane na e-adresu povezanu s vašim korisničkim imenom.',
@@ -34,14 +34,15 @@ export const hrTranslations: DefaultTranslationsObject = {
generateNewAPIKey: 'Generiraj novi API ključ',
generatingNewAPIKeyWillInvalidate:
'Generiranje novog API ključa će <1>poništiti</1> prethodni ključ. Jeste li sigurni da želite nastaviti?',
newAPIKeyGenerated: 'New API ključ generiran.',
lockUntil: 'Zaključaj dok',
logBackIn: 'Ponovna prijava',
logBackIn: 'Ponovno se prijavite',
loggedIn: 'Za prijavu s drugim korisničkim računom potrebno je prvo <0>odjaviti se</0>',
loggedInChangePassword:
'Da biste promijenili lozinku, otvorite svoj <0>račun</0> i promijenite lozinku tamo.',
loggedOutInactivity: 'Odjavljeni se zbog neaktivnosti.',
loggedOutSuccessfully: 'Uspješno ste odjavljeni..',
loggingOut: 'Odjavljujem se...',
'Da biste promijenili lozinku, otvorite svoj <0>račun</0> i promijenite je tamo.',
loggedOutInactivity: 'Odjavljeni ste zbog neaktivnosti.',
loggedOutSuccessfully: 'Uspješno ste odjavljeni.',
loggingOut: 'Odjava u tijeku...',
login: 'Prijava',
loginAttempts: 'Pokušaji prijave',
loginUser: 'Prijava korisnika',
@@ -52,16 +53,15 @@ export const hrTranslations: DefaultTranslationsObject = {
logoutSuccessful: 'Odjava uspješna.',
logoutUser: 'Odjava korisnika',
newAccountCreated:
'Novi račun je kreiran. Pristupite računu klikom na <a href="{{serverURL}}">{{serverURL}}</a>. Molim kliknite na sljedeći link ili zalijepite URL, koji se nalazi ispod, u preglednik da biste potvrdili svoj email: <a href="{{verificationURL}}">{{verificationURL}}</a><br> Nakon što potvrdite email, moći ćete se prijaviti.',
newAPIKeyGenerated: 'Novi API ključ generiran.',
'Novi račun je izrađen. Pristupite računu klikom na: <a href="{{serverURL}}">{{serverURL}}</a>. Molimo kliknite na sljedeću poveznicu ili zalijepite URL, koji se nalazi ispod, u preglednik da biste potvrdili svoju e-mail adresu: <a href="{{verificationURL}}">{{verificationURL}}</a><br> Nakon što potvrdite e-mail adresu, moći ćete se prijaviti.',
newPassword: 'Nova lozinka',
passed: 'Autentifikacija je prošla',
passwordResetSuccessfully: 'Lozinka uspješno resetirana.',
resetPassword: 'Restartiranje lozinke',
resetPasswordExpiration: 'Restartiranje roka trajanja lozinke',
resetPasswordToken: 'Restartiranje lozinke tokena',
resetYourPassword: 'Restartiraj svoju lozinku',
stayLoggedIn: 'Ostani prijavljen',
resetPassword: 'Resetiranje lozinke',
resetPasswordExpiration: 'Rok trajanja resetiranja lozinke',
resetPasswordToken: 'Resetiranje tokena lozinke',
resetYourPassword: 'Resetirajte svoju lozinku',
stayLoggedIn: 'Ostanite prijavljeni',
successfullyRegisteredFirstUser: 'Uspješno registriran prvi korisnik.',
successfullyUnlocked: 'Uspješno otključano',
tokenRefreshSuccessful: 'Osvježavanje tokena uspješno.',
@@ -72,32 +72,32 @@ export const hrTranslations: DefaultTranslationsObject = {
verifiedSuccessfully: 'Uspješno potvrđeno',
verify: 'Potvrdi',
verifyUser: 'Potvrdi korisnika',
verifyYourEmail: 'Potvrdi svoj email',
verifyYourEmail: 'Potvrdi svoju e-mail adresu',
youAreInactive:
'Neaktivni ste neko vrijeme i uskoro ćete biti automatski odjavljeni zbog vlastite sigurnosti. Želite li ostati prijavljeni?',
'Neaktivni ste već neko vrijeme i uskoro ćete biti automatski odjavljeni zbog vlastite sigurnosti. Želite li ostati prijavljeni?',
youAreReceivingResetPassword:
'Primili ste ovo jer ste Vi (ili netko drugi) zatražili promjenu lozinke za Vaš račun. Molim kliknite na poveznicu ili zalijepite ovo u svoje preglednik da biste završili proces:',
'Primili ste ovo jer ste Vi (ili netko drugi) zatražili promjenu lozinke za Vaš račun. Molimo kliknite na poveznicu ili zalijepite ovo u svoje preglednik da biste završili proces:',
youDidNotRequestPassword:
'Ako niste zatražili ovo, molim ignorirajte ovaj email i Vaša lozinka ostat će nepromijenjena.',
'Ako niste zatražili ovo, molimo ignorirajte ovaj e-mail i Vaša će lozinka ostati nepromijenjena.',
},
error: {
accountAlreadyActivated: 'Ovaj račun je već aktiviran.',
autosaving: 'Nastao je problem pri automatskom spremanju ovog dokumenta.',
correctInvalidFields: 'Molim ispravite nevaljana polja.',
correctInvalidFields: 'Molimo ispravite neispravna polja.',
deletingFile: 'Dogodila se pogreška pri brisanju datoteke.',
deletingTitle:
'Dogodila se pogreška pri brisanju {{title}}. Molim provjerite svoju internetsku vezu i pokušajte ponovno.',
emailOrPasswordIncorrect: 'Email ili lozinka netočni.',
followingFieldsInvalid_one: ' Ovo polje je nevaljano:',
followingFieldsInvalid_other: 'Ova polja su nevaljana:',
incorrectCollection: 'Nevaljana kolekcija',
invalidFileType: 'Nevaljan tip datoteke',
invalidFileTypeValue: 'Nevaljan tip datoteke: {{value}}',
loadingDocument: 'Pojavio se problem pri učitavanju dokumenta čiji je ID {{id}}.',
'Dogodila se pogreška pri brisanju {{title}}. Molimo provjerite svoju internet vezu i pokušajte ponovno.',
emailOrPasswordIncorrect: 'E-mail adresa ili lozinka netočni.',
followingFieldsInvalid_one: 'Ovo polje je neispravno:',
followingFieldsInvalid_other: 'Ova polja su neispravna:',
incorrectCollection: 'Neispravna kolekcija',
invalidFileType: 'Neispravan tip datoteke',
invalidFileTypeValue: 'Neispravan tip datoteke: {{value}}',
loadingDocument: 'Došlo je do problema pri učitavanju dokumenta čiji je ID {{id}}.',
localesNotSaved_one: 'Sljedeću lokalnu postavku nije bilo moguće spremiti:',
localesNotSaved_other: 'Sljedeće lokalne postavke nije bilo moguće spremiti:',
logoutFailed: 'Odjava nije uspjela.',
missingEmail: 'Nedostaje email.',
missingEmail: 'Nedostaje e-mail.',
missingIDOfDocument: 'Nedostaje ID dokumenta da bi se ažurirao.',
missingIDOfVersion: 'Nedostaje ID verzije.',
missingRequiredData: 'Nedostaju obvezni podaci.',
@@ -107,22 +107,22 @@ export const hrTranslations: DefaultTranslationsObject = {
notAllowedToPerformAction: 'Nemate dopuštenje izvršiti ovu radnju.',
notFound: 'Traženi resurs nije pronađen.',
noUser: 'Nema korisnika',
previewing: 'Pojavio se problem pri pregledavanju ovog dokumenta.',
problemUploadingFile: 'Pojavio se problem pri učitavanju datoteke.',
tokenInvalidOrExpired: 'Token je nevaljan ili je istekao.',
previewing: 'Došlo je do problema pri pregledavanju ovog dokumenta.',
problemUploadingFile: 'Došlo je do problema pri učitavanju datoteke.',
tokenInvalidOrExpired: 'Token je neispravan ili je istekao.',
tokenNotProvided: 'Token nije pružen.',
unPublishingDocument: 'Došlo je do problema pri poništavanju objave ovog dokumenta.',
unableToDeleteCount: 'Nije moguće izbrisati {{count}} od {{total}} {{label}}.',
unableToUpdateCount: 'Nije moguće ažurirati {{count}} od {{total}} {{label}}.',
unauthorized: 'Neovlašten, morate biti prijavljeni da biste uputili ovaj zahtjev.',
unauthorized: 'Neovlašteno, morate biti prijavljeni da biste uputili ovaj zahtjev.',
unknown: 'Došlo je do nepoznate pogreške.',
unPublishingDocument: 'Pojavio se problem pri poništavanju objave ovog dokumenta.',
unspecific: 'Došlo je do pogreške.',
userEmailAlreadyRegistered: 'Korisnik s navedenom e-poštom je već registriran.',
userEmailAlreadyRegistered: 'Korisnik s navedenom e-mail adresom je već registriran.',
userLocked: 'Ovaj korisnik je zaključan zbog previše neuspješnih pokušaja prijave.',
usernameAlreadyRegistered: 'Korisnik s navedenim korisničkim imenom već je registriran.',
usernameOrPasswordIncorrect: 'Korisničko ime ili lozinka koju ste unijeli su netočni.',
valueMustBeUnique: 'Vrijednost mora biti jedinstvena.',
verificationTokenInvalid: 'Verifikacijski token je nevaljan.',
verificationTokenInvalid: 'Verifikacijski token je neispravan.',
},
fields: {
addLabel: 'Dodaj {{label}}',
@@ -149,7 +149,7 @@ export const hrTranslations: DefaultTranslationsObject = {
itemsAndMore: '{{items}} i {{count}} više',
labelRelationship: '{{label}} veza',
latitude: 'Zemljopisna širina',
linkedTo: 'Povezabi sa <0>{{label}}</0>',
linkedTo: 'Povezan s <0>{{label}}</0>',
linkType: 'Tip poveznce',
longitude: 'Zemljopisna dužina',
newLabel: 'Novo {{label}}',
@@ -161,7 +161,7 @@ export const hrTranslations: DefaultTranslationsObject = {
removeUpload: 'Ukloni prijenos',
saveChanges: 'Spremi promjene',
searchForBlock: 'Potraži blok',
selectExistingLabel: 'Odaberi postojeće{{label}}',
selectExistingLabel: 'Odaberi postojeće {{label}}',
selectFieldsToEdit: 'Odaberite polja za uređivanje',
showAll: 'Pokaži sve',
swapRelationship: 'Zamijeni vezu',
@@ -178,7 +178,7 @@ export const hrTranslations: DefaultTranslationsObject = {
addBelow: 'Dodaj ispod',
addFilter: 'Dodaj filter',
adminTheme: 'Administratorska tema',
and: 'I',
and: 'i',
anotherUserTakenOver: 'Drugi korisnik je preuzeo uređivanje ovog dokumenta.',
applyChanges: 'Primijeni promjene',
ascending: 'Uzlazno',
@@ -197,21 +197,21 @@ export const hrTranslations: DefaultTranslationsObject = {
confirmDuplication: 'Potvrdi duplikaciju',
copied: 'Kopirano',
copy: 'Kopiraj',
create: 'Kreiraj',
create: 'Izradi',
created: 'Kreirano',
createdAt: 'Kreirano u',
createNew: 'Kreiraj novo',
createNewLabel: 'Kreiraj novo {{label}}',
creating: 'Kreira se',
creatingNewLabel: 'Kreiranje novog {{label}}',
createdAt: 'Izrađeno u',
createNew: 'Izradi novo',
createNewLabel: 'Izradi novo {{label}}',
creating: 'U izradi',
creatingNewLabel: 'Izrađivanje novog {{label}}',
currentlyEditing:
'trenutno uređuje ovaj dokument. Ako preuzmete, bit će im onemogućeno daljnje uređivanje i mogu izgubiti nespremljene promjene.',
custom: 'Prilagođen',
dark: 'Tamno',
dashboard: 'Nadzorna ploča',
delete: 'Obriši',
delete: 'Izbriši',
deletedCountSuccessfully: 'Uspješno izbrisano {{count}} {{label}}.',
deletedSuccessfully: 'Uspješno obrisano.',
deletedSuccessfully: 'Uspješno izbrisano.',
deleting: 'Brisanje...',
depth: 'Dubina',
descending: 'Silazno',
@@ -258,17 +258,16 @@ export const hrTranslations: DefaultTranslationsObject = {
next: 'Sljedeće',
noFiltersSet: 'Nema postavljenih filtera',
noLabel: '<Nema {{label}}>',
none: 'Nijedan',
noOptions: 'Nema opcija',
noResults:
'Nema pronađenih {{label}}. Ili {{label}} još uvijek ne postoji ili nijedan od odgovara postavljenim filterima.',
notFound: 'Nije pronađeno',
nothingFound: 'Ništa nije pronađeno',
none: 'Nijedan',
noOptions: 'Nema opcija',
noResults: 'Nije pronađen nijedan {{label}}. Ili {{label}} još uvijek ne postoji ili nijedan od odgovara postavljenim filterima.',
noValue: 'Bez vrijednosti',
of: 'Od',
of: 'od',
only: 'Samo',
open: 'Otvori',
or: 'Ili',
or: 'ili',
order: 'Poredak',
pageNotFound: 'Stranica nije pronađena',
password: 'Lozinka',
@@ -295,11 +294,11 @@ export const hrTranslations: DefaultTranslationsObject = {
submit: 'Podnesi',
submitting: 'Podnošenje...',
success: 'Uspjeh',
successfullyCreated: '{{label}} uspješno kreirano.',
successfullyCreated: '{{label}} uspješno izrađeno.',
successfullyDuplicated: '{{label}} uspješno duplicirano.',
takeOver: 'Preuzmi',
thisLanguage: 'Hrvatski',
titleDeleted: '{{label}} "{{title}}" uspješno obrisano.',
titleDeleted: '{{label}} "{{title}}" uspješno izbrisano.',
true: 'Istinito',
unauthorized: 'Neovlašteno',
unsavedChangesDuplicate: 'Imate nespremljene promjene. Želite li nastaviti s dupliciranjem?',
@@ -312,7 +311,7 @@ export const hrTranslations: DefaultTranslationsObject = {
user: 'Korisnik',
username: 'Korisničko ime',
users: 'Korisnici',
value: 'Attribute',
value: 'Vrijednost',
viewReadOnly: 'Pogledaj samo za čitanje',
welcome: 'Dobrodošli',
},
@@ -335,8 +334,8 @@ export const hrTranslations: DefaultTranslationsObject = {
upload: {
addFile: 'Dodaj datoteku',
addFiles: 'Dodaj datoteke',
bulkUpload: 'Masovno otpremanje',
crop: 'Usjev',
bulkUpload: 'Masovno dodavanje',
crop: 'Izreži',
cropToolDescription:
'Povucite kutove odabranog područja, nacrtajte novo područje ili prilagodite vrijednosti ispod.',
dragAndDrop: 'Povucite i ispustite datoteku',
@@ -363,13 +362,13 @@ export const hrTranslations: DefaultTranslationsObject = {
width: 'Širina',
},
validation: {
emailAddress: 'Molim unestie valjanu email adresu.',
enterNumber: 'Molim unesite valjani broj.',
emailAddress: 'Molimo unesite valjanu e-mail adresu.',
enterNumber: 'Molimo unesite valjani broj.',
fieldHasNo: 'Ovo polje nema {{label}}',
greaterThanMax: '{{value}} exceeds the maximum allowable {{label}} limit of {{max}}.',
invalidInput: 'Ovo polje ima nevaljan unos.',
invalidSelection: 'Ovo polje ima nevaljan odabir.',
invalidSelections: 'Ovo polje ima sljedeće nevaljane odabire:',
invalidInput: 'Ovo polje ima neispravan unos.',
invalidSelection: 'Ovo polje ima neispravan odabir.',
invalidSelections: 'Ovo polje ima sljedeće neispravne odabire:',
lessThanMin: '{{value}} is below the minimum allowable {{label}} limit of {{min}}.',
limitReached: 'Dosegnut je limit, može se dodati samo {{max}} stavki.',
longerThanMin: 'Ova vrijednost mora biti duža od minimalne dužine od {{minLength}} znakova',
@@ -386,14 +385,14 @@ export const hrTranslations: DefaultTranslationsObject = {
},
version: {
type: 'Tip',
aboutToPublishSelection: 'Upravo ćete objaviti sve {{label}} u izboru. Jesi li siguran?',
aboutToPublishSelection: 'Upravo ćete objaviti sve {{label}} u izboru. Jeste li sigurni?',
aboutToRestore: 'Vratit ćete {{label}} dokument u stanje u kojem je bio {{versionDate}}',
aboutToRestoreGlobal: 'Vratit ćete globalni {{label}} u stanje u kojem je bio {{versionDate}}.',
aboutToRevertToPublished:
'Vratit ćete promjene u dokumentu u objavljeno stanje. Jeste li sigurni? ',
aboutToUnpublish: 'Poništit ćete objavu ovog dokumenta. Jeste li sigurni?',
aboutToUnpublishSelection:
'Upravo ćete poništiti objavu svih {{label}} u odabiru. Jesi li siguran?',
'Upravo ćete poništiti objavu svih {{label}} u odabiru. Jeste li sigurni?',
autosave: 'Automatsko spremanje',
autosavedSuccessfully: 'Automatsko spremanje uspješno.',
autosavedVersion: 'Verzija automatski spremljenog dokumenta',
@@ -439,7 +438,7 @@ export const hrTranslations: DefaultTranslationsObject = {
versionCount_none: 'Nema pronađenih verzija',
versionCount_one: '{{count}} pronađena verzija',
versionCount_other: '{{count}} pronađenih verzija',
versionCreatedOn: '{{version}} kreiranih:',
versionCreatedOn: '{{version}} izrađenih:',
versionID: 'ID verzije',
versions: 'Verzije',
viewingVersion: 'Pregled verzije za {{entityLabel}} {{documentTitle}}',

View File

@@ -9,6 +9,7 @@ type DateFNSKeys =
| 'az'
| 'bg'
| 'cs'
| 'da'
| 'de'
| 'en-US'
| 'es'

View File

@@ -7,6 +7,7 @@ export const acceptedLanguages = [
'az',
'bg',
'cs',
'da',
'de',
'en',
'es',
@@ -51,7 +52,6 @@ export const acceptedLanguages = [
* 'ca',
* 'ca-ES-valencia',
* 'cy',
* 'da',
* 'el',
* 'en-GB',
* 'en-US',

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/ui",
"version": "3.0.0-beta.109",
"version": "3.0.0-beta.110",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -63,7 +63,12 @@ export type ReactSelectAdapterProps = {
disabled?: boolean
filterOption?:
| ((
{ data, label, value }: { data: Option; label: string; value: string },
{
allowEdit,
data,
label,
value,
}: { allowEdit: boolean; data: Option; label: string; value: string },
search: string,
) => boolean)
| undefined

View File

@@ -28,12 +28,12 @@ export const TableCellProvider: React.FC<{
return (
<TableCellContext.Provider
value={{
...contextToInherit,
cellData,
cellProps,
columnIndex,
customCellContext,
rowData,
...contextToInherit,
}}
>
{children}

View File

@@ -3,11 +3,12 @@ import type { Option } from '../../elements/ReactSelect/types.js'
import type { OptionGroup, Value } from './types.js'
type Args = {
allowEdit: boolean
options: OptionGroup[]
value: Value | Value[]
}
export const findOptionsByValue = ({ options, value }: Args): Option | Option[] => {
export const findOptionsByValue = ({ allowEdit, options, value }: Args): Option | Option[] => {
if (value || typeof value === 'number') {
if (Array.isArray(value)) {
return value.map((val) => {
@@ -25,7 +26,7 @@ export const findOptionsByValue = ({ options, value }: Args): Option | Option[]
}
})
return matchedOption
return matchedOption ? { allowEdit, ...matchedOption } : undefined
})
}
@@ -42,7 +43,7 @@ export const findOptionsByValue = ({ options, value }: Args): Option | Option[]
}
})
return matchedOption
return matchedOption ? { allowEdit, ...matchedOption } : undefined
}
return undefined

View File

@@ -46,6 +46,7 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) =>
_path: pathFromProps,
admin: {
allowCreate = true,
allowEdit = true,
className,
description,
isSortable = true,
@@ -576,7 +577,7 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) =>
}
}, [openDrawer, currentlyOpenRelationship])
const valueToRender = findOptionsByValue({ options, value })
const valueToRender = findOptionsByValue({ allowEdit, options, value })
if (!Array.isArray(valueToRender) && valueToRender?.value === 'null') {
valueToRender.value = null

View File

@@ -24,7 +24,7 @@ export const MultiValueLabel: React.FC<
} & MultiValueProps<Option>
> = (props) => {
const {
data: { label, relationTo, value },
data: { allowEdit, label, relationTo, value },
selectProps: { customProps: { draggableProps, onDocumentDrawerOpen } = {} } = {},
} = props
@@ -44,7 +44,7 @@ export const MultiValueLabel: React.FC<
}}
/>
</div>
{relationTo && hasReadPermission && (
{relationTo && hasReadPermission && allowEdit !== false && (
<Fragment>
<button
aria-label={`Edit ${label}`}

View File

@@ -25,7 +25,7 @@ export const SingleValue: React.FC<
> = (props) => {
const {
children,
data: { label, relationTo, value },
data: { allowEdit, label, relationTo, value },
selectProps: { customProps: { onDocumentDrawerOpen } = {} } = {},
} = props
@@ -39,7 +39,7 @@ export const SingleValue: React.FC<
<div className={`${baseClass}__label`}>
<div className={`${baseClass}__label-text`}>
<div className={`${baseClass}__text`}>{children}</div>
{relationTo && hasReadPermission && (
{relationTo && hasReadPermission && allowEdit !== false && (
<Fragment>
<button
aria-label={t('general:editLabel', { label })}

View File

@@ -2,6 +2,7 @@ import type { I18nClient } from '@payloadcms/translations'
import type { ClientCollectionConfig, ClientConfig, FilterOptionsResult } from 'payload'
export type Option = {
allowEdit: boolean
label: string
options?: Option[]
relationTo?: string

View File

@@ -10,6 +10,7 @@ import { useFieldProps } from '../../forms/FieldPropsProvider/index.js'
import { useField } from '../../forms/useField/index.js'
import { withCondition } from '../../forms/withCondition/index.js'
import { useConfig } from '../../providers/Config/index.js'
import { useLocale } from '../../providers/Locale/index.js'
import { useTranslation } from '../../providers/Translation/index.js'
import { isFieldRTL } from '../shared/index.js'
import './index.scss'
@@ -42,7 +43,6 @@ const TextareaFieldComponent: TextareaFieldClientComponent = (props) => {
required,
},
labelProps,
locale,
readOnly: readOnlyFromTopLevelProps,
validate,
} = props
@@ -50,6 +50,7 @@ const TextareaFieldComponent: TextareaFieldClientComponent = (props) => {
const readOnlyFromProps = readOnlyFromTopLevelProps || readOnlyFromAdmin
const { i18n } = useTranslation()
const locale = useLocale()
const {
config: { localization },

View File

@@ -153,6 +153,9 @@ export function UploadInput(props: UploadInputProps) {
collectionSlug: activeRelationTo,
})
/**
* Prevent initial retrieval of documents from running more than once
*/
const loadedValueDocsRef = React.useRef<boolean>(false)
const canCreate = useMemo(() => {
@@ -388,6 +391,7 @@ export function UploadInput(props: UploadInputProps) {
useEffect(() => {
async function loadInitialDocs() {
if (value) {
loadedValueDocsRef.current = true
const loadedDocs = await populateDocs(
Array.isArray(value) ? value : [value],
activeRelationTo,
@@ -398,8 +402,6 @@ export function UploadInput(props: UploadInputProps) {
)
}
}
loadedValueDocsRef.current = true
}
if (!loadedValueDocsRef.current) {

View File

@@ -389,7 +389,10 @@ const DocumentInfo: React.FC<
if (docAccessURL) {
const res = await fetch(`${serverURL}${api}${docAccessURL}?${qs.stringify(params)}`, {
body: JSON.stringify(data),
body: JSON.stringify({
...(data || {}),
_status: 'draft',
}),
credentials: 'include',
headers: {
'Accept-Language': i18n.language,

View File

@@ -1,11 +1,2 @@
'use client'
import * as facelessUIImport from '@faceless-ui/scroll-info'
const { ScrollInfoProvider } =
facelessUIImport && 'ScrollInfoProvider' in facelessUIImport
? facelessUIImport
: { ScrollInfoProvider: undefined }
const { useScrollInfo } =
facelessUIImport && 'useScrollInfo' in facelessUIImport
? facelessUIImport
: { useScrollInfo: undefined }
export { ScrollInfoProvider, useScrollInfo }
export { ScrollInfoProvider, useScrollInfo } from '@faceless-ui/scroll-info'

354
pnpm-lock.yaml generated
View File

@@ -1229,35 +1229,35 @@ importers:
specifier: 2.0.0-beta.0
version: 2.0.0-beta.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)
'@lexical/headless':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/link':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/list':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/mark':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/markdown':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/react':
specifier: 0.17.0
version: 0.17.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)(yjs@13.6.18)
specifier: 0.18.0
version: 0.18.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)(yjs@13.6.18)
'@lexical/rich-text':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/selection':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/table':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/utils':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@payloadcms/next':
specifier: workspace:*
version: link:../next
@@ -1280,8 +1280,8 @@ importers:
specifier: 1.0.3
version: 1.0.3
lexical:
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
react:
specifier: 19.0.0-rc-5dcb0097-20240918
version: 19.0.0-rc-5dcb0097-20240918
@@ -1311,8 +1311,8 @@ importers:
specifier: ^7.24.1
version: 7.24.7(@babel/core@7.25.2)
'@lexical/eslint-plugin':
specifier: 0.17.0
version: 0.17.0(eslint@9.9.1(jiti@1.21.6))
specifier: 0.18.0
version: 0.18.0(eslint@9.9.1(jiti@1.21.6))
'@payloadcms/eslint-config':
specifier: workspace:*
version: link:../eslint-config
@@ -1643,11 +1643,11 @@ importers:
specifier: ^3.614.0
version: 3.629.0
'@lexical/headless':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@lexical/markdown':
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
'@payloadcms/db-mongodb':
specifier: workspace:*
version: link:../packages/db-mongodb
@@ -1781,8 +1781,8 @@ importers:
specifier: 4.0.0
version: 4.0.0
lexical:
specifier: 0.17.0
version: 0.17.0
specifier: 0.18.0
version: 0.18.0
next:
specifier: 15.0.0-canary.160
version: 15.0.0-canary.160(@playwright/test@1.46.0)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-24ec0eb-20240918)(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)(sass@1.77.4)
@@ -3594,82 +3594,82 @@ packages:
'@juggle/resize-observer@3.4.0':
resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==}
'@lexical/clipboard@0.17.0':
resolution: {integrity: sha512-wYtC6VJhuSxUZc69VTU+vBgzB4HQqhve2hLrr3v+3tR2aimx3KnKphCCP1TexCntxpEnOTPXafEgpOW/EVQE+Q==}
'@lexical/clipboard@0.18.0':
resolution: {integrity: sha512-ybc+hx14wj0n2ZjdOkLcZ02MRB3UprXjpLDXlByFIuVcZpUxVcp3NzA0UBPOKXYKvdt0bmgjnAsFWM5OSbwS0w==}
'@lexical/code@0.17.0':
resolution: {integrity: sha512-8zrgHzf27aYySfUVeSKw8YP/LkRlXHSwD03BKlkSZAb4HX/WC60SGmdXUhtyTIBucqe0pnuGsRYfR9euD0/tfw==}
'@lexical/code@0.18.0':
resolution: {integrity: sha512-VB8fRHIrB8QTqyZUvGBMVWP2tpKe3ArOjPdWAqgrS8MVFldqUhuTHcW+XJFkVxcEBYCXynNT29YRYtQhfQ+vDQ==}
'@lexical/devtools-core@0.17.0':
resolution: {integrity: sha512-0ftqWsoCb96oTc8Ok+uvjGAXZpsN9oc6ml3d46BdufdZyxHXC4qU3YVoPfLkgAHzH+4fQlNypu7u3Ym3dZ2rJg==}
'@lexical/devtools-core@0.18.0':
resolution: {integrity: sha512-gVgtEkLwGjz1frOmDpFJzDPFxPgAcC9n5ZaaZWHo5GLcptnQmkuLm1t+UInQWujXhFmcyJzfiqDaMJ8EIcb2Ww==}
peerDependencies:
react: 19.0.0-rc-5dcb0097-20240918
react-dom: 19.0.0-rc-5dcb0097-20240918
'@lexical/dragon@0.17.0':
resolution: {integrity: sha512-XSsrHVwhjBIVF9VN9MFm6Go8fquj5H/jlYuyNzemHq0tOli8NaoSovGc5q0LwXr88RPsuIt1jluazR7Q1+kxTQ==}
'@lexical/dragon@0.18.0':
resolution: {integrity: sha512-toD/y2/TgtG+eFVKXf65kDk/Mv02FwgmcGH18nyAabZnO1TLBaMYPkGFdTTZ8hVmQxqIu9nZuLWUbdIBMs8UWw==}
'@lexical/eslint-plugin@0.17.0':
resolution: {integrity: sha512-O6RyQBXAdi90jlthWwfOuxYG4zqzWkpNwsX1V6N8t5iH80Te04LsnfG+hIB/5V8rxm8WPkTjMrqAX3UEZy5Shg==}
'@lexical/eslint-plugin@0.18.0':
resolution: {integrity: sha512-i9tveFKOq6Bk5CFt7qoPJlxG16bbLApxfXevvs+PDfxiNCCTkcV/DB85rGAs6LMM0FMyEbIYbmaWpq0wOZ3FSA==}
peerDependencies:
eslint: '>=7.31.0 || ^8.0.0'
'@lexical/hashtag@0.17.0':
resolution: {integrity: sha512-E6nSoz9haB6JypQtYxG5OYr36AHgam/FBMu77OWNl1KsJbkP8nInm+P22QFsNnEvs4Hk6/0FJ5g42+lTEnGmIg==}
'@lexical/hashtag@0.18.0':
resolution: {integrity: sha512-bm+Sv7keguVYbUY0ngd+iAv2Owd3dePzdVkzkmw9Al8GPXkE5ll8fjq6Xjw2u3OVhf+9pTnesIo/AS7H+h0exw==}
'@lexical/headless@0.17.0':
resolution: {integrity: sha512-yKvXcq2F6S1lwDLcwv+bHht/al1LcFmidPT3rjISRxLX+/YjUcUT8MmvV773Du4piV4rFPbVlBPFBZfHJkDxXw==}
'@lexical/headless@0.18.0':
resolution: {integrity: sha512-GPUL7rTSYer+/g37blFbJ5MXDPCgMf1wT87Wr+IF7PdUb1D68NwePQxFBBTWMlT/wjm4YU1Qzcv5Izxldif5YQ==}
'@lexical/history@0.17.0':
resolution: {integrity: sha512-SfeUKAXf9pZpqee9rMOTt33V0J0p/AS9TZLT9Un9dU6wAaHfv6NFax1ND0JoG1a9YkTc539mufxVLNjsNRc0ag==}
'@lexical/history@0.18.0':
resolution: {integrity: sha512-c87J4ke1Sae03coElJay2Ikac/4OcA2OmhtNbt2gAi/XBtcsP4mPuz1yZfZf9XIe+weekObgjinvZekQ2AFw0g==}
'@lexical/html@0.17.0':
resolution: {integrity: sha512-sI458CEP/j+Gd2YEo1+vTax31ZAjdq5jmRJMgSKxzKlkVYAUY9eH5u3Y3awPLwLVXJHiIopMX02GeZytibuTiw==}
'@lexical/html@0.18.0':
resolution: {integrity: sha512-8lhba1DFnnobXgYm4Rk5Gr2tZedD4Gl6A/NKCt7whO/CET63vT3UnK2ggcVVgtIJG530Cv0bdZoJbJu5DauI5w==}
'@lexical/link@0.17.0':
resolution: {integrity: sha512-Kux6yvPit6y0ksPpwimv3seVrXAsggkqB6oT6oAVBaDpYuygVEwNDqg/rCTtB3mHQ4eeuU33mdK7MSXZ34bZRQ==}
'@lexical/link@0.18.0':
resolution: {integrity: sha512-GCYcbNTSTwJk0lr+GMc8nn6Meq44BZs3QL2d1B0skpZAspd8yI53sRS6HDy5P+jW5P0dzyZr/XJAU4U+7zsEEg==}
'@lexical/list@0.17.0':
resolution: {integrity: sha512-anDuSUykTv+lqyCwl1m+sThrB15OKCa00Eo68/d2HQSHDD3KNWgSx709dcR17bD9oT204yOhMJbQGywuzcEyGQ==}
'@lexical/list@0.18.0':
resolution: {integrity: sha512-DEWs9Scbg3+STZeE2O0OoG8SWnKnxQccObBzyeHRjn4GAN6JA7lgcAzfrdgp0fNWTbMM/ku876MmXKGnqhvg9Q==}
'@lexical/mark@0.17.0':
resolution: {integrity: sha512-Ynqh9KHXUcB9qLOTGC9s+bbWtawOwRStkeIeAugTqrwckyYWeDaePpyJ6IhBBJy1E1CfpiZn71NDeP+FuRjnXQ==}
'@lexical/mark@0.18.0':
resolution: {integrity: sha512-QA4YWfTP5WWnCnoH/RmfcsSZyhhd7oeFWDpfP7S8Bbmhz6kiPwGcsVr+uRQBBT56AqEX167xX2rX8JR6FiYZqA==}
'@lexical/markdown@0.17.0':
resolution: {integrity: sha512-6IuJ2l5p/Ma+VBUIStIRXwTC01GEzx21gvqqywuqBUzAOiMr1oRM+DGsQgrzZrcjX+LzUlZ5ZgjuWtK8XKVAZw==}
'@lexical/markdown@0.18.0':
resolution: {integrity: sha512-uSWwcK8eJw5C+waEhU5WoX8W+JxNZbKuFnZwsn5nsp+iQgqMj4qY6g0yJub4sq8vvh6jjl4vVXhXTq2up9aykw==}
'@lexical/offset@0.17.0':
resolution: {integrity: sha512-onE6SD2mIAwBLTT5v5fVBVtRg/NpQj+o10vTWJ1ImvEUERpSoCyHMTy3IMoSMuCRwuOG9C0cFEret2u+QS8Icw==}
'@lexical/offset@0.18.0':
resolution: {integrity: sha512-KGlboyLSxQAH5PMOlJmyvHlbYXZneVnKiHpfyBV5IUX5kuyB/eZbQEYcJP9saekfQ5Xb1FWXWmsZEo+sWtrrZA==}
'@lexical/overflow@0.17.0':
resolution: {integrity: sha512-dh+nQAmeobKvZFodWyzNh1ZjX043Patk/1Lwct9XmtAGMUdXL+tB0bbguWVcDfY8OYu1CTQGfbdq2oMEJYzwsg==}
'@lexical/overflow@0.18.0':
resolution: {integrity: sha512-3ATTwttVgZtVLq60ZUWbpbXBbpuMa3PZD5CxSP3nulviL+2I4phvacV4WUN+8wMeq+PGmuarl+cYfrFL02ii3g==}
'@lexical/plain-text@0.17.0':
resolution: {integrity: sha512-AEk+3ttbRyRi7m9UbU1CdLUtGsXh4FFZkBC12twV3U82lZHOdHocLlTutP+lcbYlGjeq6UF43NxOSGzsYEunsA==}
'@lexical/plain-text@0.18.0':
resolution: {integrity: sha512-L6yQpiwW0ZacY1oNwvRBxSuW2TZaUcveZLheJc8JzGcZoVxzII/CAbLZG8691VbNuKsbOURiNXZIsgwujKmo4Q==}
'@lexical/react@0.17.0':
resolution: {integrity: sha512-HZ3joq+5g2++2vo/6scTd60Y2bsu8ya8EUdopyudnmGZGKAcAPue9pLOlBaEpsYZ7vqTuGjiPgtEBfFzDy9rlg==}
'@lexical/react@0.18.0':
resolution: {integrity: sha512-DLvIbTsjvFIFqm+9zvAjEwuZHAbSxzZf1AGqf1lLctlL/Ran0f+8EZOv5jttELTe7xISZ2+xSXTLRfyxhNwGXQ==}
peerDependencies:
react: 19.0.0-rc-5dcb0097-20240918
react-dom: 19.0.0-rc-5dcb0097-20240918
'@lexical/rich-text@0.17.0':
resolution: {integrity: sha512-XJc8gQBSwppCkESQaNcGtyTaPXZaeCQDcUVpnDjDK0vM/ZZN8TErxbujwbSqA3kO2dBds9N8WxNboSwuncMBcQ==}
'@lexical/rich-text@0.18.0':
resolution: {integrity: sha512-xMANCB7WueMsmWK8qxik5FZN4ApyaHWHQILS9r4FTbdv/DlNepsR7Pt8kg2317xZ56NAueQLIdyyKYXG1nBrHw==}
'@lexical/selection@0.17.0':
resolution: {integrity: sha512-UTjlvyhFY/lmHtBaIaVRwYnRfO9gR4I32+PT7vHQr4v3VfcgS63YEGSgEZy3Gh1pfeJqaZATN58+jCuMAQXlWQ==}
'@lexical/selection@0.18.0':
resolution: {integrity: sha512-mJoMhmxeZLfM9K2JMYETs9u179IkHQUlgtYG5GZJHjKx2iUn+9KvJ9RVssq+Lusi7C/N42wWPGNHDPdUvFtxXg==}
'@lexical/table@0.17.0':
resolution: {integrity: sha512-RQF7IG0rGL2/bPaPFUIMgDA3QMdDflvXSnE7Udgbj9yMqSKhYkaERVfNyoLckDUSuusGJd6XV+qum6JWn0nSNA==}
'@lexical/table@0.18.0':
resolution: {integrity: sha512-TeTAnuFAAgVjm1QE8adRB3GFWN+DUUiS4vzGq+ynPRCtNdpmW27NmTkRMyxKsetUtt7nIFfj4DvLvor4RwqIpA==}
'@lexical/text@0.17.0':
resolution: {integrity: sha512-kFH0V6yjW8YswmoY7vHT4zHFDflGfamuUxTPHROpdnq/JMjHeaVwtmFBdrP0gknaC8XMRXdr3EsemQ7cbOoDPA==}
'@lexical/text@0.18.0':
resolution: {integrity: sha512-MTHSBeq3K0+lqSsP5oysBMnY4tPVhB8kAa2xBnEc3dYgXFxEEvJwZahbHNX93EPObtJkxXfUuI63Al4G3lYK8A==}
'@lexical/utils@0.17.0':
resolution: {integrity: sha512-B/n0rRGDmdMrqi2qnprLt6SntC6jb4JItLmPl8zDDdg7/HxMdLq3F93vogeiXQJn0mlNqgiENWHvLAy5K2C2uQ==}
'@lexical/utils@0.18.0':
resolution: {integrity: sha512-4s9dVpBZjqIaA/1q2GtfWFjKsv2Wqhjer0Zw2mcl1TIVN0zreXxcTKN316QppAWmSQJxVGvkWHjjaZJwl6/TSw==}
'@lexical/yjs@0.17.0':
resolution: {integrity: sha512-xJv3frcK/jskssLbzdY4yfBaM7+LWaZD4YjYkJ/bvRDTey2w+McF+SvsJ/yBA8YF1oaL3rT+0aIQJ7rfH+AxjA==}
'@lexical/yjs@0.18.0':
resolution: {integrity: sha512-rl7Rl9XIb3ygQEEHOFtACdXs3BE+UUUmdyNqB6kK9A6IRGz+w4Azp+qzt8It/t+c0oaSYHpAtcLNXg1amJz+kA==}
peerDependencies:
yjs: '>=13.5.22'
@@ -7144,8 +7144,8 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
lexical@0.17.0:
resolution: {integrity: sha512-cCFmANO5rIf34NF0go/hxp5S3V5Z8G2Rsa1FJy50qF2WM5EJNJ/MqN75TApjfgMkfrbO6gau3X12nCqwsT7aDg==}
lexical@0.18.0:
resolution: {integrity: sha512-3K/B0RpzjoW+Wj2E455wWXxkqxqK8UgdIiuqkOqdOsoSSo5mCkHOU6eVw7Nlmlr1MFvAMzGmz4RPn8NZaLQ2Mw==}
lib0@0.2.97:
resolution: {integrity: sha512-Q4d1ekgvufi9FiHkkL46AhecfNjznSL9MRNoJRQ76gBHS9OqU2ArfQK0FvBpuxgWeJeNI0LVgAYMIpsGeX4gYg==}
@@ -11999,157 +11999,159 @@ snapshots:
'@juggle/resize-observer@3.4.0': {}
'@lexical/clipboard@0.17.0':
'@lexical/clipboard@0.18.0':
dependencies:
'@lexical/html': 0.17.0
'@lexical/list': 0.17.0
'@lexical/selection': 0.17.0
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/html': 0.18.0
'@lexical/list': 0.18.0
'@lexical/selection': 0.18.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/code@0.17.0':
'@lexical/code@0.18.0':
dependencies:
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
prismjs: 1.29.0
'@lexical/devtools-core@0.17.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)':
'@lexical/devtools-core@0.18.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)':
dependencies:
'@lexical/html': 0.17.0
'@lexical/link': 0.17.0
'@lexical/mark': 0.17.0
'@lexical/table': 0.17.0
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/html': 0.18.0
'@lexical/link': 0.18.0
'@lexical/mark': 0.18.0
'@lexical/table': 0.18.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
react: 19.0.0-rc-5dcb0097-20240918
react-dom: 19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918)
'@lexical/dragon@0.17.0':
'@lexical/dragon@0.18.0':
dependencies:
lexical: 0.17.0
lexical: 0.18.0
'@lexical/eslint-plugin@0.17.0(eslint@9.9.1(jiti@1.21.6))':
'@lexical/eslint-plugin@0.18.0(eslint@9.9.1(jiti@1.21.6))':
dependencies:
eslint: 9.9.1(jiti@1.21.6)
'@lexical/hashtag@0.17.0':
'@lexical/hashtag@0.18.0':
dependencies:
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/headless@0.17.0':
'@lexical/headless@0.18.0':
dependencies:
lexical: 0.17.0
lexical: 0.18.0
'@lexical/history@0.17.0':
'@lexical/history@0.18.0':
dependencies:
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/html@0.17.0':
'@lexical/html@0.18.0':
dependencies:
'@lexical/selection': 0.17.0
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/selection': 0.18.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/link@0.17.0':
'@lexical/link@0.18.0':
dependencies:
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/list@0.17.0':
'@lexical/list@0.18.0':
dependencies:
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/mark@0.17.0':
'@lexical/mark@0.18.0':
dependencies:
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/markdown@0.17.0':
'@lexical/markdown@0.18.0':
dependencies:
'@lexical/code': 0.17.0
'@lexical/link': 0.17.0
'@lexical/list': 0.17.0
'@lexical/rich-text': 0.17.0
'@lexical/text': 0.17.0
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/code': 0.18.0
'@lexical/link': 0.18.0
'@lexical/list': 0.18.0
'@lexical/rich-text': 0.18.0
'@lexical/text': 0.18.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/offset@0.17.0':
'@lexical/offset@0.18.0':
dependencies:
lexical: 0.17.0
lexical: 0.18.0
'@lexical/overflow@0.17.0':
'@lexical/overflow@0.18.0':
dependencies:
lexical: 0.17.0
lexical: 0.18.0
'@lexical/plain-text@0.17.0':
'@lexical/plain-text@0.18.0':
dependencies:
'@lexical/clipboard': 0.17.0
'@lexical/selection': 0.17.0
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/clipboard': 0.18.0
'@lexical/selection': 0.18.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/react@0.17.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)(yjs@13.6.18)':
'@lexical/react@0.18.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)(yjs@13.6.18)':
dependencies:
'@lexical/clipboard': 0.17.0
'@lexical/code': 0.17.0
'@lexical/devtools-core': 0.17.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)
'@lexical/dragon': 0.17.0
'@lexical/hashtag': 0.17.0
'@lexical/history': 0.17.0
'@lexical/link': 0.17.0
'@lexical/list': 0.17.0
'@lexical/mark': 0.17.0
'@lexical/markdown': 0.17.0
'@lexical/overflow': 0.17.0
'@lexical/plain-text': 0.17.0
'@lexical/rich-text': 0.17.0
'@lexical/selection': 0.17.0
'@lexical/table': 0.17.0
'@lexical/text': 0.17.0
'@lexical/utils': 0.17.0
'@lexical/yjs': 0.17.0(yjs@13.6.18)
lexical: 0.17.0
'@lexical/clipboard': 0.18.0
'@lexical/code': 0.18.0
'@lexical/devtools-core': 0.18.0(react-dom@19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918))(react@19.0.0-rc-5dcb0097-20240918)
'@lexical/dragon': 0.18.0
'@lexical/hashtag': 0.18.0
'@lexical/history': 0.18.0
'@lexical/link': 0.18.0
'@lexical/list': 0.18.0
'@lexical/mark': 0.18.0
'@lexical/markdown': 0.18.0
'@lexical/overflow': 0.18.0
'@lexical/plain-text': 0.18.0
'@lexical/rich-text': 0.18.0
'@lexical/selection': 0.18.0
'@lexical/table': 0.18.0
'@lexical/text': 0.18.0
'@lexical/utils': 0.18.0
'@lexical/yjs': 0.18.0(yjs@13.6.18)
lexical: 0.18.0
react: 19.0.0-rc-5dcb0097-20240918
react-dom: 19.0.0-rc-5dcb0097-20240918(react@19.0.0-rc-5dcb0097-20240918)
react-error-boundary: 3.1.4(react@19.0.0-rc-5dcb0097-20240918)
transitivePeerDependencies:
- yjs
'@lexical/rich-text@0.17.0':
'@lexical/rich-text@0.18.0':
dependencies:
'@lexical/clipboard': 0.17.0
'@lexical/selection': 0.17.0
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/clipboard': 0.18.0
'@lexical/selection': 0.18.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/selection@0.17.0':
'@lexical/selection@0.18.0':
dependencies:
lexical: 0.17.0
lexical: 0.18.0
'@lexical/table@0.17.0':
'@lexical/table@0.18.0':
dependencies:
'@lexical/utils': 0.17.0
lexical: 0.17.0
'@lexical/clipboard': 0.18.0
'@lexical/utils': 0.18.0
lexical: 0.18.0
'@lexical/text@0.17.0':
'@lexical/text@0.18.0':
dependencies:
lexical: 0.17.0
lexical: 0.18.0
'@lexical/utils@0.17.0':
'@lexical/utils@0.18.0':
dependencies:
'@lexical/list': 0.17.0
'@lexical/selection': 0.17.0
'@lexical/table': 0.17.0
lexical: 0.17.0
'@lexical/list': 0.18.0
'@lexical/selection': 0.18.0
'@lexical/table': 0.18.0
lexical: 0.18.0
'@lexical/yjs@0.17.0(yjs@13.6.18)':
'@lexical/yjs@0.18.0(yjs@13.6.18)':
dependencies:
'@lexical/offset': 0.17.0
lexical: 0.17.0
'@lexical/offset': 0.18.0
'@lexical/selection': 0.18.0
lexical: 0.18.0
yjs: 13.6.18
'@libsql/client@0.6.2(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
@@ -16409,7 +16411,7 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
lexical@0.17.0: {}
lexical@0.18.0: {}
lib0@0.2.97:
dependencies:

View File

@@ -25,6 +25,7 @@
"@payloadcms/plugin-form-builder": "beta",
"@payloadcms/plugin-nested-docs": "beta",
"@payloadcms/plugin-redirects": "beta",
"@payloadcms/plugin-search": "beta",
"@payloadcms/plugin-seo": "beta",
"@payloadcms/richtext-lexical": "beta",
"@payloadcms/ui": "beta",
@@ -38,7 +39,7 @@
"geist": "^1.3.0",
"graphql": "^16.8.2",
"jsonwebtoken": "9.0.2",
"lexical": "0.17.0",
"lexical": "0.18.0",
"lucide-react": "^0.378.0",
"next": "15.0.0-canary.160",
"payload": "beta",

10116
templates/website/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,8 @@ import React from 'react'
import type { Header as HeaderType } from '@/payload-types'
import { CMSLink } from '@/components/Link'
import Link from 'next/link'
import { SearchIcon } from 'lucide-react'
export const HeaderNav: React.FC<{ header: HeaderType }> = ({ header }) => {
const navItems = header?.navItems || []
@@ -14,6 +16,10 @@ export const HeaderNav: React.FC<{ header: HeaderType }> = ({ header }) => {
{navItems.map(({ link }, i) => {
return <CMSLink key={i} {...link} appearance="link" />
})}
<Link href="/search">
<span className="sr-only">Search</span>
<SearchIcon className="w-5" />
</Link>
</nav>
)
}

View File

@@ -39,7 +39,7 @@ export default async function Page({ params: { slug = 'home' } }) {
})
// Remove this code once your website is seeded
if (!page) {
if (!page && slug === 'home') {
page = homeStatic
}

View File

@@ -3,6 +3,7 @@ import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
import { getPayloadHMR } from '@payloadcms/next/utilities'
import configPromise from '@payload-config'
import { CollectionSlug } from 'payload'
const payloadToken = 'payload-token'
@@ -19,29 +20,67 @@ export async function GET(
const token = req.cookies.get(payloadToken)?.value
const { searchParams } = new URL(req.url)
const path = searchParams.get('path')
const collection = searchParams.get('collection') as CollectionSlug
const slug = searchParams.get('slug')
if (!path) {
return new Response('No path provided', { status: 404 })
}
const previewSecret = searchParams.get('previewSecret')
if (!token) {
new Response('You are not allowed to preview this page', { status: 403 })
}
let user
try {
user = jwt.verify(token, payload.secret)
} catch (error) {
payload.logger.error('Error verifying token for live preview:', error)
}
// You can add additional checks here to see if the user is allowed to preview this page
if (!user) {
draftMode().disable()
if (previewSecret) {
return new Response('You are not allowed to preview this page', { status: 403 })
}
} else {
if (!path) {
return new Response('No path provided', { status: 404 })
}
draftMode().enable()
redirect(path)
if (!collection) {
return new Response('No path provided', { status: 404 })
}
if (!slug) {
return new Response('No path provided', { status: 404 })
}
if (!token) {
new Response('You are not allowed to preview this page', { status: 403 })
}
if (!path.startsWith('/')) {
new Response('This endpoint can only be used for internal previews', { status: 500 })
}
let user
try {
user = jwt.verify(token, payload.secret)
} catch (error) {
payload.logger.error('Error verifying token for live preview:', error)
}
// You can add additional checks here to see if the user is allowed to preview this page
if (!user) {
draftMode().disable()
return new Response('You are not allowed to preview this page', { status: 403 })
}
// Verify the given slug exists
try {
const docs = await payload.find({
collection: collection,
where: {
slug: {
equals: slug,
},
},
})
if (!docs.docs.length) {
return new Response('Document not found', { status: 404 })
}
} catch (error) {
payload.logger.error('Error verifying token for live preview:', error)
}
draftMode().enable()
redirect(path)
}
}

View File

@@ -0,0 +1,66 @@
import type { Metadata } from 'next/types'
import { CollectionArchive } from '@/components/CollectionArchive'
import configPromise from '@payload-config'
import { getPayloadHMR } from '@payloadcms/next/utilities'
import React from 'react'
import { Post } from '@/payload-types'
import { Search } from '@/search/Component'
export default async function Page({ searchParams }: { searchParams: { q: string } }) {
const query = searchParams.q
const payload = await getPayloadHMR({ config: configPromise })
const posts = await payload.find({
collection: 'search',
depth: 1,
limit: 12,
...(query
? {
where: {
or: [
{
title: {
like: query,
},
},
{
'meta.description': {
like: query,
},
},
{
'meta.title': {
like: query,
},
},
{
slug: {
like: query,
},
},
],
},
}
: {}),
})
return (
<div className="pt-24 pb-24">
<div className="container mb-16">
<div className="prose dark:prose-invert max-w-none">
<h1 className="sr-only">Search</h1>
<Search />
</div>
</div>
<CollectionArchive posts={posts.docs as unknown as Post[]} />
</div>
)
}
export function generateMetadata(): Metadata {
return {
title: `Payload Website Template Search`,
}
}

View File

@@ -16,29 +16,30 @@ import { PreviewComponent as PreviewComponent_14 } from '@payloadcms/plugin-seo/
import { SlugComponent as SlugComponent_15 } from '@/fields/slug/SlugComponent'
import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_16 } from '@payloadcms/richtext-lexical/client'
import { BlocksFeatureClient as BlocksFeatureClient_17 } from '@payloadcms/richtext-lexical/client'
import { default as default_18 } from '@/components/BeforeDashboard'
import { default as default_19 } from '@/components/BeforeLogin'
import { LinkToDoc as LinkToDoc_18 } from '@payloadcms/plugin-search/client'
import { default as default_19 } from '@/components/BeforeDashboard'
import { default as default_20 } from '@/components/BeforeLogin'
export const importMap = {
'@payloadcms/richtext-lexical/client#RichTextCell': RichTextCell_0,
'@payloadcms/richtext-lexical/client#RichTextField': RichTextField_1,
'@payloadcms/richtext-lexical/generateComponentMap#getGenerateComponentMap':
getGenerateComponentMap_2,
'@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient': InlineToolbarFeatureClient_3,
'@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient': FixedToolbarFeatureClient_4,
'@payloadcms/richtext-lexical/client#HeadingFeatureClient': HeadingFeatureClient_5,
'@payloadcms/richtext-lexical/client#UnderlineFeatureClient': UnderlineFeatureClient_6,
'@payloadcms/richtext-lexical/client#BoldFeatureClient': BoldFeatureClient_7,
'@payloadcms/richtext-lexical/client#ItalicFeatureClient': ItalicFeatureClient_8,
'@payloadcms/richtext-lexical/client#LinkFeatureClient': LinkFeatureClient_9,
'@payloadcms/plugin-seo/client#OverviewComponent': OverviewComponent_10,
'@payloadcms/plugin-seo/client#MetaTitleComponent': MetaTitleComponent_11,
'@payloadcms/plugin-seo/client#MetaImageComponent': MetaImageComponent_12,
'@payloadcms/plugin-seo/client#MetaDescriptionComponent': MetaDescriptionComponent_13,
'@payloadcms/plugin-seo/client#PreviewComponent': PreviewComponent_14,
'@/fields/slug/SlugComponent#SlugComponent': SlugComponent_15,
'@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient': HorizontalRuleFeatureClient_16,
'@payloadcms/richtext-lexical/client#BlocksFeatureClient': BlocksFeatureClient_17,
'@/components/BeforeDashboard#default': default_18,
'@/components/BeforeLogin#default': default_19,
"@payloadcms/richtext-lexical/client#RichTextCell": RichTextCell_0,
"@payloadcms/richtext-lexical/client#RichTextField": RichTextField_1,
"@payloadcms/richtext-lexical/generateComponentMap#getGenerateComponentMap": getGenerateComponentMap_2,
"@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_3,
"@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient": FixedToolbarFeatureClient_4,
"@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_5,
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_6,
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_7,
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_8,
"@payloadcms/richtext-lexical/client#LinkFeatureClient": LinkFeatureClient_9,
"@payloadcms/plugin-seo/client#OverviewComponent": OverviewComponent_10,
"@payloadcms/plugin-seo/client#MetaTitleComponent": MetaTitleComponent_11,
"@payloadcms/plugin-seo/client#MetaImageComponent": MetaImageComponent_12,
"@payloadcms/plugin-seo/client#MetaDescriptionComponent": MetaDescriptionComponent_13,
"@payloadcms/plugin-seo/client#PreviewComponent": PreviewComponent_14,
"@/fields/slug/SlugComponent#SlugComponent": SlugComponent_15,
"@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_16,
"@payloadcms/richtext-lexical/client#BlocksFeatureClient": BlocksFeatureClient_17,
"@payloadcms/plugin-search/client#LinkToDoc": LinkToDoc_18,
"@/components/BeforeDashboard#default": default_19,
"@/components/BeforeLogin#default": default_20
}

View File

@@ -33,13 +33,21 @@ export const Pages: CollectionConfig = {
livePreview: {
url: ({ data }) => {
const path = generatePreviewPath({
path: `/${typeof data?.slug === 'string' ? data.slug : ''}`,
slug: typeof data?.slug === 'string' ? data.slug : '',
collection: 'pages',
})
return `${process.env.NEXT_PUBLIC_SERVER_URL}${path}`
},
},
preview: (doc) =>
generatePreviewPath({ path: `/${typeof doc?.slug === 'string' ? doc.slug : ''}` }),
preview: (data) => {
const path = generatePreviewPath({
slug: typeof data?.slug === 'string' ? data.slug : '',
collection: 'pages',
})
return `${process.env.NEXT_PUBLIC_SERVER_URL}${path}`
},
useAsTitle: 'title',
},
fields: [

View File

@@ -40,13 +40,21 @@ export const Posts: CollectionConfig = {
livePreview: {
url: ({ data }) => {
const path = generatePreviewPath({
path: `/posts/${typeof data?.slug === 'string' ? data.slug : ''}`,
slug: typeof data?.slug === 'string' ? data.slug : '',
collection: 'posts',
})
return `${process.env.NEXT_PUBLIC_SERVER_URL}${path}`
},
},
preview: (doc) =>
generatePreviewPath({ path: `/posts/${typeof doc?.slug === 'string' ? doc.slug : ''}` }),
preview: (data) => {
const path = generatePreviewPath({
slug: typeof data?.slug === 'string' ? data.slug : '',
collection: 'posts',
})
return `${process.env.NEXT_PUBLIC_SERVER_URL}${path}`
},
useAsTitle: 'title',
},
fields: [

View File

@@ -45,5 +45,6 @@ export const PayloadRedirects: React.FC<Props> = async ({ disableNotFound, url }
}
if (disableNotFound) return null
return notFound()
notFound()
}

View File

@@ -23,6 +23,7 @@ const collections: CollectionSlug[] = [
'posts',
'forms',
'form-submissions',
'search',
]
const globals: GlobalSlug[] = ['header', 'footer']
@@ -65,7 +66,6 @@ export const seed = async ({
}
for (const collection of collections) {
console.log('delete', collection)
await payload.delete({
collection: collection,
where: {

View File

@@ -8,6 +8,7 @@ import {
TextInput,
FieldLabel,
useFormFields,
useForm,
} from '@payloadcms/ui'
import { formatSlug } from './formatSlug'
@@ -33,33 +34,42 @@ export const SlugComponent: React.FC<SlugComponentProps> = ({
const { value, setValue } = useField<string>({ path })
const { value: checkboxValue, setValue: setCheckboxValue } = useField<boolean>({
path: checkboxFieldPath,
const { dispatchFields } = useForm()
// The value of the checkbox
// We're using separate useFormFields to minimise re-renders
const checkboxValue = useFormFields(([fields]) => {
return fields[checkboxFieldPath]?.value as string
})
const fieldToUseValue = useFormFields(([fields, dispatch]) => {
// The value of the field we're listening to for the slug
const targetFieldValue = useFormFields(([fields]) => {
return fields[fieldToUse]?.value as string
})
useEffect(() => {
if (checkboxValue) {
if (fieldToUseValue) {
const formattedSlug = formatSlug(fieldToUseValue)
if (targetFieldValue) {
const formattedSlug = formatSlug(targetFieldValue)
if (value !== formattedSlug) setValue(formattedSlug)
} else {
if (value !== '') setValue('')
}
}
}, [fieldToUseValue, checkboxValue, setValue, value])
}, [targetFieldValue, checkboxValue, setValue, value])
const handleLock = useCallback(
(e) => {
e.preventDefault()
setCheckboxValue(!checkboxValue)
dispatchFields({
type: 'UPDATE',
path: checkboxFieldPath,
value: !checkboxValue,
})
},
[checkboxValue, setCheckboxValue],
[checkboxValue, targetFieldValue],
)
const readOnly = readOnlyFromProps || checkboxValue
@@ -74,7 +84,7 @@ export const SlugComponent: React.FC<SlugComponentProps> = ({
</Button>
</div>
<TextInput label={''} value={value} onChange={setValue} path={path} readOnly={readOnly} />
<TextInput value={value} onChange={setValue} path={path} readOnly={Boolean(readOnly)} />
</div>
)
}

View File

@@ -19,6 +19,8 @@ export interface Config {
redirects: Redirect;
forms: Form;
'form-submissions': FormSubmission;
search: Search;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
@@ -578,6 +580,85 @@ export interface FormSubmission {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "search".
*/
export interface Search {
id: string;
title?: string | null;
priority?: number | null;
doc: {
relationTo: 'posts';
value: string | Post;
};
slug?: string | null;
meta?: {
title?: string | null;
description?: string | null;
image?: (string | null) | Media;
};
categories?:
| {
relationTo?: string | null;
id?: string | null;
title?: string | null;
}[]
| null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: string;
document?:
| ({
relationTo: 'pages';
value: string | Page;
} | null)
| ({
relationTo: 'posts';
value: string | Post;
} | null)
| ({
relationTo: 'media';
value: string | Media;
} | null)
| ({
relationTo: 'categories';
value: string | Category;
} | null)
| ({
relationTo: 'users';
value: string | User;
} | null)
| ({
relationTo: 'redirects';
value: string | Redirect;
} | null)
| ({
relationTo: 'forms';
value: string | Form;
} | null)
| ({
relationTo: 'form-submissions';
value: string | FormSubmission;
} | null)
| ({
relationTo: 'search';
value: string | Search;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: string | User;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".

View File

@@ -6,6 +6,7 @@ import { formBuilderPlugin } from '@payloadcms/plugin-form-builder'
import { nestedDocsPlugin } from '@payloadcms/plugin-nested-docs'
import { redirectsPlugin } from '@payloadcms/plugin-redirects'
import { seoPlugin } from '@payloadcms/plugin-seo'
import { searchPlugin } from '@payloadcms/plugin-search'
import {
BoldFeature,
FixedToolbarFeature,
@@ -32,6 +33,9 @@ import { revalidateRedirects } from './hooks/revalidateRedirects'
import { GenerateTitle, GenerateURL } from '@payloadcms/plugin-seo/types'
import { Page, Post } from 'src/payload-types'
import { searchFields } from '@/search/fieldOverrides'
import { beforeSyncWithSearch } from '@/search/beforeSync'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
@@ -188,6 +192,15 @@ export default buildConfig({
},
},
}),
searchPlugin({
collections: ['posts'],
beforeSync: beforeSyncWithSearch,
searchOverrides: {
fields: ({ defaultFields }) => {
return [...defaultFields, ...searchFields]
},
},
}),
payloadCloudPlugin(), // storage-adapter-placeholder
],
secret: process.env.PAYLOAD_SECRET!,

Some files were not shown because too many files have changed in this diff Show More