Compare commits
154 Commits
fix/cpa-ex
...
fix/findVa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58f841cee4 | ||
|
|
f0a157f939 | ||
|
|
19d6b1aac8 | ||
|
|
9b382b6adf | ||
|
|
bf5d31960b | ||
|
|
3ad29d251f | ||
|
|
07e9444c09 | ||
|
|
5dd13f2873 | ||
|
|
878be913fd | ||
|
|
0524f198a6 | ||
|
|
5f2e846350 | ||
|
|
d3265b9931 | ||
|
|
33261b36bf | ||
|
|
73d4201df8 | ||
|
|
50d3da5824 | ||
|
|
41aac41df4 | ||
|
|
6a5b95af7c | ||
|
|
2e7bfcbd63 | ||
|
|
3ee9a32a38 | ||
|
|
c2d38b4109 | ||
|
|
5d9c537145 | ||
|
|
904b6a6dbe | ||
|
|
cc6de7ef42 | ||
|
|
a3ef4fbfac | ||
|
|
e9ff611879 | ||
|
|
5825d0cfc7 | ||
|
|
103b476c82 | ||
|
|
a3279b319e | ||
|
|
bbb0ab784c | ||
|
|
32eac5b0c2 | ||
|
|
86098c9140 | ||
|
|
7fd2cdf04c | ||
|
|
8d507996c8 | ||
|
|
aa82763cb8 | ||
|
|
e7e6a7dd97 | ||
|
|
e14c670a51 | ||
|
|
21f5d3473c | ||
|
|
36597110e9 | ||
|
|
4f2b237858 | ||
|
|
d90afba70d | ||
|
|
decd512daa | ||
|
|
b2bf95b17b | ||
|
|
10e29dd5e2 | ||
|
|
4c4ae1295e | ||
|
|
adb805dadb | ||
|
|
e5f0ca3d45 | ||
|
|
fe2b7693cc | ||
|
|
30d4a098b1 | ||
|
|
aa7918fe6e | ||
|
|
f23f87243c | ||
|
|
41b75882a1 | ||
|
|
cfd3c34aba | ||
|
|
270137e92e | ||
|
|
cab817d2aa | ||
|
|
db622e2b79 | ||
|
|
c52204317a | ||
|
|
a85af1a6d3 | ||
|
|
bccadd5101 | ||
|
|
2fa723743e | ||
|
|
2904de778d | ||
|
|
d37dfb1376 | ||
|
|
b203f617af | ||
|
|
ee46f27881 | ||
|
|
2426784726 | ||
|
|
95b78a5951 | ||
|
|
d1c1ad2a1d | ||
|
|
2980bdb799 | ||
|
|
fe6923d0a7 | ||
|
|
7eec63ae69 | ||
|
|
77a7bc5e9c | ||
|
|
780becc88a | ||
|
|
a2d394ec82 | ||
|
|
b1c8c96e97 | ||
|
|
6b6b596489 | ||
|
|
a89bc1479f | ||
|
|
bd9f3b5bd2 | ||
|
|
2584ff42eb | ||
|
|
cc1f5fb70c | ||
|
|
4f7f378b84 | ||
|
|
b279fa7bde | ||
|
|
93230a5915 | ||
|
|
9f31daf8e7 | ||
|
|
ded7164dca | ||
|
|
cc4526844a | ||
|
|
362f25f593 | ||
|
|
7567d2358a | ||
|
|
b418c3cade | ||
|
|
db0d07d9a7 | ||
|
|
b56e2faad2 | ||
|
|
56982f9811 | ||
|
|
9e1258811a | ||
|
|
1d2accfcbb | ||
|
|
4a8bea2dde | ||
|
|
0149e42276 | ||
|
|
36d9900774 | ||
|
|
f4d624a0c5 | ||
|
|
57bcfcc8be | ||
|
|
d73ddbde0c | ||
|
|
189dd64799 | ||
|
|
572ce2955a | ||
|
|
87ca312a54 | ||
|
|
2b2fa67031 | ||
|
|
2f45749634 | ||
|
|
0534dd9506 | ||
|
|
aee1ea1346 | ||
|
|
82ba8cf8f4 | ||
|
|
1dfff2b0b0 | ||
|
|
6b695355c3 | ||
|
|
29c32d3141 | ||
|
|
f6afbed5d2 | ||
|
|
5dcf96ca10 | ||
|
|
91c22bd88c | ||
|
|
0d8b5677d9 | ||
|
|
e55c89c4b7 | ||
|
|
f762d683c6 | ||
|
|
953c538af0 | ||
|
|
65d0272950 | ||
|
|
c570d6178c | ||
|
|
c935420937 | ||
|
|
72dd527a15 | ||
|
|
1d6e0941e7 | ||
|
|
91f7deb278 | ||
|
|
d3986cfaf0 | ||
|
|
4a9de40098 | ||
|
|
f4679a4088 | ||
|
|
cb8ee7d2b0 | ||
|
|
06ef8da836 | ||
|
|
91dc98978d | ||
|
|
07ff1ee7be | ||
|
|
72d393d24c | ||
|
|
95d4324af3 | ||
|
|
a617d3166c | ||
|
|
6770e7a1b3 | ||
|
|
f5e535dacf | ||
|
|
3d9c25e278 | ||
|
|
3bdb127ad4 | ||
|
|
de4be1eb78 | ||
|
|
d26529282f | ||
|
|
2694603353 | ||
|
|
9630de1bac | ||
|
|
91e867ecb1 | ||
|
|
25e196bdd7 | ||
|
|
b631eebdb5 | ||
|
|
a66f134cf6 | ||
|
|
b3aec9a23f | ||
|
|
31911d87c1 | ||
|
|
2d37ac41a2 | ||
|
|
b68af8ba31 | ||
|
|
4c775d1ced | ||
|
|
4706019a22 | ||
|
|
9c33a48192 | ||
|
|
8ec6784645 | ||
|
|
8d9bf835a0 | ||
|
|
2eef7ee388 |
@@ -39,7 +39,7 @@ const GlobalWithAccessControl: GlobalConfig = {
|
||||
update: ({ req: { user } }) => {...},
|
||||
|
||||
// Version-enabled Globals only
|
||||
readVersions: () => {...},
|
||||
readVersion: () => {...},
|
||||
},
|
||||
// highlight-end
|
||||
}
|
||||
@@ -64,7 +64,7 @@ If a Global supports [Versions](../versions/overview), the following additional
|
||||
|
||||
Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can read this global based on its current properties.
|
||||
|
||||
To add read Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../configuration/globals):
|
||||
To add read Access Control to a [Global](../configuration/globals), use the `read` property in the [Global Config](../configuration/globals):
|
||||
|
||||
```ts
|
||||
import { GlobalConfig } from 'payload'
|
||||
@@ -72,7 +72,7 @@ import { GlobalConfig } from 'payload'
|
||||
const Header: GlobalConfig = {
|
||||
// ...
|
||||
// highlight-start
|
||||
access: {
|
||||
read: {
|
||||
read: ({ req: { user } }) => {
|
||||
return Boolean(user)
|
||||
},
|
||||
|
||||
@@ -65,7 +65,7 @@ preview: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlig
|
||||
|
||||
The Preview feature can be used to achieve "Draft Preview". After clicking the preview button from the Admin Panel, you can enter into "draft mode" within your front-end application. This will allow you to adjust your page queries to include the `draft: true` param. When this param is present on the request, Payload will send back a draft document as opposed to a published one based on the document's `_status` field.
|
||||
|
||||
To enter draft mode, the URL provided to the `preview` function can point to a custom endpoint in your front-end application that sets a cookie or session variable to indicate that draft mode is enabled. This is framework specific, so the mechanisms here vary from framework to framework although the underlying concept is the same.
|
||||
To enter draft mode, the URL provided to the `preview` function can point to a custom endpoint in your front-end application that sets a cookie or session variable to indicate that draft mode is enabled. This is framework specific, so the mechanisms here very from framework to framework although the underlying concept is the same.
|
||||
|
||||
### Next.js
|
||||
|
||||
|
||||
@@ -605,7 +605,7 @@ return (
|
||||
textField: {
|
||||
initialValue: 'Updated text',
|
||||
valid: true,
|
||||
value: 'Updated text',
|
||||
value: 'Upddated text',
|
||||
},
|
||||
},
|
||||
// blockType: "yourBlockSlug",
|
||||
@@ -875,7 +875,7 @@ Useful to retrieve info about the currently logged in user as well as methods fo
|
||||
| **`refreshCookie`** | A method to trigger the silent refreshing of a user's auth token |
|
||||
| **`setToken`** | Set the token of the user, to be decoded and used to reset the user and token in memory |
|
||||
| **`token`** | The logged in user's token (useful for creating preview links, etc.) |
|
||||
| **`refreshPermissions`** | Load new permissions (useful when content that affects permissions has been changed) |
|
||||
| **`refreshPermissions`** | Load new permissions (useful when content that effects permissions has been changed) |
|
||||
| **`permissions`** | The permissions of the current user |
|
||||
|
||||
```tsx
|
||||
@@ -1143,7 +1143,7 @@ This is useful for scenarios where you need to trigger another fetch regardless
|
||||
|
||||
Route transitions are useful in showing immediate visual feedback to the user when navigating between pages. This is especially useful on slow networks when navigating to data heavy or process intensive pages.
|
||||
|
||||
By default, any instances of `Link` from `@payloadcms/ui` will trigger route transitions by default.
|
||||
By default, any instances of `Link` from `@payloadcms/ui` will trigger route transitions dy default.
|
||||
|
||||
```tsx
|
||||
import { Link } from '@payloadcms/ui'
|
||||
|
||||
@@ -62,7 +62,7 @@ In this scenario, if your cookie was still valid, malicious-intent.com would be
|
||||
|
||||
### CSRF Prevention
|
||||
|
||||
Define domains that you trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload Config to do this:
|
||||
Define domains that your trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload Config to do this:
|
||||
|
||||
```ts
|
||||
// payload.config.ts
|
||||
@@ -102,8 +102,8 @@ If option 1 isn't possible, then you can get around this limitation by [configur
|
||||
|
||||
```
|
||||
SameSite: None // allows the cookie to cross domains
|
||||
Secure: true // ensures it's sent over HTTPS only
|
||||
HttpOnly: true // ensures it's not accessible via client side JavaScript
|
||||
Secure: true // ensures its sent over HTTPS only
|
||||
HttpOnly: true // ensures its not accessible via client side JavaScript
|
||||
```
|
||||
|
||||
Configuration example:
|
||||
|
||||
@@ -71,7 +71,7 @@ export const Customers: CollectionConfig = {
|
||||
|
||||
#### generateEmailSubject
|
||||
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function arguments are the same but you can only return a string - not HTML.
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
@@ -178,7 +178,7 @@ The following arguments are passed to the `generateEmailHTML` function:
|
||||
|
||||
#### generateEmailSubject
|
||||
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function arguments are the same but you can only return a string - not HTML.
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
@@ -38,7 +38,7 @@ const request = await fetch('http://localhost:3000', {
|
||||
|
||||
### Omitting The Token
|
||||
|
||||
In some cases you may want to prevent the token from being returned from the auth operations. You can do that by setting `removeTokenFromResponses` to `true` like so:
|
||||
In some cases you may want to prevent the token from being returned from the auth operations. You can do that by setting `removeTokenFromResponse` to `true` like so:
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
@@ -46,7 +46,7 @@ import type { CollectionConfig } from 'payload'
|
||||
export const UsersWithoutJWTs: CollectionConfig = {
|
||||
slug: 'users-without-jwts',
|
||||
auth: {
|
||||
removeTokenFromResponses: true, // highlight-line
|
||||
removeTokenFromResponse: true, // highlight-line
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -67,7 +67,7 @@ query {
|
||||
}
|
||||
```
|
||||
|
||||
Document access can also be queried on a collection/global basis. Access on a global can be queried like `http://localhost:3000/api/global-slug/access`, Collection document access can be queried like `http://localhost:3000/api/collection-slug/access/:id`.
|
||||
Document access can also be queried on a collection/global basis. Access on a global can queried like `http://localhost:3000/api/global-slug/access`, Collection document access can be queried like `http://localhost:3000/api/collection-slug/access/:id`.
|
||||
|
||||
## Me
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ export const Admins: CollectionConfig = {
|
||||
</Banner>
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** Auth-enabled Collections will be automatically injected with the
|
||||
**Note:** Auth-enabled Collections with be automatically injected with the
|
||||
`hash`, `salt`, and `email` fields. [More
|
||||
details](../fields/overview#field-names).
|
||||
</Banner>
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords: authentication, config, configuration, documentation, Content Manageme
|
||||
|
||||
During the lifecycle of a request you will be able to access the data you have configured to be stored in the JWT by accessing `req.user`. The user object is automatically appended to the request for you.
|
||||
|
||||
### Defining Token Data
|
||||
### Definining Token Data
|
||||
|
||||
You can specify what data gets encoded to the Cookie/JWT-Token by setting `saveToJWT` property on fields within your auth collection.
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ The following options are available:
|
||||
#### Edit View Options
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
import type { CollectionCOnfig } from 'payload'
|
||||
|
||||
export const MyCollection: CollectionConfig = {
|
||||
// ...
|
||||
@@ -275,7 +275,7 @@ You can also pass an object to the collection's `graphQL` property, which allows
|
||||
|
||||
## TypeScript
|
||||
|
||||
You can import types from Payload to help make writing your Collection configs easier and type-safe. There are two main types that represent the Collection Config, `CollectionConfig` and `SanitizedCollectionConfig`.
|
||||
You can import types from Payload to help make writing your Collection configs easier and type-safe. There are two main types that represent the Collection Config, `CollectionConfig` and `SanitizeCollectionConfig`.
|
||||
|
||||
The `CollectionConfig` type represents a raw Collection Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedCollectionConfig` type represents a Collection Config after it has been fully sanitized. Generally, this is only used internally by Payload.
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ You can also pass an object to the global's `graphQL` property, which allows you
|
||||
|
||||
## TypeScript
|
||||
|
||||
You can import types from Payload to help make writing your Global configs easier and type-safe. There are two main types that represent the Global Config, `GlobalConfig` and `SanitizedGlobalConfig`.
|
||||
You can import types from Payload to help make writing your Global configs easier and type-safe. There are two main types that represent the Global Config, `GlobalConfig` and `SanitizeGlobalConfig`.
|
||||
|
||||
The `GlobalConfig` type represents a raw Global Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedGlobalConfig` type represents a Global Config after it has been fully sanitized. Generally, this is only used internally by Payload.
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ For more information about what we track, take a look at our [privacy policy](/p
|
||||
|
||||
## Cross-origin resource sharing (CORS)#cors
|
||||
|
||||
Cross-origin resource sharing (CORS) can be configured with either a whitelist array of URLS to allow CORS requests from, a wildcard string (`*`) to accept incoming requests from any domain, or an object with the following properties:
|
||||
Cross-origin resource sharing (CORS) can be configured with either a whitelist array of URLS to allow CORS requests from, a wildcard string (`*`) to accept incoming requests from any domain, or a object with the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -292,7 +292,7 @@ export const script = async (config: SanitizedConfig) => {
|
||||
collection: 'pages',
|
||||
data: { title: 'my title' },
|
||||
})
|
||||
payload.logger.info('Successfully seeded!')
|
||||
payload.logger.info('Succesffully seeded!')
|
||||
process.exit(0)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -59,7 +59,7 @@ _For details on how to build Custom Views, including all available props, see [B
|
||||
|
||||
### Document Root
|
||||
|
||||
The Document Root is mounted on the top-level route for a Document. Setting this property will completely take over the entire Document View layout, including the title, [Document Tabs](#document-tabs), _and all other nested Document Views_ including the [Edit View](./edit-view), API View, etc.
|
||||
The Document Root is mounted on the top-level route for a Document. Setting this property will completely take over the entire Document View layout, including the title, [Document Tabs](#ocument-tabs), _and all other nested Document Views_ including the [Edit View](./edit-view), API View, etc.
|
||||
|
||||
When setting a Document Root, you are responsible for rendering all necessary components and controls, as no document controls or tabs would be rendered. To replace only the Edit View precisely, use the `edit.default` key instead.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ The following options are available:
|
||||
| `beforeDashboard` | An array of Custom Components to inject into the built-in Dashboard, _before_ the default dashboard contents. [More details](#beforedashboard). |
|
||||
| `beforeLogin` | An array of Custom Components to inject into the built-in Login, _before_ the default login form. [More details](#beforelogin). |
|
||||
| `beforeNavLinks` | An array of Custom Components to inject into the built-in Nav, _before_ the links themselves. [More details](#beforenavlinks). |
|
||||
| `graphics.Icon` | The simplified logo used in contexts like the `Nav` component. [More details](#graphicsicon). |
|
||||
| `graphics.Icon` | The simplified logo used in contexts like the the `Nav` component. [More details](#graphicsicon). |
|
||||
| `graphics.Logo` | The full logo used in contexts like the `Login` view. [More details](#graphicslogo). |
|
||||
| `header` | An array of Custom Components to be injected above the Payload header. [More details](#header). |
|
||||
| `logout.Button` | The button displayed in the sidebar that logs the user out. [More details](#logoutbutton). |
|
||||
@@ -345,7 +345,7 @@ export default function MyCustomIcon() {
|
||||
|
||||
The `Logo` property is the full logo used in contexts like the `Login` view. This is typically a larger, more detailed representation of your brand.
|
||||
|
||||
To add a custom logo, use the `admin.components.graphics.Logo` property in your Payload Config:
|
||||
To add a custom logo, use the `admin.components.graphic.Logo` property in your Payload Config:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
@@ -39,7 +39,7 @@ export default buildConfig({
|
||||
import { vercelPostgresAdapter } from '@payloadcms/db-vercel-postgres'
|
||||
|
||||
export default buildConfig({
|
||||
// Automatically uses process.env.POSTGRES_URL if no options are provided.
|
||||
// Automatically uses proces.env.POSTGRES_URL if no options are provided.
|
||||
db: vercelPostgresAdapter(),
|
||||
// Optionally, can accept the same options as the @vercel/postgres package.
|
||||
db: vercelPostgresAdapter({
|
||||
@@ -224,7 +224,7 @@ Make sure Payload doesn't overlap table names with its collections. For example,
|
||||
### afterSchemaInit
|
||||
|
||||
Runs after the Drizzle schema is built. You can use this hook to modify the schema with features that aren't supported by Payload, or if you want to add a column that you don't want to be in the Payload config.
|
||||
To extend a table, Payload exposes `extendTable` utility to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
To extend a table, Payload exposes `extendTable` utillity to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
The following example adds the `extra_integer_column` column and a composite index on `country` and `city` columns.
|
||||
|
||||
```ts
|
||||
|
||||
@@ -189,7 +189,7 @@ Make sure Payload doesn't overlap table names with its collections. For example,
|
||||
### afterSchemaInit
|
||||
|
||||
Runs after the Drizzle schema is built. You can use this hook to modify the schema with features that aren't supported by Payload, or if you want to add a column that you don't want to be in the Payload config.
|
||||
To extend a table, Payload exposes `extendTable` utility to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
To extend a table, Payload exposes `extendTable` utillity to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
The following example adds the `extra_integer_column` column and a composite index on `country` and `city` columns.
|
||||
|
||||
```ts
|
||||
|
||||
@@ -80,7 +80,7 @@ export const MyArrayField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Array Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Array Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------- | ----------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -78,7 +78,7 @@ export const MyBlocksField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Blocks Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Blocks Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | -------------------------------------------------------------------------- |
|
||||
|
||||
@@ -68,7 +68,7 @@ export const MyCodeField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Code Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Code Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -58,7 +58,7 @@ export const MyCollapsibleField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Collapsible Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Collapsible Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------- |
|
||||
|
||||
@@ -65,7 +65,7 @@ export const MyDateField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Date Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Date Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -65,7 +65,7 @@ export const MyEmailField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Email Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Email Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------- |
|
||||
|
||||
@@ -69,7 +69,7 @@ export const MyGroupField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Group Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Group Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
|
||||
@@ -67,7 +67,7 @@ export const MyJSONField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The JSON Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The JSON Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -70,7 +70,7 @@ export const MyNumberField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Number Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Number Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -36,7 +36,7 @@ export const MyRadioField: Field = {
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing an `label` string and a `value` string. |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
@@ -82,7 +82,7 @@ export const MyRadioField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Radio Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Radio Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -86,7 +86,7 @@ export const MyRelationshipField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Relationship Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Relationship Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -54,7 +54,6 @@ export const MySelectField: Field = {
|
||||
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`filterOptions`** | Dynamically filter which options are available based on the user, data, etc. [More details](#filterOptions) |
|
||||
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
|
||||
| **`virtual`** | Provide `true` to disable field in the database, or provide a string path to [link the field with a relationship](/docs/fields/relationship#linking-virtual-fields-with-relationships). See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
|
||||
|
||||
@@ -68,61 +67,6 @@ _\* An asterisk denotes that a property is required._
|
||||
used as a GraphQL enum.
|
||||
</Banner>
|
||||
|
||||
### filterOptions
|
||||
|
||||
Used to dynamically filter which options are available based on the user, data, etc.
|
||||
|
||||
Some examples of this might include:
|
||||
|
||||
- Restricting options based on a user's role, e.g. admin-only options
|
||||
- Displaying different options based on the value of another field, e.g. a city/state selector
|
||||
|
||||
The result of `filterOptions` will determine:
|
||||
|
||||
- Which options are displayed in the Admin Panel
|
||||
- Which options can be saved to the database
|
||||
|
||||
To do this, use the `filterOptions` property in your [Field Config](./overview):
|
||||
|
||||
```ts
|
||||
import type { Field } from 'payload'
|
||||
|
||||
export const MySelectField: Field = {
|
||||
// ...
|
||||
// highlight-start
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: 'One',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Two',
|
||||
value: 'two',
|
||||
},
|
||||
{
|
||||
label: 'Three',
|
||||
value: 'three',
|
||||
},
|
||||
],
|
||||
filterOptions: ({ options, data }) =>
|
||||
data.disallowOption1
|
||||
? options.filter(
|
||||
(option) =>
|
||||
(typeof option === 'string' ? options : option.value) !== 'one',
|
||||
)
|
||||
: options,
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** This property is similar to `filterOptions` in
|
||||
[Relationship](./relationship) or [Upload](./upload) fields, except that the
|
||||
return value of this function is simply an array of options, not a query
|
||||
constraint.
|
||||
</Banner>
|
||||
|
||||
## Admin Options
|
||||
|
||||
To customize the appearance and behavior of the Select Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
|
||||
@@ -139,7 +83,7 @@ export const MySelectField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Select Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Select Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -70,7 +70,7 @@ export const MyTextField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Text Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Text Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -67,7 +67,7 @@ export const MyTextareaField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Textarea Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Textarea Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Folders
|
||||
label: Overview
|
||||
label: Folders
|
||||
order: 10
|
||||
desc: Folders allow you to group documents across collections, and are a great way to organize your content.
|
||||
keywords: folders, folder, content organization
|
||||
@@ -10,11 +10,6 @@ Folders allow you to group documents across collections, and are a great way to
|
||||
|
||||
The configuration for folders is done in two places, the collection config and the Payload config. The collection config is where you enable folders, and the Payload config is where you configure the global folder settings.
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** The Folders feature is currently in beta and may be subject to
|
||||
change in minor versions updates prior to being stable.
|
||||
</Banner>
|
||||
|
||||
## Folder Configuration
|
||||
|
||||
On the payload config, you can configure the following settings under the `folders` property:
|
||||
@@ -95,7 +90,9 @@ const config = buildConfig({
|
||||
{
|
||||
slug: 'pages',
|
||||
// highlight-start
|
||||
folders: true, // defaults to false
|
||||
admin: {
|
||||
folders: true, // defaults to false
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
|
||||
@@ -23,7 +23,7 @@ Let's see examples on how context can be used in the first two scenarios mention
|
||||
|
||||
### Passing Data Between Hooks
|
||||
|
||||
To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it in the context of a later hook.
|
||||
To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it the context in a later hook.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ Simply add a task to the `jobs.tasks` array in your Payload config. A task consi
|
||||
| `onSuccess` | Function to be executed if the task succeeds. |
|
||||
| `retries` | Specify the number of times that this step should be retried if it fails. If this is undefined, the task will either inherit the retries from the workflow or have no retries. If this is 0, the task will not be retried. By default, this is undefined. |
|
||||
|
||||
The logic for the Task is defined in the `handler` - which can be defined as a function, or a path to a function. The `handler` will run once a worker picks up a Job that includes this task.
|
||||
The logic for the Task is defined in the `handler` - which can be defined as a function, or a path to a function. The `handler` will run once a worker picks picks up a Job that includes this task.
|
||||
|
||||
It should return an object with an `output` key, which should contain the output of the task as you've defined.
|
||||
|
||||
@@ -213,7 +213,7 @@ export default buildConfig({
|
||||
|
||||
## Nested tasks
|
||||
|
||||
You can run sub-tasks within an existing task, by using the `tasks` or `inlineTask` arguments passed to the task `handler` function:
|
||||
You can run sub-tasks within an existing task, by using the `tasks` or `ìnlineTask` arguments passed to the task `handler` function:
|
||||
|
||||
```ts
|
||||
export default buildConfig({
|
||||
|
||||
@@ -260,7 +260,7 @@ If you are using relationships or uploads in your front-end application, and you
|
||||
{
|
||||
// ...
|
||||
// If your site is running on a different domain than your Payload server,
|
||||
// This will allow requests to be made between the two domains
|
||||
// This will allows requests to be made between the two domains
|
||||
cors: [
|
||||
'http://localhost:3001' // Your front-end application
|
||||
],
|
||||
|
||||
@@ -135,7 +135,7 @@ export const MyComponent: React.FC<{
|
||||
|
||||
### Overriding Converters
|
||||
|
||||
You can override any of the default JSX converters by passing your custom converter, keyed to the node type, to the `converters` prop / the converters function.
|
||||
You can override any of the default JSX converters by passing passing your custom converter, keyed to the node type, to the `converters` prop / the converters function.
|
||||
|
||||
Example - overriding the upload node converter to use next/image:
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Autosave
|
||||
label: Autosave
|
||||
order: 30
|
||||
desc: Using Payload's Draft functionality, you can configure your collections and globals to autosave changes as drafts, and publish only you're ready.
|
||||
keywords: version history, revisions, audit log, draft, publish, autosave, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
keywords: version history, revisions, audit log, draft, publish, autosave, Content Management System, cms, headless, javascript, node, react, nextjss
|
||||
---
|
||||
|
||||
Extending on Payload's [Draft](/docs/versions/drafts) functionality, you can configure your collections and globals to autosave changes as drafts, and publish only you're ready. The Admin UI will automatically adapt to autosaving progress at an interval that you define, and will store all autosaved changes as a new Draft version. Never lose your work - and publish changes to the live document only when you're ready.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import { admins } from './access/admins'
|
||||
import { adminsAndUser } from './access/adminsAndUser'
|
||||
import adminsAndUser from './access/adminsAndUser'
|
||||
import { anyone } from './access/anyone'
|
||||
import { checkRole } from './access/checkRole'
|
||||
import { loginAfterCreate } from './hooks/loginAfterCreate'
|
||||
@@ -25,7 +25,6 @@ export const Users: CollectionConfig = {
|
||||
create: anyone,
|
||||
update: adminsAndUser,
|
||||
delete: admins,
|
||||
unlock: admins,
|
||||
admin: ({ req: { user } }) => checkRole(['admin'], user),
|
||||
},
|
||||
hooks: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Access } from 'payload'
|
||||
import type { Access } from 'payload/config'
|
||||
|
||||
import { checkRole } from './checkRole'
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import type { Access } from 'payload'
|
||||
import type { Access } from 'payload/config'
|
||||
|
||||
import { checkRole } from './checkRole'
|
||||
|
||||
export const adminsAndUser: Access = ({ req: { user } }) => {
|
||||
const adminsAndUser: Access = ({ req: { user } }) => {
|
||||
if (user) {
|
||||
if (checkRole(['admin'], user)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return {
|
||||
id: { equals: user.id },
|
||||
id: user.id,
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export default adminsAndUser
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import type { Access } from 'payload'
|
||||
import type { Access } from 'payload/config'
|
||||
|
||||
export const anyone: Access = () => true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { User } from '../../payload-types'
|
||||
|
||||
export const checkRole = (allRoles: User['roles'] = [], user: User | null = null): boolean => {
|
||||
export const checkRole = (allRoles: User['roles'] = [], user: User = undefined): boolean => {
|
||||
if (user) {
|
||||
if (
|
||||
allRoles.some((role) => {
|
||||
@@ -8,9 +8,8 @@ export const checkRole = (allRoles: User['roles'] = [], user: User | null = null
|
||||
return individualRole === role
|
||||
})
|
||||
})
|
||||
) {
|
||||
return true
|
||||
}
|
||||
)
|
||||
{return true}
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { FieldHook } from 'payload'
|
||||
import type { FieldHook } from 'payload/types'
|
||||
|
||||
import type { User } from '../../payload-types'
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
import path from 'path'
|
||||
import express from 'express'
|
||||
import { buildConfig } from 'payload'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import express from 'express'
|
||||
import type { Request, Response } from 'express'
|
||||
import { parse } from 'url'
|
||||
import next from 'next'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/admin-bar",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "An admin bar for React apps using Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
8
packages/create-payload-app/src/lib/constants.ts
Normal file
8
packages/create-payload-app/src/lib/constants.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { readFileSync } from 'fs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'path'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
const packageJson = JSON.parse(readFileSync(path.resolve(dirname, '../../package.json'), 'utf-8'))
|
||||
export const PACKAGE_VERSION = packageJson.version
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { ProjectTemplate } from '../types.js'
|
||||
|
||||
import { error, info } from '../utils/log.js'
|
||||
import { PACKAGE_VERSION } from './constants.js'
|
||||
|
||||
export function validateTemplate({ templateName }: { templateName: string }): boolean {
|
||||
export function validateTemplate(templateName: string): boolean {
|
||||
const validTemplates = getValidTemplates()
|
||||
if (!validTemplates.map((t) => t.name).includes(templateName)) {
|
||||
error(`'${templateName}' is not a valid template.`)
|
||||
@@ -19,13 +20,13 @@ export function getValidTemplates(): ProjectTemplate[] {
|
||||
name: 'blank',
|
||||
type: 'starter',
|
||||
description: 'Blank 3.0 Template',
|
||||
url: `https://github.com/payloadcms/payload/templates/blank#main`,
|
||||
url: `https://github.com/payloadcms/payload/templates/blank#v${PACKAGE_VERSION}`,
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
type: 'starter',
|
||||
description: 'Website Template',
|
||||
url: `https://github.com/payloadcms/payload/templates/website#main`,
|
||||
url: `https://github.com/payloadcms/payload/templates/website#v${PACKAGE_VERSION}`,
|
||||
},
|
||||
{
|
||||
name: 'plugin',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import execa from 'execa'
|
||||
import fse from 'fs-extra'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'path'
|
||||
@@ -8,7 +9,6 @@ const dirname = path.dirname(filename)
|
||||
import type { NextAppDetails } from '../types.js'
|
||||
|
||||
import { copyRecursiveSync } from '../utils/copy-recursive-sync.js'
|
||||
import { getLatestPackageVersion } from '../utils/getLatestPackageVersion.js'
|
||||
import { info } from '../utils/log.js'
|
||||
import { getPackageManager } from './get-package-manager.js'
|
||||
import { installPackages } from './install-packages.js'
|
||||
@@ -36,8 +36,15 @@ export async function updatePayloadInProject(
|
||||
|
||||
const packageManager = await getPackageManager({ projectDir })
|
||||
|
||||
// Fetch latest Payload version
|
||||
const latestPayloadVersion = await getLatestPackageVersion({ packageName: 'payload' })
|
||||
// Fetch latest Payload version from npm
|
||||
const { exitCode: getLatestVersionExitCode, stdout: latestPayloadVersion } = await execa('npm', [
|
||||
'show',
|
||||
'payload',
|
||||
'version',
|
||||
])
|
||||
if (getLatestVersionExitCode !== 0) {
|
||||
throw new Error('Failed to fetch latest Payload version')
|
||||
}
|
||||
|
||||
if (payloadVersion === latestPayloadVersion) {
|
||||
return { message: `Payload v${payloadVersion} is already up to date.`, success: true }
|
||||
|
||||
@@ -8,6 +8,7 @@ import path from 'path'
|
||||
import type { CliArgs } from './types.js'
|
||||
|
||||
import { configurePayloadConfig } from './lib/configure-payload-config.js'
|
||||
import { PACKAGE_VERSION } from './lib/constants.js'
|
||||
import { createProject } from './lib/create-project.js'
|
||||
import { parseExample } from './lib/examples.js'
|
||||
import { generateSecret } from './lib/generate-secret.js'
|
||||
@@ -19,7 +20,6 @@ import { parseTemplate } from './lib/parse-template.js'
|
||||
import { selectDb } from './lib/select-db.js'
|
||||
import { getValidTemplates, validateTemplate } from './lib/templates.js'
|
||||
import { updatePayloadInProject } from './lib/update-payload-in-project.js'
|
||||
import { getLatestPackageVersion } from './utils/getLatestPackageVersion.js'
|
||||
import { debug, error, info } from './utils/log.js'
|
||||
import {
|
||||
feedbackOutro,
|
||||
@@ -78,18 +78,13 @@ export class Main {
|
||||
|
||||
async init(): Promise<void> {
|
||||
try {
|
||||
const debugFlag = this.args['--debug']
|
||||
|
||||
const LATEST_VERSION = await getLatestPackageVersion({
|
||||
debug: debugFlag,
|
||||
packageName: 'payload',
|
||||
})
|
||||
|
||||
if (this.args['--help']) {
|
||||
helpMessage()
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const debugFlag = this.args['--debug']
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('\n')
|
||||
p.intro(chalk.bgCyan(chalk.black(' create-payload-app ')))
|
||||
@@ -205,7 +200,7 @@ export class Main {
|
||||
|
||||
const templateArg = this.args['--template']
|
||||
if (templateArg) {
|
||||
const valid = validateTemplate({ templateName: templateArg })
|
||||
const valid = validateTemplate(templateArg)
|
||||
if (!valid) {
|
||||
helpMessage()
|
||||
process.exit(1)
|
||||
@@ -235,7 +230,7 @@ export class Main {
|
||||
}
|
||||
|
||||
if (debugFlag) {
|
||||
debug(`Using ${exampleArg ? 'examples' : 'templates'} from git tag: v${LATEST_VERSION}`)
|
||||
debug(`Using ${exampleArg ? 'examples' : 'templates'} from git tag: v${PACKAGE_VERSION}`)
|
||||
}
|
||||
|
||||
if (!exampleArg) {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Fetches the latest version of a package from the NPM registry.
|
||||
*
|
||||
* Used in determining the latest version of Payload to use in the generated templates.
|
||||
*/
|
||||
export async function getLatestPackageVersion({
|
||||
debug = false,
|
||||
packageName = 'payload',
|
||||
}: {
|
||||
debug?: boolean
|
||||
/**
|
||||
* Package name to fetch the latest version for based on the NPM registry URL
|
||||
*
|
||||
* Eg. for `'payload'`, it will fetch the version from `https://registry.npmjs.org/payload`
|
||||
*
|
||||
* @default 'payload'
|
||||
*/
|
||||
packageName?: string
|
||||
}) {
|
||||
try {
|
||||
const response = await fetch(`https://registry.npmjs.org/${packageName}`)
|
||||
const data = await response.json()
|
||||
const latestVersion = data['dist-tags'].latest
|
||||
|
||||
if (debug) {
|
||||
console.log(`Found latest version of ${packageName}: ${latestVersion}`)
|
||||
}
|
||||
|
||||
return latestVersion
|
||||
} catch (error) {
|
||||
console.error('Error fetching Payload version:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-sqlite",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The officially supported SQLite database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-vercel-postgres",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "Vercel Postgres adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/drizzle",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "A library of shared functions used by different payload database adapters",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -28,8 +28,6 @@ export async function migrateReset(this: DrizzleAdapter): Promise<void> {
|
||||
|
||||
const req = await createLocalReq({}, payload)
|
||||
|
||||
existingMigrations.reverse()
|
||||
|
||||
// Rollback all migrations in order
|
||||
for (const migration of existingMigrations) {
|
||||
const migrationFile = migrationFiles.find((m) => m.name === migration.name)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-nodemailer",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "Payload Nodemailer Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-resend",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "Payload Resend Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-react",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The official React SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-vue",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The official Vue SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The official live preview JavaScript SDK for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -59,7 +59,6 @@ export const DocumentTabLink: React.FC<{
|
||||
className={[baseClass, isActive && `${baseClass}--active`].filter(Boolean).join(' ')}
|
||||
disabled={isActive}
|
||||
el={!isActive || href !== pathname ? 'link' : 'div'}
|
||||
margin={false}
|
||||
newTab={newTab}
|
||||
size="medium"
|
||||
to={!isActive || href !== pathname ? hrefWithLocale : undefined}
|
||||
|
||||
@@ -30,7 +30,7 @@ export const DefaultNavClient: React.FC<{
|
||||
|
||||
const [folderCollectionSlugs] = React.useState<string[]>(() => {
|
||||
return collections.reduce<string[]>((acc, collection) => {
|
||||
if (collection.folders) {
|
||||
if (collection.admin.folders) {
|
||||
acc.push(collection.slug)
|
||||
}
|
||||
return acc
|
||||
|
||||
@@ -76,8 +76,9 @@ export const buildBrowseByFolderView = async (
|
||||
|
||||
const { breadcrumbs, documents, subfolders } = await getFolderData({
|
||||
folderID,
|
||||
req: initPageResult.req,
|
||||
payload: initPageResult.req.payload,
|
||||
search: query?.search as string,
|
||||
user: initPageResult.req.user,
|
||||
})
|
||||
|
||||
const resolvedFolderID = breadcrumbs[breadcrumbs.length - 1]?.id
|
||||
@@ -87,7 +88,7 @@ export const buildBrowseByFolderView = async (
|
||||
((resolvedFolderID && folderID && folderID !== resolvedFolderID) ||
|
||||
(folderID && !resolvedFolderID))
|
||||
) {
|
||||
redirect(
|
||||
return redirect(
|
||||
formatAdminURL({
|
||||
adminRoute,
|
||||
path: config.admin.routes.browseByFolder,
|
||||
|
||||
@@ -11,9 +11,6 @@ export const BrowseByFolder: React.FC<BuildFolderViewArgs> = async (args) => {
|
||||
const { View } = await buildBrowseByFolderView(args)
|
||||
return View
|
||||
} catch (error) {
|
||||
if (error?.message === 'NEXT_REDIRECT') {
|
||||
throw error
|
||||
}
|
||||
if (error.message === 'not-found') {
|
||||
notFound()
|
||||
} else {
|
||||
|
||||
@@ -112,8 +112,9 @@ export const buildCollectionFolderView = async (
|
||||
const { breadcrumbs, documents, subfolders } = await getFolderData({
|
||||
collectionSlug,
|
||||
folderID,
|
||||
req: initPageResult.req,
|
||||
payload: initPageResult.req.payload,
|
||||
search: query?.search as string,
|
||||
user: initPageResult.req.user,
|
||||
})
|
||||
|
||||
const resolvedFolderID = breadcrumbs[breadcrumbs.length - 1]?.id
|
||||
@@ -123,7 +124,7 @@ export const buildCollectionFolderView = async (
|
||||
((resolvedFolderID && folderID && folderID !== resolvedFolderID) ||
|
||||
(folderID && !resolvedFolderID))
|
||||
) {
|
||||
redirect(
|
||||
return redirect(
|
||||
formatAdminURL({
|
||||
adminRoute,
|
||||
path: `/collections/${collectionSlug}/${config.folders.slug}`,
|
||||
|
||||
@@ -11,9 +11,6 @@ export const CollectionFolderView: React.FC<BuildCollectionFolderViewStateArgs>
|
||||
const { View } = await buildCollectionFolderView(args)
|
||||
return View
|
||||
} catch (error) {
|
||||
if (error?.message === 'NEXT_REDIRECT') {
|
||||
throw error
|
||||
}
|
||||
if (error.message === 'not-found') {
|
||||
notFound()
|
||||
} else {
|
||||
|
||||
@@ -20,11 +20,7 @@ export const resolveAllFilterOptions = async ({
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
(field.type === 'relationship' || field.type === 'upload') &&
|
||||
'filterOptions' in field &&
|
||||
field.filterOptions
|
||||
) {
|
||||
if ('name' in field && 'filterOptions' in field && field.filterOptions) {
|
||||
const options = await resolveFilterOptions(field.filterOptions, {
|
||||
id: undefined,
|
||||
blockData: undefined,
|
||||
|
||||
@@ -113,8 +113,8 @@ export const getRouteData = ({
|
||||
let matchedCollection: SanitizedConfig['collections'][number] = undefined
|
||||
let matchedGlobal: SanitizedConfig['globals'][number] = undefined
|
||||
|
||||
const folderCollectionSlugs = config.collections.reduce((acc, { slug, folders }) => {
|
||||
if (folders) {
|
||||
const folderCollectionSlugs = config.collections.reduce((acc, { slug, admin }) => {
|
||||
if (admin?.folders) {
|
||||
return [...acc, slug]
|
||||
}
|
||||
return acc
|
||||
|
||||
@@ -45,8 +45,8 @@ export const generatePageMetadata = async ({
|
||||
const config = await configPromise
|
||||
const params = await paramsPromise
|
||||
|
||||
const folderCollectionSlugs = config.collections.reduce((acc, { slug, folders }) => {
|
||||
if (folders) {
|
||||
const folderCollectionSlugs = config.collections.reduce((acc, { slug, admin }) => {
|
||||
if (admin?.folders) {
|
||||
return [...acc, slug]
|
||||
}
|
||||
return acc
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/payload-cloud",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The official Payload Cloud plugin",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
|
||||
"keywords": [
|
||||
"admin panel",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { Option, SelectField, SelectFieldClient } from '../../fields/config/types.js'
|
||||
import type { SelectField, SelectFieldClient } from '../../fields/config/types.js'
|
||||
import type { SelectFieldValidation } from '../../fields/validations.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
ClientFieldBase,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type SupportedLanguages } from '@payloadcms/translations'
|
||||
|
||||
import type { SanitizedDocumentPermissions } from '../../auth/types.js'
|
||||
import type { Field, Option, Validate } from '../../fields/config/types.js'
|
||||
import type { Field, Validate } from '../../fields/config/types.js'
|
||||
import type { TypedLocale } from '../../index.js'
|
||||
import type { DocumentPreferences } from '../../preferences/types.js'
|
||||
import type { PayloadRequest, SelectType, Where } from '../../types/index.js'
|
||||
@@ -67,10 +67,6 @@ export type FieldState = {
|
||||
lastRenderedPath?: string
|
||||
passesCondition?: boolean
|
||||
rows?: Row[]
|
||||
/**
|
||||
* The result of running `field.filterOptions` on select fields.
|
||||
*/
|
||||
selectFilterOptions?: Option[]
|
||||
valid?: boolean
|
||||
validate?: Validate
|
||||
value?: unknown
|
||||
|
||||
@@ -69,6 +69,7 @@ export const addDefaultsToCollectionConfig = (collection: CollectionConfig): Col
|
||||
custom: {},
|
||||
enableRichTextLink: true,
|
||||
enableRichTextRelationship: true,
|
||||
folders: false,
|
||||
useAsTitle: 'id',
|
||||
...(collection.admin || {}),
|
||||
pagination: {
|
||||
@@ -82,7 +83,6 @@ export const addDefaultsToCollectionConfig = (collection: CollectionConfig): Col
|
||||
collection.custom = collection.custom ?? {}
|
||||
collection.endpoints = collection.endpoints ?? []
|
||||
collection.fields = collection.fields ?? []
|
||||
collection.folders = collection.folders ?? false
|
||||
|
||||
collection.hooks = {
|
||||
afterChange: [],
|
||||
|
||||
@@ -345,6 +345,10 @@ export type CollectionAdminOptions = {
|
||||
disableCopyToLocale?: boolean
|
||||
enableRichTextLink?: boolean
|
||||
enableRichTextRelationship?: boolean
|
||||
/**
|
||||
* Enables folders for this collection
|
||||
*/
|
||||
folders?: CollectionFoldersConfiguration
|
||||
/**
|
||||
* Specify a navigational group for collections in the admin sidebar.
|
||||
* - Provide a string to place the entity in a custom group.
|
||||
@@ -440,10 +444,6 @@ export type CollectionConfig<TSlug extends CollectionSlug = any> = {
|
||||
*/
|
||||
endpoints?: false | Omit<Endpoint, 'root'>[]
|
||||
fields: Field[]
|
||||
/**
|
||||
* Enables folders for this collection
|
||||
*/
|
||||
folders?: CollectionFoldersConfiguration
|
||||
/**
|
||||
* Specify which fields should be selected always, regardless of the `select` query which can be useful that the field exists for access control / hooks
|
||||
*/
|
||||
|
||||
@@ -851,7 +851,7 @@ export type Config = {
|
||||
*
|
||||
* @default '/browse-by-folder'
|
||||
*/
|
||||
browseByFolder?: `/${string}`
|
||||
browseByFolder: `/${string}`
|
||||
/** The route for the create first user page.
|
||||
*
|
||||
* @default '/create-first-user'
|
||||
@@ -985,7 +985,6 @@ export type Config = {
|
||||
endpoints?: Endpoint[]
|
||||
/**
|
||||
* Options for folder view within the admin panel
|
||||
* @experimental this feature may change in minor versions until it is fully stable
|
||||
*/
|
||||
folders?: RootFoldersConfiguration
|
||||
/**
|
||||
|
||||
@@ -21,8 +21,6 @@ export async function migrateReset(this: BaseDatabaseAdapter): Promise<void> {
|
||||
|
||||
const req = await createLocalReq({}, payload)
|
||||
|
||||
migrationFiles.reverse()
|
||||
|
||||
// Rollback all migrations in order
|
||||
for (const migration of migrationFiles) {
|
||||
// Create or update migration in database
|
||||
|
||||
@@ -55,9 +55,10 @@ export { formatFolderOrDocumentItem } from '../folders/utils/formatFolderOrDocum
|
||||
export { validOperators, validOperatorSet } from '../types/constants.js'
|
||||
|
||||
export { formatFilesize } from '../uploads/formatFilesize.js'
|
||||
export { isImage } from '../uploads/isImage.js'
|
||||
|
||||
export { isImage } from '../uploads/isImage.js'
|
||||
export { combineWhereConstraints } from '../utilities/combineWhereConstraints.js'
|
||||
|
||||
export {
|
||||
deepCopyObject,
|
||||
deepCopyObjectComplex,
|
||||
@@ -73,14 +74,12 @@ export {
|
||||
} from '../utilities/deepMerge.js'
|
||||
|
||||
export { extractID } from '../utilities/extractID.js'
|
||||
|
||||
export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON.js'
|
||||
export { flattenAllFields } from '../utilities/flattenAllFields.js'
|
||||
export { default as flattenTopLevelFields } from '../utilities/flattenTopLevelFields.js'
|
||||
|
||||
export { default as flattenTopLevelFields } from '../utilities/flattenTopLevelFields.js'
|
||||
export { formatAdminURL } from '../utilities/formatAdminURL.js'
|
||||
export { formatLabels, toWords } from '../utilities/formatLabels.js'
|
||||
export { getBestFitFromSizes } from '../utilities/getBestFitFromSizes.js'
|
||||
export { getDataByPath } from '../utilities/getDataByPath.js'
|
||||
|
||||
export { getFieldPermissions } from '../utilities/getFieldPermissions.js'
|
||||
|
||||
@@ -36,7 +36,7 @@ export type ServerOnlyFieldProperties =
|
||||
| 'dbName' // can be a function
|
||||
| 'editor' // This is a `richText` only property
|
||||
| 'enumName' // can be a function
|
||||
| 'filterOptions' // This is a `relationship`, `upload`, and `select` only property
|
||||
| 'filterOptions' // This is a `relationship` and `upload` only property
|
||||
| 'graphQL'
|
||||
| 'label'
|
||||
| 'typescriptSchema'
|
||||
@@ -53,7 +53,7 @@ const serverOnlyFieldProperties: Partial<ServerOnlyFieldProperties>[] = [
|
||||
'access',
|
||||
'validate',
|
||||
'defaultValue',
|
||||
'filterOptions', // This is a `relationship`, `upload`, and `select` only property
|
||||
'filterOptions', // This is a `relationship` and `upload` only property
|
||||
'editor', // This is a `richText` only property
|
||||
'custom',
|
||||
'typescriptSchema',
|
||||
@@ -67,12 +67,10 @@ const serverOnlyFieldProperties: Partial<ServerOnlyFieldProperties>[] = [
|
||||
// `tabs`
|
||||
// `admin`
|
||||
]
|
||||
|
||||
const serverOnlyFieldAdminProperties: Partial<ServerOnlyFieldAdminProperties>[] = [
|
||||
'condition',
|
||||
'components',
|
||||
]
|
||||
|
||||
type FieldWithDescription = {
|
||||
admin: AdminClient
|
||||
} & ClientField
|
||||
|
||||
@@ -42,7 +42,6 @@ import type {
|
||||
CollapsibleFieldLabelClientComponent,
|
||||
CollapsibleFieldLabelServerComponent,
|
||||
ConditionalDateProps,
|
||||
Data,
|
||||
DateFieldClientProps,
|
||||
DateFieldErrorClientComponent,
|
||||
DateFieldErrorServerComponent,
|
||||
@@ -1104,19 +1103,8 @@ export type SelectField = {
|
||||
* Customize the DB enum name
|
||||
*/
|
||||
enumName?: DBIdentifierName
|
||||
/**
|
||||
* Reduce the available options based on the current user, value of another field, etc.
|
||||
* Similar to the `filterOptions` property on `relationship` and `upload` fields, except with a different return type.
|
||||
*/
|
||||
filterOptions?: (args: {
|
||||
data: Data
|
||||
options: Option[]
|
||||
req: PayloadRequest
|
||||
siblingData: Data
|
||||
}) => Option[]
|
||||
hasMany?: boolean
|
||||
/**
|
||||
* Customize generated GraphQL and Typescript schema names.
|
||||
/** Customize generated GraphQL and Typescript schema names.
|
||||
* By default, it is bound to the collection.
|
||||
*
|
||||
* This is useful if you would like to generate a top level type to share amongst collections/fields.
|
||||
|
||||
@@ -327,7 +327,7 @@ describe('Field Validations', () => {
|
||||
},
|
||||
],
|
||||
}
|
||||
it('should allow valid input', async () => {
|
||||
it('should allow valid input', () => {
|
||||
const val = 'one'
|
||||
const result = select(val, selectOptions)
|
||||
expect(result).toStrictEqual(true)
|
||||
|
||||
@@ -865,23 +865,13 @@ export type SelectFieldSingleValidation = Validate<string, unknown, unknown, Sel
|
||||
|
||||
export const select: SelectFieldValidation = (
|
||||
value,
|
||||
{ data, filterOptions, hasMany, options, req, req: { t }, required, siblingData },
|
||||
{ hasMany, options, req: { t }, required },
|
||||
) => {
|
||||
const filteredOptions =
|
||||
typeof filterOptions === 'function'
|
||||
? filterOptions({
|
||||
data,
|
||||
options,
|
||||
req,
|
||||
siblingData,
|
||||
})
|
||||
: options
|
||||
|
||||
if (
|
||||
Array.isArray(value) &&
|
||||
value.some(
|
||||
(input) =>
|
||||
!filteredOptions.some(
|
||||
!options.some(
|
||||
(option) => option === input || (typeof option !== 'string' && option?.value === input),
|
||||
),
|
||||
)
|
||||
@@ -891,7 +881,7 @@ export const select: SelectFieldValidation = (
|
||||
|
||||
if (
|
||||
typeof value === 'string' &&
|
||||
!filteredOptions.some(
|
||||
!options.some(
|
||||
(option) => option === value || (typeof option !== 'string' && option.value === value),
|
||||
)
|
||||
) {
|
||||
|
||||
@@ -15,23 +15,25 @@ export async function addFolderCollections(config: NonNullable<Config>): Promise
|
||||
|
||||
for (let i = 0; i < config.collections.length; i++) {
|
||||
const collection = config.collections[i]
|
||||
if (collection && collection?.folders) {
|
||||
collection.fields.push({
|
||||
name: folderFieldName,
|
||||
type: 'relationship',
|
||||
admin: {
|
||||
allowCreate: false,
|
||||
allowEdit: false,
|
||||
components: {
|
||||
Cell: '@payloadcms/ui/rsc#FolderTableCell',
|
||||
Field: '@payloadcms/ui/rsc#FolderEditField',
|
||||
if (collection?.admin?.folders) {
|
||||
if (collection) {
|
||||
collection.fields.push({
|
||||
name: folderFieldName,
|
||||
type: 'relationship',
|
||||
admin: {
|
||||
allowCreate: false,
|
||||
allowEdit: false,
|
||||
components: {
|
||||
Cell: '@payloadcms/ui/rsc#FolderTableCell',
|
||||
Field: '@payloadcms/ui/rsc#FolderEditField',
|
||||
},
|
||||
},
|
||||
},
|
||||
index: true,
|
||||
label: 'Folder',
|
||||
relationTo: folderSlug,
|
||||
})
|
||||
enabledCollectionSlugs.push(collection.slug)
|
||||
index: true,
|
||||
label: 'Folder',
|
||||
relationTo: folderSlug,
|
||||
})
|
||||
enabledCollectionSlugs.push(collection.slug)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CollectionConfig } from '../collections/config/types.js'
|
||||
|
||||
import { populateFolderDataEndpoint } from './endpoints/populateFolderData.js'
|
||||
import { deleteSubfoldersBeforeDelete } from './hooks/deleteSubfoldersAfterDelete.js'
|
||||
import { deleteSubfoldersAfterDelete } from './hooks/deleteSubfoldersAfterDelete.js'
|
||||
import { dissasociateAfterDelete } from './hooks/dissasociateAfterDelete.js'
|
||||
import { reparentChildFolder } from './hooks/reparentChildFolder.js'
|
||||
|
||||
@@ -61,8 +61,8 @@ export const createFolderCollection = ({
|
||||
collectionSlugs,
|
||||
folderFieldName,
|
||||
}),
|
||||
deleteSubfoldersAfterDelete({ folderFieldName, folderSlug: slug }),
|
||||
],
|
||||
beforeDelete: [deleteSubfoldersBeforeDelete({ folderFieldName, folderSlug: slug })],
|
||||
},
|
||||
labels: {
|
||||
plural: 'Folders',
|
||||
|
||||
@@ -33,8 +33,9 @@ export const populateFolderDataEndpoint: Endpoint = {
|
||||
const data = await getFolderData({
|
||||
collectionSlug: req.searchParams?.get('collectionSlug') || undefined,
|
||||
folderID: req.searchParams?.get('folderID') || undefined,
|
||||
req,
|
||||
payload: req.payload,
|
||||
search: req.searchParams?.get('search') || undefined,
|
||||
user: req.user,
|
||||
})
|
||||
|
||||
return Response.json(data)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { CollectionBeforeDeleteHook } from '../../index.js'
|
||||
import type { CollectionAfterDeleteHook } from '../../index.js'
|
||||
|
||||
type Args = {
|
||||
folderFieldName: string
|
||||
folderSlug: string
|
||||
}
|
||||
export const deleteSubfoldersBeforeDelete = ({
|
||||
export const deleteSubfoldersAfterDelete = ({
|
||||
folderFieldName,
|
||||
folderSlug,
|
||||
}: Args): CollectionBeforeDeleteHook => {
|
||||
}: Args): CollectionAfterDeleteHook => {
|
||||
return async ({ id, req }) => {
|
||||
await req.payload.delete({
|
||||
collection: folderSlug,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { CollectionSlug, Document } from '../../index.js'
|
||||
import type { FolderOrDocument } from '../types.js'
|
||||
|
||||
import { isImage } from '../../uploads/isImage.js'
|
||||
import { getBestFitFromSizes } from '../../utilities/getBestFitFromSizes.js'
|
||||
|
||||
type Args = {
|
||||
folderFieldName: string
|
||||
isUpload: boolean
|
||||
@@ -20,7 +17,7 @@ export function formatFolderOrDocumentItem({
|
||||
}: Args): FolderOrDocument {
|
||||
const itemValue: FolderOrDocument['value'] = {
|
||||
id: value?.id,
|
||||
_folderOrDocumentTitle: String((useAsTitle && value?.[useAsTitle]) || value['id']),
|
||||
_folderOrDocumentTitle: (useAsTitle && value?.[useAsTitle]) || value['id'],
|
||||
createdAt: value?.createdAt,
|
||||
folderID: value?.[folderFieldName],
|
||||
updatedAt: value?.updatedAt,
|
||||
@@ -29,15 +26,7 @@ export function formatFolderOrDocumentItem({
|
||||
if (isUpload) {
|
||||
itemValue.filename = value.filename
|
||||
itemValue.mimeType = value.mimeType
|
||||
itemValue.url = isImage(value.mimeType)
|
||||
? getBestFitFromSizes({
|
||||
sizes: value.sizes,
|
||||
targetSizeMax: 520,
|
||||
targetSizeMin: 300,
|
||||
url: value.url,
|
||||
width: value.width,
|
||||
})
|
||||
: undefined
|
||||
itemValue.url = value.url
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import type { Document, PayloadRequest } from '../../types/index.js'
|
||||
import type { User } from '../../index.js'
|
||||
import type { Document, Payload } from '../../types/index.js'
|
||||
import type { FolderBreadcrumb } from '../types.js'
|
||||
|
||||
type GetFolderBreadcrumbsArgs = {
|
||||
breadcrumbs?: FolderBreadcrumb[]
|
||||
folderID?: number | string
|
||||
req: PayloadRequest
|
||||
payload: Payload
|
||||
user?: User
|
||||
}
|
||||
/**
|
||||
* Builds breadcrumbs up from child folder
|
||||
@@ -13,9 +15,9 @@ type GetFolderBreadcrumbsArgs = {
|
||||
export const getFolderBreadcrumbs = async ({
|
||||
breadcrumbs = [],
|
||||
folderID,
|
||||
req,
|
||||
payload,
|
||||
user,
|
||||
}: GetFolderBreadcrumbsArgs): Promise<FolderBreadcrumb[] | null> => {
|
||||
const { payload, user } = req
|
||||
const folderFieldName: string = payload.config.folders.fieldName
|
||||
if (folderID) {
|
||||
const folderQuery = await payload.find({
|
||||
@@ -23,7 +25,6 @@ export const getFolderBreadcrumbs = async ({
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
overrideAccess: false,
|
||||
req,
|
||||
select: {
|
||||
name: true,
|
||||
[folderFieldName]: true,
|
||||
@@ -51,7 +52,8 @@ export const getFolderBreadcrumbs = async ({
|
||||
typeof folder[folderFieldName] === 'string'
|
||||
? folder[folderFieldName]
|
||||
: folder[folderFieldName].id,
|
||||
req,
|
||||
payload,
|
||||
user,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
import type { CollectionSlug, User } from '../../index.js'
|
||||
import type { Payload } from '../../types/index.js'
|
||||
import type { GetFolderDataResult } from '../types.js'
|
||||
|
||||
import { parseDocumentID } from '../../index.js'
|
||||
@@ -19,11 +19,20 @@ type Args = {
|
||||
* @default undefined
|
||||
*/
|
||||
folderID?: number | string
|
||||
req: PayloadRequest
|
||||
/**
|
||||
* The locale to use for the document query
|
||||
* @default undefined
|
||||
*/
|
||||
payload: Payload
|
||||
/**
|
||||
* Search term to filter documents by - only applicable IF `collectionSlug` exists and NO `folderID` is provided
|
||||
*/
|
||||
search?: string
|
||||
/**
|
||||
* The user making the request
|
||||
* @default undefined
|
||||
*/
|
||||
user?: User
|
||||
}
|
||||
/**
|
||||
* Query for documents, subfolders and breadcrumbs for a given folder
|
||||
@@ -31,10 +40,10 @@ type Args = {
|
||||
export const getFolderData = async ({
|
||||
collectionSlug,
|
||||
folderID: _folderID,
|
||||
req,
|
||||
payload,
|
||||
search,
|
||||
user,
|
||||
}: Args): Promise<GetFolderDataResult> => {
|
||||
const { payload, user } = req
|
||||
const parentFolderID = parseDocumentID({
|
||||
id: _folderID,
|
||||
collectionSlug: payload.config.folders.slug,
|
||||
@@ -43,7 +52,8 @@ export const getFolderData = async ({
|
||||
|
||||
const breadcrumbsPromise = getFolderBreadcrumbs({
|
||||
folderID: parentFolderID,
|
||||
req,
|
||||
payload,
|
||||
user,
|
||||
})
|
||||
|
||||
if (parentFolderID) {
|
||||
@@ -51,7 +61,8 @@ export const getFolderData = async ({
|
||||
const documentAndSubfolderPromise = queryDocumentsAndFoldersFromJoin({
|
||||
collectionSlug,
|
||||
parentFolderID,
|
||||
req,
|
||||
payload,
|
||||
user,
|
||||
})
|
||||
const [breadcrumbs, documentsAndSubfolders] = await Promise.all([
|
||||
breadcrumbsPromise,
|
||||
@@ -67,14 +78,16 @@ export const getFolderData = async ({
|
||||
// subfolders and documents are queried separately
|
||||
const subfoldersPromise = getOrphanedDocs({
|
||||
collectionSlug: payload.config.folders.slug,
|
||||
req,
|
||||
payload,
|
||||
search,
|
||||
user,
|
||||
})
|
||||
const documentsPromise = collectionSlug
|
||||
? getOrphanedDocs({
|
||||
collectionSlug,
|
||||
req,
|
||||
payload,
|
||||
search,
|
||||
user,
|
||||
})
|
||||
: Promise.resolve([])
|
||||
const [breadcrumbs, subfolders, documents] = await Promise.all([
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { User } from '../../auth/types.js'
|
||||
import type { PaginatedDocs } from '../../database/types.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { Document, PayloadRequest } from '../../types/index.js'
|
||||
import type { Document, Payload } from '../../types/index.js'
|
||||
import type { FolderOrDocument } from '../types.js'
|
||||
|
||||
import { formatFolderOrDocumentItem } from './formatFolderOrDocumentItem.js'
|
||||
@@ -12,17 +13,18 @@ type QueryDocumentsAndFoldersResults = {
|
||||
type QueryDocumentsAndFoldersArgs = {
|
||||
collectionSlug?: CollectionSlug
|
||||
parentFolderID: number | string
|
||||
req: PayloadRequest
|
||||
payload: Payload
|
||||
user?: User
|
||||
}
|
||||
export async function queryDocumentsAndFoldersFromJoin({
|
||||
collectionSlug,
|
||||
parentFolderID,
|
||||
req,
|
||||
payload,
|
||||
user,
|
||||
}: QueryDocumentsAndFoldersArgs): Promise<QueryDocumentsAndFoldersResults> {
|
||||
const { payload, user } = req
|
||||
const folderCollectionSlugs: string[] = payload.config.collections.reduce<string[]>(
|
||||
(acc, collection) => {
|
||||
if (collection?.folders) {
|
||||
if (collection?.admin?.folders) {
|
||||
acc.push(collection.slug)
|
||||
}
|
||||
return acc
|
||||
@@ -48,7 +50,6 @@ export async function queryDocumentsAndFoldersFromJoin({
|
||||
},
|
||||
limit: 1,
|
||||
overrideAccess: false,
|
||||
req,
|
||||
user,
|
||||
where: {
|
||||
id: {
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import type { CollectionSlug, PayloadRequest, Where } from '../../index.js'
|
||||
import type { CollectionSlug, Payload, User, Where } from '../../index.js'
|
||||
import type { FolderOrDocument } from '../types.js'
|
||||
|
||||
import { formatFolderOrDocumentItem } from './formatFolderOrDocumentItem.js'
|
||||
|
||||
type Args = {
|
||||
collectionSlug: CollectionSlug
|
||||
req: PayloadRequest
|
||||
payload: Payload
|
||||
search?: string
|
||||
user?: User
|
||||
}
|
||||
export async function getOrphanedDocs({
|
||||
collectionSlug,
|
||||
req,
|
||||
payload,
|
||||
search,
|
||||
user,
|
||||
}: Args): Promise<FolderOrDocument[]> {
|
||||
const { payload, user } = req
|
||||
let whereConstraints: Where = {
|
||||
or: [
|
||||
{
|
||||
@@ -41,7 +42,6 @@ export async function getOrphanedDocs({
|
||||
collection: collectionSlug,
|
||||
limit: 0,
|
||||
overrideAccess: false,
|
||||
req,
|
||||
sort: payload.collections[collectionSlug].config.admin.useAsTitle,
|
||||
user,
|
||||
where: whereConstraints,
|
||||
|
||||
@@ -30,7 +30,7 @@ export function findUpSync({
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found && dir !== root) {
|
||||
if (!found) {
|
||||
dir = path.dirname(dir) // Move up one directory level.
|
||||
continue
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export async function findUp({
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found && dir !== root) {
|
||||
if (!found) {
|
||||
dir = path.dirname(dir) // Move up one directory level.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud-storage",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "The official cloud storage plugin for Payload CMS",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-form-builder",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "Form builder plugin for Payload CMS",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-import-export",
|
||||
"version": "3.39.1",
|
||||
"version": "3.38.0",
|
||||
"description": "Import-Export plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user