Compare commits
28 Commits
v3.0.0-bet
...
v3.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d6e7f8a37 | ||
|
|
3d37d74c6e | ||
|
|
de19822ed4 | ||
|
|
2b2bcb5264 | ||
|
|
e9b01e6d9f | ||
|
|
b0a760193e | ||
|
|
95569e44e4 | ||
|
|
11816080a6 | ||
|
|
3a86822f0a | ||
|
|
6f8604e18c | ||
|
|
aec3f5e308 | ||
|
|
e0a5de6730 | ||
|
|
5eee49da9a | ||
|
|
b7d01dec70 | ||
|
|
0618130fe3 | ||
|
|
cd245793fc | ||
|
|
3a6c75a1a3 | ||
|
|
5a683b6947 | ||
|
|
9b27f03e61 | ||
|
|
89746ebe09 | ||
|
|
eacf2030cd | ||
|
|
86428539f5 | ||
|
|
a7f519c53a | ||
|
|
49a2d70fbb | ||
|
|
cb7fa00a6f | ||
|
|
a212cdef3f | ||
|
|
4f323a3754 | ||
|
|
f5e7578b41 |
2
.github/actions/setup/action.yml
vendored
2
.github/actions/setup/action.yml
vendored
@@ -25,7 +25,7 @@ runs:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ inputs.pnpm-version }}
|
||||
run_install: false
|
||||
|
||||
20
.github/workflows/main.yml
vendored
20
.github/workflows/main.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
@@ -217,7 +217,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
@@ -332,7 +332,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
@@ -407,7 +407,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
@@ -420,7 +420,7 @@ jobs:
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- name: Start MongoDB
|
||||
uses: supercharge/mongodb-github-action@1.10.0
|
||||
uses: supercharge/mongodb-github-action@1.11.0
|
||||
with:
|
||||
mongodb-version: 6.0
|
||||
|
||||
@@ -451,7 +451,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
@@ -492,7 +492,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Start MongoDB
|
||||
uses: supercharge/mongodb-github-action@1.10.0
|
||||
uses: supercharge/mongodb-github-action@1.11.0
|
||||
with:
|
||||
mongodb-version: 6.0
|
||||
|
||||
@@ -520,7 +520,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
|
||||
@@ -145,7 +145,7 @@ Instead, we utilize component paths to reference React Components. This method e
|
||||
|
||||
When constructing the `ClientConfig`, Payload uses the component paths as keys to fetch the corresponding React Component imports from the Import Map. It then substitutes the `PayloadComponent` with a `MappedComponent`. A `MappedComponent` includes the React Component and additional metadata, such as whether it's a server or a client component and which props it should receive. These components are then rendered through the `<RenderComponent />` component within the Payload Admin Panel.
|
||||
|
||||
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map.
|
||||
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map. If you encounter any errors running this command, see the [Troubleshooting](/docs/beta/local-api/outside-nextjs#troubleshooting) section.
|
||||
|
||||
### Component paths in external packages
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ For more granular control, pass a configuration object instead. Payload exposes
|
||||
|
||||
| Property | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **`Component`** \* | Pass in the component that should be rendered when a user navigates to this route. |
|
||||
| **`Component`** \* | Pass in the component path that should be rendered when a user navigates to this route. |
|
||||
| **`path`** \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
|
||||
| **`exact`** | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
|
||||
| **`strict`** | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
|
||||
@@ -111,7 +111,20 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
|
||||
components: {
|
||||
views: {
|
||||
edit: {
|
||||
Component: '/path/to/MyCustomEditView', // highlight-line
|
||||
root: {
|
||||
Component: '/path/to/MyCustomEditView', // highlight-line
|
||||
}
|
||||
// other options include:
|
||||
// default
|
||||
// versions
|
||||
// version
|
||||
// api
|
||||
// livePreview
|
||||
// [key: string]
|
||||
// See "Document Views" for more details
|
||||
},
|
||||
list: {
|
||||
Component: '/path/to/MyCustomListView',
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -123,7 +136,7 @@ _For details on how to build Custom Views, see [Building Custom Views](#building
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
The `Edit` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `Edit.Default` key instead.
|
||||
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
|
||||
</Banner>
|
||||
|
||||
The following options are available:
|
||||
@@ -152,18 +165,29 @@ export const MyGlobalConfig: SanitizedGlobalConfig = {
|
||||
admin: {
|
||||
components: {
|
||||
views: {
|
||||
edit: '/path/to/MyCustomEditView', // highlight-line
|
||||
edit: {
|
||||
root: {
|
||||
Component: '/path/to/MyCustomEditView', // highlight-line
|
||||
}
|
||||
// other options include:
|
||||
// default
|
||||
// versions
|
||||
// version
|
||||
// api
|
||||
// livePreview
|
||||
// [key: string]
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
The `Edit` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `Edit.Default` key instead.
|
||||
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
|
||||
</Banner>
|
||||
|
||||
The following options are available:
|
||||
@@ -199,25 +223,26 @@ export const MyCollectionOrGlobalConfig: SanitizedCollectionConfig = {
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
If you need to replace the _entire_ Edit View, including _all_ nested Document Views, use the `Edit` key itself. See [Custom Collection Views](#collection-views) or [Custom Global Views](#global-views) for more information.
|
||||
If you need to replace the _entire_ Edit View, including _all_ nested Document Views, use the `root` key. See [Custom Collection Views](#collection-views) or [Custom Global Views](#global-views) for more information.
|
||||
</Banner>
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Property | Description |
|
||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`default`** | The Default view is the primary view in which your document is edited. |
|
||||
| **`versions`** | The Versions view is used to view the version history of a single document. [More details](../versions). |
|
||||
| **`version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
|
||||
| **`api`** | The API view is used to display the REST API JSON response for a given document. |
|
||||
| **`livePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview). |
|
||||
| **`root`** | The Root View overrides all other nested views and routes. No document controls or tabs are rendered when this key is set. |
|
||||
| **`default`** | The Default View is the primary view in which your document is edited. It is rendered within the "Edit" tab. |
|
||||
| **`versions`** | The Versions View is used to navigate the version history of a single document. It is rendered within the "Versions" tab. [More details](../versions). |
|
||||
| **`version`** | The Version View is used to edit a single version of a document. It is rendered within the "Version" tab. [More details](../versions). |
|
||||
| **`api`** | The API View is used to display the REST API JSON response for a given document. It is rendered within the "API" tab. |
|
||||
| **`livePreview`** | The LivePreview view is used to display the Live Preview interface. It is rendered within the "Live Preview" tab. [More details](../live-preview). |
|
||||
|
||||
### Document Tabs
|
||||
|
||||
|
||||
@@ -61,14 +61,27 @@ payload run src/seed.ts
|
||||
The `payload run` command does two things for you:
|
||||
|
||||
1. It loads the environment variables the same way Next.js loads them, eliminating the need for additional dependencies like `dotenv`. The usage of `dotenv` is not recommended, as Next.js loads environment variables differently. By using `payload run`, you ensure consistent environment variable handling across your Payload and Next.js setup.
|
||||
2. It initializes swc, allowing direct execution of TypeScript files without requiring tools like tsx or ts-node.
|
||||
2. It initializes tsx, allowing direct execution of TypeScript files manually installing tools like tsx or ts-node.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you encounter import-related errors, try running the script in TSX mode:
|
||||
If you encounter import-related errors, you have 2 options:
|
||||
|
||||
#### Option 1: enable swc mode by appending `--use-swc` to the `payload` command:
|
||||
|
||||
Example:
|
||||
```sh
|
||||
payload run src/seed.ts --use-tsx
|
||||
payload run src/seed.ts --use-swc
|
||||
```
|
||||
|
||||
Note: Install tsx in your project first. Be aware that TSX mode is slower than the default swc mode, so only use it if necessary.
|
||||
Note: Install @swc-node/register in your project first. While swc mode is faster than the default tsx mode, it might break for some imports.
|
||||
|
||||
#### Option 2: use an alternative runtime like bun
|
||||
|
||||
While we do not guarantee support for alternative runtimes, you are free to use them and disable payloads own transpilation by appending the `--disable-transpilation` flag to the `payload` command:
|
||||
|
||||
```sh
|
||||
bunx --bun payload run src/seed.ts --disable-transpile
|
||||
```
|
||||
|
||||
You will need to have bun installed on your system for this to work.
|
||||
|
||||
@@ -119,7 +119,7 @@ A function that allows you to return any meta title, including from document's c
|
||||
{
|
||||
// ...
|
||||
seoPlugin({
|
||||
generateTitle: ({ ...docInfo, doc, locale }) => `Website.com — ${doc?.title}`,
|
||||
generateTitle: ({ ...docInfo, doc, locale, req }) => `Website.com — ${doc?.title}`,
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -133,7 +133,7 @@ A function that allows you to return any meta description, including from docume
|
||||
{
|
||||
// ...
|
||||
seoPlugin({
|
||||
generateDescription: ({ ...docInfo, doc, locale }) => doc?.excerpt,
|
||||
generateDescription: ({ ...docInfo, doc, locale, req }) => doc?.excerpt,
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -147,7 +147,7 @@ A function that allows you to return any meta image, including from document's c
|
||||
{
|
||||
// ...
|
||||
seoPlugin({
|
||||
generateImage: ({ ...docInfo, doc, locale }) => doc?.featuredImage,
|
||||
generateImage: ({ ...docInfo, doc, locale, req }) => doc?.featuredImage,
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -161,7 +161,7 @@ A function called by the search preview component to display the actual URL of y
|
||||
{
|
||||
// ...
|
||||
seoPlugin({
|
||||
generateURL: ({ ...docInfo, doc, locale }) =>
|
||||
generateURL: ({ ...docInfo, doc, locale, req }) =>
|
||||
`https://yoursite.com/${collection?.slug}/${doc?.slug}`,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ export const rootEslintConfig = [
|
||||
'payload/no-jsx-import-statements': 'warn',
|
||||
'payload/no-relative-monorepo-imports': 'error',
|
||||
'payload/no-imports-from-exports-dir': 'error',
|
||||
'payload/no-imports-from-self': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -103,6 +103,8 @@
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@payloadcms/eslint-plugin": "workspace:*",
|
||||
"@payloadcms/live-preview-react": "workspace:*",
|
||||
"@payloadcms/db-postgres": "workspace:*",
|
||||
"drizzle-kit": "0.23.2-df9e596",
|
||||
"@playwright/test": "1.46.0",
|
||||
"@swc-node/register": "1.10.9",
|
||||
"@swc/cli": "0.4.0",
|
||||
@@ -164,6 +166,7 @@
|
||||
"node": "^18.20.2 || >=20.9.0",
|
||||
"pnpm": "^9.7.0"
|
||||
},
|
||||
"packageManager": "pnpm@9.7.0",
|
||||
"pnpm": {
|
||||
"allowedDeprecatedVersions": {
|
||||
"abab": "2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-sqlite",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The officially supported SQLite database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/drizzle",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "A library of shared functions used by different payload database adapters",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
@@ -58,11 +58,13 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./types": {
|
||||
"import": "./dist/types.js",
|
||||
"types": "./dist/types.d.ts"
|
||||
"types": "./dist/types.d.ts",
|
||||
"default": "./dist/types.js"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-nodemailer",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Payload Nodemailer Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-resend",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Payload Resend Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
67
packages/eslint-plugin/customRules/no-imports-from-self.js
Normal file
67
packages/eslint-plugin/customRules/no-imports-from-self.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
export const rule = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow a package from importing from itself',
|
||||
category: 'Best Practices',
|
||||
recommended: true,
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
let packageName = null
|
||||
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
const importPath = node.source.value
|
||||
const pkgName = getPackageName(context, packageName)
|
||||
if (pkgName && importPath.startsWith(pkgName)) {
|
||||
context.report({
|
||||
node,
|
||||
message: `Package "${pkgName}" should not import from itself. Use relative instead.`,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default rule
|
||||
|
||||
/**
|
||||
* @param {import('eslint').Rule.RuleContext} context
|
||||
* @param {string|undefined} packageName
|
||||
*/
|
||||
function getPackageName(context, packageName) {
|
||||
if (packageName) {
|
||||
return packageName
|
||||
}
|
||||
|
||||
const fileName = context.getFilename()
|
||||
const pkg = findNearestPackageJson(path.dirname(fileName))
|
||||
if (pkg) {
|
||||
return pkg.name
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} startDir
|
||||
*/
|
||||
function findNearestPackageJson(startDir) {
|
||||
let currentDir = startDir
|
||||
while (currentDir !== path.dirname(currentDir)) {
|
||||
// Root directory check
|
||||
const pkgPath = path.join(currentDir, 'package.json')
|
||||
if (fs.existsSync(pkgPath)) {
|
||||
const pkgContent = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
||||
return pkgContent
|
||||
}
|
||||
currentDir = path.dirname(currentDir)
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export const rule = {
|
||||
const importPath = node.source.value
|
||||
|
||||
// Match imports starting with any number of "../" followed by "packages/"
|
||||
const regex = /^(\.\.\/)*packages\/[^/]+\/src/
|
||||
const regex = /^(\.\.\/)*((?!src\b)\w+\/)+src\//
|
||||
|
||||
if (regex.test(importPath)) {
|
||||
context.report({
|
||||
|
||||
@@ -3,6 +3,7 @@ import noNonRetryableAssertions from './customRules/no-non-retryable-assertions.
|
||||
import noRelativeMonorepoImports from './customRules/no-relative-monorepo-imports.js'
|
||||
import noImportsFromExportsDir from './customRules/no-imports-from-exports-dir.js'
|
||||
import noFlakyAssertions from './customRules/no-flaky-assertions.js'
|
||||
import noImportsFromSelf from './customRules/no-imports-from-self.js'
|
||||
|
||||
/**
|
||||
* @type {import('eslint').ESLint.Plugin}
|
||||
@@ -13,6 +14,7 @@ const index = {
|
||||
'no-non-retryable-assertions': noNonRetryableAssertions,
|
||||
'no-relative-monorepo-imports': noRelativeMonorepoImports,
|
||||
'no-imports-from-exports-dir': noImportsFromExportsDir,
|
||||
'no-imports-from-self': noImportsFromSelf,
|
||||
'no-flaky-assertions': noFlakyAssertions,
|
||||
'no-wait-function': {
|
||||
create: function (context) {
|
||||
|
||||
@@ -1,21 +1,54 @@
|
||||
#!/usr/bin/env node
|
||||
#!/usr/bin/env node --no-deprecation
|
||||
|
||||
import { register } from 'node:module'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||
|
||||
// Allow disabling SWC for debugging
|
||||
if (process.env.DISABLE_SWC !== 'true') {
|
||||
const useSwc = process.argv.includes('--use-swc')
|
||||
const disableTranspile = process.argv.includes('--disable-transpile')
|
||||
|
||||
if (disableTranspile) {
|
||||
// Remove --disable-transpile from arguments
|
||||
process.argv = process.argv.filter((arg) => arg !== '--disable-transpile')
|
||||
|
||||
const start = async () => {
|
||||
const { bin } = await import('./dist/bin/index.js')
|
||||
await bin()
|
||||
}
|
||||
|
||||
void start()
|
||||
} else {
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
const url = pathToFileURL(dirname).toString() + '/'
|
||||
|
||||
register('@swc-node/register/esm', url)
|
||||
}
|
||||
if (!useSwc) {
|
||||
const start = async () => {
|
||||
// Use tsx
|
||||
let tsImport = (await import('tsx/esm/api')).tsImport
|
||||
|
||||
const start = async () => {
|
||||
const { bin } = await import('./dist/bin/index.js')
|
||||
await bin()
|
||||
}
|
||||
const { bin } = await tsImport('./dist/bin/index.js', url)
|
||||
await bin()
|
||||
}
|
||||
|
||||
void start()
|
||||
void start()
|
||||
} else if (useSwc) {
|
||||
const { register } = await import('node:module')
|
||||
// Remove --use-swc from arguments
|
||||
process.argv = process.argv.filter((arg) => arg !== '--use-swc')
|
||||
|
||||
try {
|
||||
register('@swc-node/register/esm', url)
|
||||
} catch (_) {
|
||||
console.error(
|
||||
'@swc-node/register is not installed. Please install @swc-node/register in your project, if you want to use swc in payload run.',
|
||||
)
|
||||
}
|
||||
|
||||
const start = async () => {
|
||||
const { bin } = await import('./dist/bin/index.js')
|
||||
await bin()
|
||||
}
|
||||
|
||||
void start()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -43,7 +43,7 @@
|
||||
"dependencies": {
|
||||
"graphql-scalars": "1.22.2",
|
||||
"pluralize": "8.0.0",
|
||||
"@swc-node/register": "1.10.9",
|
||||
"tsx": "4.17.0",
|
||||
"ts-essentials": "7.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-react",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"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.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The official Vue SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The official live preview JavaScript SDK for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
.doc-header {
|
||||
width: 100%;
|
||||
margin-top: base(0.5);
|
||||
padding-bottom: calc(var(--base) * 1.5);
|
||||
margin-top: base(0.4);
|
||||
padding-bottom: calc(var(--base) * 1.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
@@ -27,6 +27,9 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0;
|
||||
padding-bottom: base(0.2);
|
||||
line-height: 1;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@include mid-break {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
position: absolute;
|
||||
order: 3;
|
||||
left: unset;
|
||||
inset-inline-end: base(0.5);
|
||||
inset-inline-end: base(0.8);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--theme-elevation-600);
|
||||
@@ -16,8 +16,8 @@
|
||||
border: none;
|
||||
|
||||
svg {
|
||||
width: base(0.75);
|
||||
height: base(0.75);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -33,10 +33,11 @@
|
||||
|
||||
.toast-title {
|
||||
line-height: base(1);
|
||||
margin-right: base(1);
|
||||
}
|
||||
|
||||
.payload-toast-item {
|
||||
padding: base(0.5);
|
||||
padding: base(0.8);
|
||||
color: var(--theme-elevation-800);
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
@@ -69,8 +70,8 @@
|
||||
}
|
||||
|
||||
.toast-icon {
|
||||
width: base(1);
|
||||
height: base(1);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -84,8 +85,8 @@
|
||||
|
||||
&.toast-warning {
|
||||
color: var(--theme-warning-800);
|
||||
border-color: var(--theme-warning-150);
|
||||
background-color: var(--theme-warning-50);
|
||||
border-color: var(--theme-warning-250);
|
||||
background-color: var(--theme-warning-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-warning-600);
|
||||
@@ -98,8 +99,8 @@
|
||||
|
||||
&.toast-error {
|
||||
color: var(--theme-error-800);
|
||||
border-color: var(--theme-error-150);
|
||||
background-color: var(--theme-error-50);
|
||||
border-color: var(--theme-error-250);
|
||||
background-color: var(--theme-error-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-error-600);
|
||||
@@ -112,8 +113,8 @@
|
||||
|
||||
&.toast-success {
|
||||
color: var(--theme-success-800);
|
||||
border-color: var(--theme-success-150);
|
||||
background-color: var(--theme-success-50);
|
||||
border-color: var(--theme-success-250);
|
||||
background-color: var(--theme-success-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-success-600);
|
||||
@@ -126,8 +127,8 @@
|
||||
|
||||
&.toast-info {
|
||||
color: var(--theme-elevation-800);
|
||||
border-color: var(--theme-elevation-150);
|
||||
background-color: var(--theme-elevation-50);
|
||||
border-color: var(--theme-elevation-250);
|
||||
background-color: var(--theme-elevation-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-elevation-600);
|
||||
|
||||
@@ -66,139 +66,89 @@ export const getViewsFromConfig = ({
|
||||
config?.admin?.livePreview?.globals?.includes(globalConfig?.slug)
|
||||
|
||||
if (collectionConfig) {
|
||||
const editConfig = collectionConfig?.admin?.components?.views?.edit
|
||||
const EditOverride = typeof editConfig === 'function' ? editConfig : null
|
||||
const [collectionEntity, collectionSlug, segment3, segment4, segment5, ...remainingSegments] =
|
||||
routeSegments
|
||||
|
||||
if (EditOverride) {
|
||||
CustomView = EditOverride
|
||||
}
|
||||
|
||||
if (!EditOverride) {
|
||||
const [collectionEntity, collectionSlug, segment3, segment4, segment5, ...remainingSegments] =
|
||||
routeSegments
|
||||
|
||||
if (!docPermissions?.read?.permission) {
|
||||
notFound()
|
||||
} else {
|
||||
// `../:id`, or `../create`
|
||||
switch (routeSegments.length) {
|
||||
case 3: {
|
||||
switch (segment3) {
|
||||
case 'create': {
|
||||
if ('create' in docPermissions && docPermissions?.create?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'default'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultEditView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
if (!docPermissions?.read?.permission) {
|
||||
notFound()
|
||||
} else {
|
||||
// `../:id`, or `../create`
|
||||
switch (routeSegments.length) {
|
||||
case 3: {
|
||||
switch (segment3) {
|
||||
case 'create': {
|
||||
if ('create' in docPermissions && docPermissions?.create?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'default'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultEditView,
|
||||
}
|
||||
break
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// `../:id/api`, `../:id/preview`, `../:id/versions`, etc
|
||||
case 4: {
|
||||
switch (segment4) {
|
||||
case 'api': {
|
||||
if (collectionConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'api'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultAPIView,
|
||||
}
|
||||
}
|
||||
break
|
||||
default: {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'default'),
|
||||
}
|
||||
|
||||
case 'preview': {
|
||||
if (livePreviewEnabled) {
|
||||
DefaultView = {
|
||||
Component: DefaultLivePreviewView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'versions': {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'versions'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionsView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
const baseRoute = [
|
||||
adminRoute !== '/' && adminRoute,
|
||||
'collections',
|
||||
collectionSlug,
|
||||
segment3,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
const currentRoute = [baseRoute, segment4, segment5, ...remainingSegments]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByRoute({
|
||||
baseRoute,
|
||||
currentRoute,
|
||||
views,
|
||||
}),
|
||||
}
|
||||
break
|
||||
DefaultView = {
|
||||
Component: DefaultEditView,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// `../:id/versions/:version`, etc
|
||||
default: {
|
||||
if (segment4 === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
// `../:id/api`, `../:id/preview`, `../:id/versions`, etc
|
||||
case 4: {
|
||||
switch (segment4) {
|
||||
case 'api': {
|
||||
if (collectionConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'version'),
|
||||
payloadComponent: getCustomViewByKey(views, 'api'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionView,
|
||||
Component: DefaultAPIView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'preview': {
|
||||
if (livePreviewEnabled) {
|
||||
DefaultView = {
|
||||
Component: DefaultLivePreviewView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'versions': {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'versions'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionsView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
const baseRoute = [
|
||||
adminRoute !== '/' && adminRoute,
|
||||
collectionEntity,
|
||||
'collections',
|
||||
collectionSlug,
|
||||
segment3,
|
||||
]
|
||||
@@ -216,144 +166,176 @@ export const getViewsFromConfig = ({
|
||||
views,
|
||||
}),
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// `../:id/versions/:version`, etc
|
||||
default: {
|
||||
if (segment4 === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'version'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const baseRoute = [
|
||||
adminRoute !== '/' && adminRoute,
|
||||
collectionEntity,
|
||||
collectionSlug,
|
||||
segment3,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
const currentRoute = [baseRoute, segment4, segment5, ...remainingSegments]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByRoute({
|
||||
baseRoute,
|
||||
currentRoute,
|
||||
views,
|
||||
}),
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (globalConfig) {
|
||||
const editConfig = globalConfig?.admin?.components?.views?.edit
|
||||
const EditOverride = typeof editConfig === 'function' ? editConfig : null
|
||||
const [globalEntity, globalSlug, segment3, ...remainingSegments] = routeSegments
|
||||
|
||||
if (EditOverride) {
|
||||
CustomView = EditOverride
|
||||
}
|
||||
|
||||
if (!EditOverride) {
|
||||
const [globalEntity, globalSlug, segment3, ...remainingSegments] = routeSegments
|
||||
|
||||
if (!docPermissions?.read?.permission) {
|
||||
notFound()
|
||||
} else {
|
||||
switch (routeSegments.length) {
|
||||
case 2: {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'default'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultEditView,
|
||||
}
|
||||
break
|
||||
if (!docPermissions?.read?.permission) {
|
||||
notFound()
|
||||
} else {
|
||||
switch (routeSegments.length) {
|
||||
case 2: {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'default'),
|
||||
}
|
||||
|
||||
case 3: {
|
||||
// `../:slug/api`, `../:slug/preview`, `../:slug/versions`, etc
|
||||
switch (segment3) {
|
||||
case 'api': {
|
||||
if (globalConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'api'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultAPIView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'preview': {
|
||||
if (livePreviewEnabled) {
|
||||
DefaultView = {
|
||||
Component: DefaultLivePreviewView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'versions': {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'versions'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionsView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
if (docPermissions?.read?.permission) {
|
||||
const baseRoute = [adminRoute, globalEntity, globalSlug, segment3]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
const currentRoute = [baseRoute, segment3, ...remainingSegments]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByRoute({
|
||||
baseRoute,
|
||||
currentRoute,
|
||||
views,
|
||||
}),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultEditView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
DefaultView = {
|
||||
Component: DefaultEditView,
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
// `../:slug/versions/:version`, etc
|
||||
if (segment3 === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
case 3: {
|
||||
// `../:slug/api`, `../:slug/preview`, `../:slug/versions`, etc
|
||||
switch (segment3) {
|
||||
case 'api': {
|
||||
if (globalConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'version'),
|
||||
payloadComponent: getCustomViewByKey(views, 'api'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionView,
|
||||
Component: DefaultAPIView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'preview': {
|
||||
if (livePreviewEnabled) {
|
||||
DefaultView = {
|
||||
Component: DefaultLivePreviewView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'versions': {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByKey(views, 'versions'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionsView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const baseRoute = [adminRoute !== '/' && adminRoute, 'globals', globalSlug]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
break
|
||||
}
|
||||
|
||||
const currentRoute = [baseRoute, segment3, ...remainingSegments]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
default: {
|
||||
if (docPermissions?.read?.permission) {
|
||||
const baseRoute = [adminRoute, globalEntity, globalSlug, segment3]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
const currentRoute = [baseRoute, segment3, ...remainingSegments]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByRoute({
|
||||
baseRoute,
|
||||
currentRoute,
|
||||
views,
|
||||
}),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultEditView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
// `../:slug/versions/:version`, etc
|
||||
if (segment3 === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByRoute({
|
||||
baseRoute,
|
||||
currentRoute,
|
||||
views,
|
||||
}),
|
||||
payloadComponent: getCustomViewByKey(views, 'version'),
|
||||
}
|
||||
DefaultView = {
|
||||
Component: DefaultVersionView,
|
||||
}
|
||||
} else {
|
||||
ErrorView = {
|
||||
Component: UnauthorizedView,
|
||||
}
|
||||
}
|
||||
break
|
||||
} else {
|
||||
const baseRoute = [adminRoute !== '/' && adminRoute, 'globals', globalSlug]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
const currentRoute = [baseRoute, segment3, ...remainingSegments]
|
||||
.filter(Boolean)
|
||||
.join('/')
|
||||
|
||||
CustomView = {
|
||||
payloadComponent: getCustomViewByRoute({
|
||||
baseRoute,
|
||||
currentRoute,
|
||||
views,
|
||||
}),
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
|
||||
const isEditing = getIsEditing({ id, collectionSlug, globalSlug })
|
||||
|
||||
let ViewOverride: MappedComponent<ServerSideEditViewProps>
|
||||
let RootViewOverride: MappedComponent<ServerSideEditViewProps>
|
||||
let CustomView: MappedComponent<ServerSideEditViewProps>
|
||||
let DefaultView: MappedComponent<ServerSideEditViewProps>
|
||||
let ErrorView: MappedComponent<AdminViewProps>
|
||||
@@ -115,19 +115,18 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
|
||||
apiURL = `${serverURL}${apiRoute}/${collectionSlug}/${id}${apiQueryParams}`
|
||||
|
||||
ViewOverride =
|
||||
collectionConfig?.admin?.components?.views?.edit?.default &&
|
||||
'Component' in collectionConfig.admin.components.views.edit.default
|
||||
RootViewOverride =
|
||||
collectionConfig?.admin?.components?.views?.edit?.root &&
|
||||
'Component' in collectionConfig.admin.components.views.edit.root
|
||||
? createMappedComponent(
|
||||
collectionConfig?.admin?.components?.views?.edit?.default
|
||||
?.Component as EditViewComponent, // some type info gets lost from Config => SanitizedConfig due to our usage of Deep type operations from ts-essentials. Despite .Component being defined as EditViewComponent, this info is lost and we need cast it here.
|
||||
collectionConfig?.admin?.components?.views?.edit?.root?.Component as EditViewComponent, // some type info gets lost from Config => SanitizedConfig due to our usage of Deep type operations from ts-essentials. Despite .Component being defined as EditViewComponent, this info is lost and we need cast it here.
|
||||
undefined,
|
||||
undefined,
|
||||
'collectionConfig?.admin?.components?.views?.edit?.default',
|
||||
'collectionConfig?.admin?.components?.views?.edit?.root',
|
||||
)
|
||||
: null
|
||||
|
||||
if (!ViewOverride) {
|
||||
if (!RootViewOverride) {
|
||||
const collectionViews = getViewsFromConfig({
|
||||
collectionConfig,
|
||||
config,
|
||||
@@ -157,7 +156,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
)
|
||||
}
|
||||
|
||||
if (!CustomView && !DefaultView && !ViewOverride && !ErrorView) {
|
||||
if (!CustomView && !DefaultView && !RootViewOverride && !ErrorView) {
|
||||
ErrorView = createMappedComponent(undefined, undefined, NotFoundView, 'NotFoundView')
|
||||
}
|
||||
}
|
||||
@@ -170,9 +169,11 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
const params = new URLSearchParams({
|
||||
locale: locale?.code,
|
||||
})
|
||||
|
||||
if (globalConfig.versions?.drafts) {
|
||||
params.append('draft', 'true')
|
||||
}
|
||||
|
||||
if (locale?.code) {
|
||||
params.append('locale', locale.code)
|
||||
}
|
||||
@@ -181,10 +182,18 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
|
||||
apiURL = `${serverURL}${apiRoute}/${globalSlug}${apiQueryParams}`
|
||||
|
||||
const editConfig = globalConfig?.admin?.components?.views?.edit
|
||||
ViewOverride = typeof editConfig === 'function' ? editConfig : null
|
||||
RootViewOverride =
|
||||
globalConfig?.admin?.components?.views?.edit?.root &&
|
||||
'Component' in globalConfig.admin.components.views.edit.root
|
||||
? createMappedComponent(
|
||||
globalConfig?.admin?.components?.views?.edit?.root?.Component as EditViewComponent, // some type info gets lost from Config => SanitizedConfig due to our usage of Deep type operations from ts-essentials. Despite .Component being defined as EditViewComponent, this info is lost and we need cast it here.
|
||||
undefined,
|
||||
undefined,
|
||||
'globalConfig?.admin?.components?.views?.edit?.root',
|
||||
)
|
||||
: null
|
||||
|
||||
if (!ViewOverride) {
|
||||
if (!RootViewOverride) {
|
||||
const globalViews = getViewsFromConfig({
|
||||
config,
|
||||
docPermissions,
|
||||
@@ -213,7 +222,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
'globalViews?.ErrorView.payloadComponent',
|
||||
)
|
||||
|
||||
if (!CustomView && !DefaultView && !ViewOverride && !ErrorView) {
|
||||
if (!CustomView && !DefaultView && !RootViewOverride && !ErrorView) {
|
||||
ErrorView = createMappedComponent(undefined, undefined, NotFoundView, 'NotFoundView')
|
||||
}
|
||||
}
|
||||
@@ -268,7 +277,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
initialState={formState}
|
||||
isEditing={isEditing}
|
||||
>
|
||||
{!ViewOverride && (
|
||||
{!RootViewOverride && (
|
||||
<DocumentHeader
|
||||
collectionConfig={collectionConfig}
|
||||
globalConfig={globalConfig}
|
||||
@@ -294,7 +303,9 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
<RenderComponent mappedComponent={ErrorView} />
|
||||
) : (
|
||||
<RenderComponent
|
||||
mappedComponent={ViewOverride ? ViewOverride : CustomView ? CustomView : DefaultView}
|
||||
mappedComponent={
|
||||
RootViewOverride ? RootViewOverride : CustomView ? CustomView : DefaultView
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</EditDepthProvider>
|
||||
|
||||
@@ -149,8 +149,10 @@ export const Auth: React.FC<Props> = (props) => {
|
||||
{(showPasswordFields || requirePassword) && (
|
||||
<div className={`${baseClass}__changing-password`}>
|
||||
<PasswordField
|
||||
autoComplete="new-password"
|
||||
field={{
|
||||
name: 'password',
|
||||
_path: 'password',
|
||||
admin: {
|
||||
disabled,
|
||||
},
|
||||
|
||||
@@ -98,14 +98,18 @@ export const DefaultEditView: React.FC = () => {
|
||||
if (globalSlug) classes.push(`global-edit--${globalSlug}`)
|
||||
if (collectionSlug) classes.push(`collection-edit--${collectionSlug}`)
|
||||
|
||||
const [schemaPath, setSchemaPath] = React.useState(entitySlug)
|
||||
const [schemaPath, setSchemaPath] = React.useState(() => {
|
||||
if (operation === 'create' && auth && !auth.disableLocalStrategy) {
|
||||
return `_${entitySlug}.auth`
|
||||
}
|
||||
|
||||
return entitySlug
|
||||
})
|
||||
const [validateBeforeSubmit, setValidateBeforeSubmit] = useState(() => {
|
||||
if (
|
||||
operation === 'create' &&
|
||||
collectionConfig.auth &&
|
||||
!collectionConfig.auth.disableLocalStrategy
|
||||
)
|
||||
if (operation === 'create' && auth && !auth.disableLocalStrategy) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-end;
|
||||
flex-wrap: wrap;
|
||||
gap: base(0.8);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
.pill {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
margin: 0 0 base(0.2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
#!/usr/bin/env node --no-deprecation
|
||||
#!/usr/bin/env -S node --no-deprecation
|
||||
|
||||
import { register } from 'node:module'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||
|
||||
const useTsx = process.argv.includes('--use-tsx')
|
||||
const useSwc = process.argv.includes('--use-swc')
|
||||
const disableTranspile = process.argv.includes('--disable-transpile')
|
||||
|
||||
// Allow disabling SWC/TSX for debugging
|
||||
if (process.env.DISABLE_SWC !== 'true' && !useTsx) {
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
const url = pathToFileURL(dirname).toString() + '/'
|
||||
|
||||
register('@swc-node/register/esm', url)
|
||||
if (disableTranspile) {
|
||||
// Remove --disable-transpile from arguments
|
||||
process.argv = process.argv.filter((arg) => arg !== '--disable-transpile')
|
||||
|
||||
const start = async () => {
|
||||
const { bin } = await import('./dist/bin/index.js')
|
||||
@@ -20,25 +16,39 @@ if (process.env.DISABLE_SWC !== 'true' && !useTsx) {
|
||||
}
|
||||
|
||||
void start()
|
||||
} else if (useTsx) {
|
||||
// Remove --use-tsx from arguments
|
||||
process.argv = process.argv.filter((arg) => arg !== '--use-tsx')
|
||||
} else {
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
const url = pathToFileURL(dirname).toString() + '/'
|
||||
|
||||
const start = async () => {
|
||||
// Use tsx
|
||||
let tsImport
|
||||
try {
|
||||
tsImport = (await import('tsx/esm/api')).tsImport
|
||||
} catch (_) {
|
||||
console.error(
|
||||
'tsx is not installed. Please install tsx in your project, if you want to use tsx in payload run.',
|
||||
)
|
||||
return
|
||||
if (!useSwc) {
|
||||
const start = async () => {
|
||||
// Use tsx
|
||||
let tsImport = (await import('tsx/esm/api')).tsImport
|
||||
|
||||
const { bin } = await tsImport('./dist/bin/index.js', url)
|
||||
await bin()
|
||||
}
|
||||
|
||||
const { bin } = await tsImport('./dist/bin/index.js', import.meta.url)
|
||||
await bin()
|
||||
}
|
||||
void start()
|
||||
} else if (useSwc) {
|
||||
const { register } = await import('node:module')
|
||||
// Remove --use-swc from arguments
|
||||
process.argv = process.argv.filter((arg) => arg !== '--use-swc')
|
||||
|
||||
void start()
|
||||
try {
|
||||
register('@swc-node/register/esm', url)
|
||||
} catch (_) {
|
||||
console.error(
|
||||
'@swc-node/register is not installed. Please install @swc-node/register in your project, if you want to use swc in payload run.',
|
||||
)
|
||||
}
|
||||
|
||||
const start = async () => {
|
||||
const { bin } = await import('./dist/bin/index.js')
|
||||
await bin()
|
||||
}
|
||||
|
||||
void start()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
|
||||
"keywords": [
|
||||
"admin panel",
|
||||
@@ -86,7 +86,7 @@
|
||||
"dependencies": {
|
||||
"@next/env": "^15.0.0-canary.104",
|
||||
"@payloadcms/translations": "workspace:*",
|
||||
"@swc-node/register": "1.10.9",
|
||||
"tsx": "4.17.0",
|
||||
"ajv": "8.14.0",
|
||||
"bson-objectid": "2.0.4",
|
||||
"ci-info": "^4.0.0",
|
||||
|
||||
@@ -227,8 +227,13 @@ export type MappedClientComponent<TComponentClientProps extends JsonObject = Jso
|
||||
type: 'client'
|
||||
}
|
||||
|
||||
export type MappedEmptyComponent = {
|
||||
type: 'empty'
|
||||
}
|
||||
|
||||
export type MappedComponent<TComponentClientProps extends JsonObject = JsonObject> =
|
||||
| MappedClientComponent<TComponentClientProps>
|
||||
| MappedEmptyComponent
|
||||
| MappedServerComponent<TComponentClientProps>
|
||||
| undefined
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export const apiKeyFields = [
|
||||
type: 'checkbox',
|
||||
admin: {
|
||||
components: {
|
||||
Field: '@payloadcms/ui/shared#emptyComponent',
|
||||
Field: false,
|
||||
},
|
||||
},
|
||||
label: ({ t }) => t('authentication:enableAPIKey'),
|
||||
@@ -23,7 +23,7 @@ export const apiKeyFields = [
|
||||
type: 'text',
|
||||
admin: {
|
||||
components: {
|
||||
Field: '@payloadcms/ui/shared#emptyComponent',
|
||||
Field: false,
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
|
||||
@@ -7,7 +7,7 @@ export const emailFieldConfig: EmailField = {
|
||||
type: 'email',
|
||||
admin: {
|
||||
components: {
|
||||
Field: '@payloadcms/ui/shared#emptyComponent',
|
||||
Field: false,
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
|
||||
@@ -7,7 +7,7 @@ export const usernameFieldConfig: TextField = {
|
||||
type: 'text',
|
||||
admin: {
|
||||
components: {
|
||||
Field: '@payloadcms/ui/shared#emptyComponent',
|
||||
Field: false,
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
|
||||
@@ -26,7 +26,7 @@ export const verificationFields: Field[] = [
|
||||
},
|
||||
admin: {
|
||||
components: {
|
||||
Field: '@payloadcms/ui/shared#emptyComponent',
|
||||
Field: false,
|
||||
},
|
||||
},
|
||||
label: ({ t }) => t('authentication:verified'),
|
||||
|
||||
@@ -44,11 +44,11 @@ export const ensureUsernameOrEmail = <TSlug extends CollectionSlug>({
|
||||
missingFields = true
|
||||
}
|
||||
// prevent clearing email if no username
|
||||
if ('email' in data && !data.email && !originalDoc.username) {
|
||||
if ('email' in data && !data.email && !originalDoc.username && !data?.username) {
|
||||
missingFields = true
|
||||
}
|
||||
// prevent clearing username if no email
|
||||
if ('username' in data && !data.username && !originalDoc.email) {
|
||||
if ('username' in data && !data.username && !originalDoc.email && !data?.email) {
|
||||
missingFields = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export function addPayloadComponentToImportMap({
|
||||
imports[importIdentifier] = {
|
||||
path:
|
||||
componentPath.startsWith('.') || componentPath.startsWith('/')
|
||||
? path.join(baseDir, componentPath.slice(1))
|
||||
? path.posix.join(baseDir.replace(/\\/g, '/'), componentPath.slice(1))
|
||||
: componentPath,
|
||||
specifier: exportName,
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ export function parsePayloadComponent(payloadComponent: PayloadComponent): {
|
||||
exportName: string
|
||||
path: string
|
||||
} {
|
||||
if (!payloadComponent) {
|
||||
return null
|
||||
}
|
||||
const pathAndMaybeExport =
|
||||
typeof payloadComponent === 'string' ? payloadComponent : payloadComponent.path
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import minimist from 'minimist'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import path from 'path'
|
||||
|
||||
import type { BinScript } from '../config/types.js'
|
||||
@@ -29,7 +30,7 @@ export const bin = async () => {
|
||||
process.argv = [process.argv[0], process.argv[1], ...args._.slice(2)]
|
||||
|
||||
try {
|
||||
await import(absoluteScriptPath)
|
||||
await import(pathToFileURL(absoluteScriptPath).toString())
|
||||
} catch (error) {
|
||||
console.error(`Error running script: ${absoluteScriptPath}`)
|
||||
console.error(error)
|
||||
@@ -42,7 +43,7 @@ export const bin = async () => {
|
||||
}
|
||||
|
||||
const configPath = findConfig()
|
||||
const configPromise = await import(configPath)
|
||||
const configPromise = await import(pathToFileURL(configPath).toString())
|
||||
let config = await configPromise
|
||||
if (config.default) config = await config.default
|
||||
|
||||
@@ -52,7 +53,7 @@ export const bin = async () => {
|
||||
|
||||
if (userBinScript) {
|
||||
try {
|
||||
const script: BinScript = await import(userBinScript.scriptPath)
|
||||
const script: BinScript = await import(pathToFileURL(userBinScript.scriptPath).toString())
|
||||
await script(config)
|
||||
} catch (err) {
|
||||
console.log(`Could not find associated bin script for the ${userBinScript.key} command`)
|
||||
|
||||
@@ -22,10 +22,7 @@ const getTSConfigPaths = (): {
|
||||
const rootConfigDir = path.resolve(tsConfigDir, tsConfig.compilerOptions.baseUrl || '')
|
||||
const srcPath = tsConfig.compilerOptions?.rootDir || path.resolve(process.cwd(), 'src')
|
||||
const outPath = tsConfig.compilerOptions?.outDir || path.resolve(process.cwd(), 'dist')
|
||||
let configPath = path.resolve(
|
||||
rootConfigDir,
|
||||
tsConfig.compilerOptions?.paths?.['@payload-config']?.[0],
|
||||
)
|
||||
let configPath = tsConfig.compilerOptions?.paths?.['@payload-config']?.[0]
|
||||
|
||||
if (configPath) {
|
||||
configPath = path.resolve(rootConfigDir, configPath)
|
||||
|
||||
@@ -13,7 +13,7 @@ import type { default as sharp } from 'sharp'
|
||||
import type { DeepRequired } from 'ts-essentials'
|
||||
|
||||
import type { RichTextAdapterProvider } from '../admin/RichText.js'
|
||||
import type { DocumentTabConfig, MappedComponent, RichTextAdapter } from '../admin/types.js'
|
||||
import type { DocumentTabConfig, RichTextAdapter } from '../admin/types.js'
|
||||
import type { AdminViewConfig, ServerSideEditViewProps } from '../admin/views/types.js'
|
||||
import type { Permissions } from '../auth/index.js'
|
||||
import type {
|
||||
@@ -38,12 +38,12 @@ import type { PayloadLogger } from '../utilities/logger.js'
|
||||
/**
|
||||
* The string path pointing to the React component. If one of the generics is `never`, you effectively mark it as a server-only or client-only component.
|
||||
*
|
||||
* If the path is an empty string, it will be treated as () => null
|
||||
* If it is `false` an empty component will be rendered.
|
||||
*/
|
||||
export type PayloadComponent<
|
||||
TComponentServerProps extends never | object = Record<string, any>,
|
||||
TComponentClientProps extends never | object = Record<string, any>,
|
||||
> = RawPayloadComponent<TComponentServerProps, TComponentClientProps> | string
|
||||
> = RawPayloadComponent<TComponentServerProps, TComponentClientProps> | false | string
|
||||
|
||||
// We need the actual object as its own type, otherwise the infers for the PayloadClientReactComponent / PayloadServerReactComponent will not work due to the string union.
|
||||
// We also NEED to actually use those generics for this to work, thus they are part of the props.
|
||||
@@ -912,28 +912,44 @@ export type SanitizedConfig = {
|
||||
'collections' | 'editor' | 'endpoint' | 'globals' | 'i18n' | 'localization' | 'upload'
|
||||
>
|
||||
|
||||
export type EditConfig = {
|
||||
[key: string]: Partial<EditViewConfig>
|
||||
/**
|
||||
* Replace or modify individual nested routes, or add new ones:
|
||||
* + `default` - `/admin/collections/:collection/:id`
|
||||
* + `api` - `/admin/collections/:collection/:id/api`
|
||||
* + `livePreview` - `/admin/collections/:collection/:id/preview`
|
||||
* + `references` - `/admin/collections/:collection/:id/references`
|
||||
* + `relationships` - `/admin/collections/:collection/:id/relationships`
|
||||
* + `versions` - `/admin/collections/:collection/:id/versions`
|
||||
* + `version` - `/admin/collections/:collection/:id/versions/:version`
|
||||
* + `customView` - `/admin/collections/:collection/:id/:path`
|
||||
*/
|
||||
api?: Partial<EditViewConfig>
|
||||
default?: Partial<EditViewConfig>
|
||||
livePreview?: Partial<EditViewConfig>
|
||||
version?: Partial<EditViewConfig>
|
||||
versions?: Partial<EditViewConfig>
|
||||
// TODO: uncomment these as they are built
|
||||
// references?: EditView
|
||||
// relationships?: EditView
|
||||
}
|
||||
export type EditConfig =
|
||||
| {
|
||||
[key: string]: EditViewConfig
|
||||
/**
|
||||
* Replace or modify individual nested routes, or add new ones:
|
||||
* + `default` - `/admin/collections/:collection/:id`
|
||||
* + `api` - `/admin/collections/:collection/:id/api`
|
||||
* + `livePreview` - `/admin/collections/:collection/:id/preview`
|
||||
* + `references` - `/admin/collections/:collection/:id/references`
|
||||
* + `relationships` - `/admin/collections/:collection/:id/relationships`
|
||||
* + `versions` - `/admin/collections/:collection/:id/versions`
|
||||
* + `version` - `/admin/collections/:collection/:id/versions/:version`
|
||||
* + `customView` - `/admin/collections/:collection/:id/:path`
|
||||
*
|
||||
* To override the entire Edit View including all nested views, use the `root` key.
|
||||
*/
|
||||
api?: Partial<EditViewConfig>
|
||||
default?: Partial<EditViewConfig>
|
||||
livePreview?: Partial<EditViewConfig>
|
||||
root?: never
|
||||
version?: Partial<EditViewConfig>
|
||||
versions?: Partial<EditViewConfig>
|
||||
// TODO: uncomment these as they are built
|
||||
// references?: EditView
|
||||
// relationships?: EditView
|
||||
}
|
||||
| {
|
||||
api?: never
|
||||
default?: never
|
||||
livePreview?: never
|
||||
/**
|
||||
* Replace or modify _all_ nested document views and routes, including the document header, controls, and tabs. This cannot be used in conjunction with other nested views.
|
||||
* + `root` - `/admin/collections/:collection/:id/**\/*`
|
||||
*/
|
||||
root: Partial<EditViewConfig>
|
||||
version?: never
|
||||
versions?: never
|
||||
}
|
||||
|
||||
export type EntityDescriptionComponent = CustomComponent
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ export { setsAreEqual } from '../utilities/setsAreEqual.js'
|
||||
|
||||
export { default as toKebabCase } from '../utilities/toKebabCase.js'
|
||||
|
||||
export { unflatten } from '../utilities/unflatten.js'
|
||||
|
||||
export { wait } from '../utilities/wait.js'
|
||||
|
||||
export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex.js'
|
||||
|
||||
@@ -962,7 +962,9 @@ export type SingleRelationshipFieldClient = {
|
||||
|
||||
export type RelationshipField = PolymorphicRelationshipField | SingleRelationshipField
|
||||
|
||||
export type RelationshipFieldClient = PolymorphicRelationshipFieldClient
|
||||
export type RelationshipFieldClient =
|
||||
| PolymorphicRelationshipFieldClient
|
||||
| SingleRelationshipFieldClient
|
||||
|
||||
export type ValueWithRelation = {
|
||||
relationTo: CollectionSlug
|
||||
|
||||
@@ -17,7 +17,7 @@ const baseVersionFields: Field[] = [
|
||||
type: 'select',
|
||||
admin: {
|
||||
components: {
|
||||
Field: '@payloadcms/ui/shared#emptyComponent',
|
||||
Field: false,
|
||||
},
|
||||
disableBulkEdit: true,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud-storage",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The official cloud storage plugin for Payload CMS",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The official Payload Cloud plugin",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-form-builder",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Form builder plugin for Payload CMS",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-nested-docs",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The official Nested Docs plugin for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-redirects",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Redirects plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-relationship-object-ids",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "A Payload plugin to store all relationship IDs as ObjectIDs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-search",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Search plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-seo",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "SEO plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -61,7 +61,7 @@ export const MetaDescriptionComponent: React.FC<MetaDescriptionProps> = (props)
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
} satisfies Parameters<GenerateDescription>[0]),
|
||||
} satisfies Omit<Parameters<GenerateDescription>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -57,7 +57,7 @@ export const MetaImageComponent: React.FC<MetaImageProps> = (props) => {
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
} satisfies Parameters<GenerateImage>[0]),
|
||||
} satisfies Omit<Parameters<GenerateImage>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -62,7 +62,7 @@ export const MetaTitleComponent: React.FC<MetaTitleProps> = (props) => {
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
} satisfies Parameters<GenerateTitle>[0]),
|
||||
} satisfies Omit<Parameters<GenerateTitle>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -49,7 +49,7 @@ export const PreviewComponent: React.FC<PreviewProps> = ({
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
} satisfies Parameters<GenerateURL>[0]),
|
||||
} satisfies Omit<Parameters<GenerateURL>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -134,11 +134,12 @@ export const seoPlugin =
|
||||
{
|
||||
handler: async (req) => {
|
||||
await addDataAndFileToRequest(req)
|
||||
req.t
|
||||
|
||||
const result = pluginConfig.generateTitle
|
||||
? await pluginConfig.generateTitle(
|
||||
req.data as unknown as Parameters<GenerateTitle>[0],
|
||||
)
|
||||
? await pluginConfig.generateTitle({
|
||||
...req.data,
|
||||
req,
|
||||
} as unknown as Parameters<GenerateTitle>[0])
|
||||
: ''
|
||||
return new Response(JSON.stringify({ result }), { status: 200 })
|
||||
},
|
||||
@@ -148,10 +149,12 @@ export const seoPlugin =
|
||||
{
|
||||
handler: async (req) => {
|
||||
await addDataAndFileToRequest(req)
|
||||
|
||||
const result = pluginConfig.generateDescription
|
||||
? await pluginConfig.generateDescription(
|
||||
req.data as unknown as Parameters<GenerateDescription>[0],
|
||||
)
|
||||
? await pluginConfig.generateDescription({
|
||||
...req.data,
|
||||
req,
|
||||
} as unknown as Parameters<GenerateDescription>[0])
|
||||
: ''
|
||||
return new Response(JSON.stringify({ result }), { status: 200 })
|
||||
},
|
||||
@@ -161,8 +164,12 @@ export const seoPlugin =
|
||||
{
|
||||
handler: async (req) => {
|
||||
await addDataAndFileToRequest(req)
|
||||
|
||||
const result = pluginConfig.generateURL
|
||||
? await pluginConfig.generateURL(req.data as unknown as Parameters<GenerateURL>[0])
|
||||
? await pluginConfig.generateURL({
|
||||
...req.data,
|
||||
req,
|
||||
} as unknown as Parameters<GenerateURL>[0])
|
||||
: ''
|
||||
return new Response(JSON.stringify({ result }), { status: 200 })
|
||||
},
|
||||
@@ -172,10 +179,12 @@ export const seoPlugin =
|
||||
{
|
||||
handler: async (req) => {
|
||||
await addDataAndFileToRequest(req)
|
||||
|
||||
const result = pluginConfig.generateImage
|
||||
? await pluginConfig.generateImage(
|
||||
req.data as unknown as Parameters<GenerateImage>[0],
|
||||
)
|
||||
? await pluginConfig.generateImage({
|
||||
...req.data,
|
||||
req,
|
||||
} as unknown as Parameters<GenerateImage>[0])
|
||||
: ''
|
||||
return new Response(result, { status: 200 })
|
||||
},
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import type { DocumentInfoContext } from '@payloadcms/ui'
|
||||
import type { Field, TextField, TextareaField, UploadField } from 'payload'
|
||||
import type { Field, PayloadRequest, TextField, TextareaField, UploadField } from 'payload'
|
||||
|
||||
export type GenerateTitle<T = any> = (
|
||||
args: { doc: T; locale?: string } & DocumentInfoContext,
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type GenerateDescription<T = any> = (
|
||||
args: {
|
||||
doc: T
|
||||
locale?: string
|
||||
req: PayloadRequest
|
||||
} & DocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type GenerateImage<T = any> = (
|
||||
args: { doc: T; locale?: string } & DocumentInfoContext,
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type GenerateURL<T = any> = (
|
||||
args: { doc: T; locale?: string } & DocumentInfoContext,
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type SEOPluginConfig = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-stripe",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Stripe plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-lexical",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
position: absolute;
|
||||
order: 3;
|
||||
left: unset;
|
||||
inset-inline-end: base(0.5);
|
||||
inset-inline-end: base(0.8);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--theme-elevation-600);
|
||||
@@ -16,8 +16,8 @@
|
||||
border: none;
|
||||
|
||||
svg {
|
||||
width: base(0.75);
|
||||
height: base(0.75);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -33,10 +33,11 @@
|
||||
|
||||
.toast-title {
|
||||
line-height: base(1);
|
||||
margin-right: base(1);
|
||||
}
|
||||
|
||||
.payload-toast-item {
|
||||
padding: base(0.5);
|
||||
padding: base(0.8);
|
||||
color: var(--theme-elevation-800);
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
@@ -69,8 +70,8 @@
|
||||
}
|
||||
|
||||
.toast-icon {
|
||||
width: base(1);
|
||||
height: base(1);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -84,8 +85,8 @@
|
||||
|
||||
&.toast-warning {
|
||||
color: var(--theme-warning-800);
|
||||
border-color: var(--theme-warning-150);
|
||||
background-color: var(--theme-warning-50);
|
||||
border-color: var(--theme-warning-250);
|
||||
background-color: var(--theme-warning-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-warning-600);
|
||||
@@ -98,8 +99,8 @@
|
||||
|
||||
&.toast-error {
|
||||
color: var(--theme-error-800);
|
||||
border-color: var(--theme-error-150);
|
||||
background-color: var(--theme-error-50);
|
||||
border-color: var(--theme-error-250);
|
||||
background-color: var(--theme-error-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-error-600);
|
||||
@@ -112,8 +113,8 @@
|
||||
|
||||
&.toast-success {
|
||||
color: var(--theme-success-800);
|
||||
border-color: var(--theme-success-150);
|
||||
background-color: var(--theme-success-50);
|
||||
border-color: var(--theme-success-250);
|
||||
background-color: var(--theme-success-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-success-600);
|
||||
@@ -126,8 +127,8 @@
|
||||
|
||||
&.toast-info {
|
||||
color: var(--theme-elevation-800);
|
||||
border-color: var(--theme-elevation-150);
|
||||
background-color: var(--theme-elevation-50);
|
||||
border-color: var(--theme-elevation-250);
|
||||
background-color: var(--theme-elevation-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-elevation-600);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-slate",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The officially supported Slate richtext adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -3,5 +3,5 @@ import type { RichTextCustomElement } from '../../../types.js'
|
||||
export const textAlign: RichTextCustomElement = {
|
||||
name: 'alignment',
|
||||
Button: '@payloadcms/richtext-slate/client#TextAlignElementButton',
|
||||
Element: '@payloadcms/ui/shared#emptyComponent',
|
||||
Element: false,
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
position: absolute;
|
||||
order: 3;
|
||||
left: unset;
|
||||
inset-inline-end: base(0.5);
|
||||
inset-inline-end: base(0.8);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--theme-elevation-600);
|
||||
@@ -16,8 +16,8 @@
|
||||
border: none;
|
||||
|
||||
svg {
|
||||
width: base(0.75);
|
||||
height: base(0.75);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -33,10 +33,11 @@
|
||||
|
||||
.toast-title {
|
||||
line-height: base(1);
|
||||
margin-right: base(1);
|
||||
}
|
||||
|
||||
.payload-toast-item {
|
||||
padding: base(0.5);
|
||||
padding: base(0.8);
|
||||
color: var(--theme-elevation-800);
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
@@ -69,8 +70,8 @@
|
||||
}
|
||||
|
||||
.toast-icon {
|
||||
width: base(1);
|
||||
height: base(1);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -84,8 +85,8 @@
|
||||
|
||||
&.toast-warning {
|
||||
color: var(--theme-warning-800);
|
||||
border-color: var(--theme-warning-150);
|
||||
background-color: var(--theme-warning-50);
|
||||
border-color: var(--theme-warning-250);
|
||||
background-color: var(--theme-warning-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-warning-600);
|
||||
@@ -98,8 +99,8 @@
|
||||
|
||||
&.toast-error {
|
||||
color: var(--theme-error-800);
|
||||
border-color: var(--theme-error-150);
|
||||
background-color: var(--theme-error-50);
|
||||
border-color: var(--theme-error-250);
|
||||
background-color: var(--theme-error-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-error-600);
|
||||
@@ -112,8 +113,8 @@
|
||||
|
||||
&.toast-success {
|
||||
color: var(--theme-success-800);
|
||||
border-color: var(--theme-success-150);
|
||||
background-color: var(--theme-success-50);
|
||||
border-color: var(--theme-success-250);
|
||||
background-color: var(--theme-success-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-success-600);
|
||||
@@ -126,8 +127,8 @@
|
||||
|
||||
&.toast-info {
|
||||
color: var(--theme-elevation-800);
|
||||
border-color: var(--theme-elevation-150);
|
||||
background-color: var(--theme-elevation-50);
|
||||
border-color: var(--theme-elevation-250);
|
||||
background-color: var(--theme-elevation-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-elevation-600);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-azure",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Payload storage adapter for Azure Blob Storage",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-gcs",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Payload storage adapter for Google Cloud Storage",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-s3",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Payload storage adapter for Amazon S3",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-uploadthing",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Payload storage adapter for uploadthing",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-vercel-blob",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Payload storage adapter for Vercel Blob Storage",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/translations",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/ui",
|
||||
"version": "3.0.0-beta.80",
|
||||
"version": "3.0.0-beta.84",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -155,7 +155,7 @@ export const Autosave: React.FC<Props> = ({
|
||||
}
|
||||
})
|
||||
.then((json) => {
|
||||
if (versionsConfig?.drafts && versionsConfig?.drafts?.validate && json.errors) {
|
||||
if (versionsConfig?.drafts && versionsConfig?.drafts?.validate && json?.errors) {
|
||||
if (Array.isArray(json.errors)) {
|
||||
const [fieldErrors, nonFieldErrors] = json.errors.reduce(
|
||||
([fieldErrs, nonFieldErrs], err) => {
|
||||
@@ -224,7 +224,7 @@ export const Autosave: React.FC<Props> = ({
|
||||
if (autosaveTimeout) clearTimeout(autosaveTimeout)
|
||||
if (abortController.signal) {
|
||||
try {
|
||||
abortController.abort()
|
||||
abortController.abort('Autosave closed early.')
|
||||
} catch (error) {
|
||||
// swallow error
|
||||
}
|
||||
|
||||
@@ -13,13 +13,20 @@ const handleDragOver = (e: DragEvent) => {
|
||||
const baseClass = 'dropzone'
|
||||
|
||||
export type Props = {
|
||||
className?: string
|
||||
mimeTypes?: string[]
|
||||
onChange: (e: FileList) => void
|
||||
onPasteUrlClick?: () => void
|
||||
readonly className?: string
|
||||
readonly mimeTypes?: string[]
|
||||
readonly multipleFiles?: boolean
|
||||
readonly onChange: (e: FileList) => void
|
||||
readonly onPasteUrlClick?: () => void
|
||||
}
|
||||
|
||||
export const Dropzone: React.FC<Props> = ({ className, mimeTypes, onChange, onPasteUrlClick }) => {
|
||||
export const Dropzone: React.FC<Props> = ({
|
||||
className,
|
||||
mimeTypes,
|
||||
multipleFiles,
|
||||
onChange,
|
||||
onPasteUrlClick,
|
||||
}) => {
|
||||
const dropRef = React.useRef<HTMLDivElement>(null)
|
||||
const [dragging, setDragging] = React.useState(false)
|
||||
const inputRef = React.useRef(null)
|
||||
@@ -111,17 +118,21 @@ export const Dropzone: React.FC<Props> = ({ className, mimeTypes, onChange, onPa
|
||||
>
|
||||
{t('upload:selectFile')}
|
||||
</Button>
|
||||
<Button
|
||||
buttonStyle="secondary"
|
||||
className={`${baseClass}__file-button`}
|
||||
onClick={onPasteUrlClick}
|
||||
size="medium"
|
||||
>
|
||||
{t('upload:pasteURL')}
|
||||
</Button>
|
||||
{typeof onPasteUrlClick === 'function' && (
|
||||
<Button
|
||||
buttonStyle="secondary"
|
||||
className={`${baseClass}__file-button`}
|
||||
onClick={onPasteUrlClick}
|
||||
size="medium"
|
||||
>
|
||||
{t('upload:pasteURL')}
|
||||
</Button>
|
||||
)}
|
||||
<input
|
||||
accept={mimeTypes?.join(',')}
|
||||
aria-hidden="true"
|
||||
className={`${baseClass}__hidden-input`}
|
||||
multiple={multipleFiles}
|
||||
onChange={handleFileSelection}
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
'use client'
|
||||
import { CloseMenuIcon, MenuIcon } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import { ChevronIcon } from '../../icons/Chevron/index.js'
|
||||
import { CloseMenuIcon } from '../../icons/CloseMenu/index.js'
|
||||
import { MenuIcon } from '../../icons/Menu/index.js'
|
||||
import { useTranslation } from '../../providers/Translation/index.js'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'hamburger'
|
||||
|
||||
export const Hamburger: React.FC<{
|
||||
closeIcon?: 'collapse' | 'x'
|
||||
isActive?: boolean
|
||||
readonly closeIcon?: 'collapse' | 'x'
|
||||
readonly isActive?: boolean
|
||||
}> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const { closeIcon = 'x', isActive = false } = props
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
@import '../../scss/styles';
|
||||
|
||||
.id-label {
|
||||
font-size: base(0.75);
|
||||
font-size: base(0.8);
|
||||
line-height: base(1.2);
|
||||
font-weight: normal;
|
||||
color: var(--theme-elevation-600);
|
||||
background: var(--theme-elevation-100);
|
||||
padding: 0 base(0.6);
|
||||
padding: base(0.2) base(0.4);
|
||||
border-radius: $style-radius-m;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,10 @@ import AnimateHeightImport from 'react-animate-height'
|
||||
const AnimateHeight = (AnimateHeightImport.default ||
|
||||
AnimateHeightImport) as typeof AnimateHeightImport.default
|
||||
|
||||
import { useListInfo } from '@payloadcms/ui'
|
||||
|
||||
import { useUseTitleField } from '../../hooks/useUseAsTitle.js'
|
||||
import { ChevronIcon } from '../../icons/Chevron/index.js'
|
||||
import { SearchIcon } from '../../icons/Search/index.js'
|
||||
import { useListInfo } from '../../providers/ListInfo/index.js'
|
||||
import { useListQuery } from '../../providers/ListQuery/index.js'
|
||||
import { useSearchParams } from '../../providers/SearchParams/index.js'
|
||||
import { useTranslation } from '../../providers/Translation/index.js'
|
||||
@@ -32,13 +31,13 @@ import './index.scss'
|
||||
const baseClass = 'list-controls'
|
||||
|
||||
export type ListControlsProps = {
|
||||
collectionConfig: ClientCollectionConfig
|
||||
enableColumns?: boolean
|
||||
enableSort?: boolean
|
||||
fields: ClientField[]
|
||||
handleSearchChange?: (search: string) => void
|
||||
handleSortChange?: (sort: string) => void
|
||||
handleWhereChange?: (where: Where) => void
|
||||
readonly collectionConfig: ClientCollectionConfig
|
||||
readonly enableColumns?: boolean
|
||||
readonly enableSort?: boolean
|
||||
readonly fields: ClientField[]
|
||||
readonly handleSearchChange?: (search: string) => void
|
||||
readonly handleSortChange?: (sort: string) => void
|
||||
readonly handleWhereChange?: (where: Where) => void
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
'use client'
|
||||
import type { DropdownIndicatorProps } from 'react-select'
|
||||
|
||||
import { ChevronIcon } from '@payloadcms/ui'
|
||||
import React, { type JSX } from 'react'
|
||||
|
||||
import type { Option as OptionType } from '../types.js'
|
||||
|
||||
import { ChevronIcon } from '../../../icons/Chevron/index.js'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'dropdown-indicator'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@import '../../scss/styles.scss';
|
||||
|
||||
.render-title {
|
||||
display: inline-flex;
|
||||
display: inline-block;
|
||||
&__id {
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
|
||||
@@ -8,10 +8,9 @@ import { useTranslation } from '../../providers/Translation/index.js'
|
||||
import { StepNavProvider, useStepNav } from './context.js'
|
||||
import './index.scss'
|
||||
export { SetStepNav } from './SetStepNav.js'
|
||||
import { PayloadIcon } from '@payloadcms/ui'
|
||||
|
||||
import type { StepNavItem } from './types.js'
|
||||
|
||||
import { PayloadIcon } from '../../graphics/Icon/index.js'
|
||||
import { RenderComponent } from '../../providers/Config/RenderComponent.js'
|
||||
|
||||
const baseClass = 'step-nav'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
import type { DateFieldClient, DefaultCellComponentProps } from 'payload'
|
||||
|
||||
import { useConfig } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import { useConfig } from '../../../../../providers/Config/index.js'
|
||||
import { useTranslation } from '../../../../../providers/Translation/index.js'
|
||||
import { formatDate } from '../../../../../utilities/formatDate.js'
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ import type {
|
||||
StaticLabel,
|
||||
} from 'payload'
|
||||
|
||||
import { DefaultCell } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import type { ColumnPreferences } from '../../providers/ListInfo/index.js'
|
||||
import type { Column } from '../Table/index.js'
|
||||
|
||||
import { DefaultCell } from '../../elements/Table/DefaultCell/index.js'
|
||||
import { FieldLabel } from '../../fields/FieldLabel/index.js'
|
||||
import { flattenFieldMap } from '../../utilities/flattenFieldMap.js'
|
||||
import { SelectAll } from '../SelectAll/index.js'
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
'use client'
|
||||
import type { FormState, SanitizedCollectionConfig, UploadEdits } from 'payload'
|
||||
|
||||
import { useForm, useUploadEdits } from '@payloadcms/ui'
|
||||
import { isImage, reduceFieldsToValues } from 'payload/shared'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { FieldError } from '../../fields/FieldError/index.js'
|
||||
import { fieldBaseClass } from '../../fields/shared/index.js'
|
||||
import { useForm } from '../../forms/Form/index.js'
|
||||
import { useField } from '../../forms/useField/index.js'
|
||||
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
|
||||
import { useTranslation } from '../../providers/Translation/index.js'
|
||||
import { useUploadEdits } from '../../providers/UploadEdits/index.js'
|
||||
import { Button } from '../Button/index.js'
|
||||
import { Drawer, DrawerToggler } from '../Drawer/index.js'
|
||||
import { Dropzone } from '../Dropzone/index.js'
|
||||
@@ -33,10 +34,10 @@ const validate = (value) => {
|
||||
}
|
||||
|
||||
type UploadActionsArgs = {
|
||||
customActions?: React.ReactNode[]
|
||||
enableAdjustments: boolean
|
||||
enablePreviewSizes: boolean
|
||||
mimeType: string
|
||||
readonly customActions?: React.ReactNode[]
|
||||
readonly enableAdjustments: boolean
|
||||
readonly enablePreviewSizes: boolean
|
||||
readonly mimeType: string
|
||||
}
|
||||
|
||||
export const UploadActions = ({
|
||||
@@ -77,11 +78,11 @@ export const UploadActions = ({
|
||||
}
|
||||
|
||||
export type UploadProps = {
|
||||
collectionSlug: string
|
||||
customActions?: React.ReactNode[]
|
||||
initialState?: FormState
|
||||
onChange?: (file?: File) => void
|
||||
uploadConfig: SanitizedCollectionConfig['upload']
|
||||
readonly collectionSlug: string
|
||||
readonly customActions?: React.ReactNode[]
|
||||
readonly initialState?: FormState
|
||||
readonly onChange?: (file?: File) => void
|
||||
readonly uploadConfig: SanitizedCollectionConfig['upload']
|
||||
}
|
||||
|
||||
export const Upload: React.FC<UploadProps> = (props) => {
|
||||
@@ -108,15 +109,7 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
||||
const handleFileChange = useCallback(
|
||||
(newFile: File) => {
|
||||
if (newFile instanceof File) {
|
||||
const fileReader = new FileReader()
|
||||
fileReader.onload = (e) => {
|
||||
const imgSrc = e.target?.result
|
||||
|
||||
if (typeof imgSrc === 'string') {
|
||||
setFileSrc(imgSrc)
|
||||
}
|
||||
}
|
||||
fileReader.readAsDataURL(newFile)
|
||||
setFileSrc(URL.createObjectURL(newFile))
|
||||
}
|
||||
|
||||
setValue(newFile)
|
||||
@@ -201,6 +194,9 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
setDoc(reduceFieldsToValues(initialState || {}, true))
|
||||
if (initialState?.file?.value instanceof File) {
|
||||
setFileSrc(URL.createObjectURL(initialState.file.value))
|
||||
}
|
||||
setReplacingFile(false)
|
||||
}, [initialState])
|
||||
|
||||
@@ -265,7 +261,9 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
||||
<div className={`${baseClass}__add-file-wrap`}>
|
||||
<button
|
||||
className={`${baseClass}__add-file`}
|
||||
onClick={handleUrlSubmit}
|
||||
onClick={() => {
|
||||
void handleUrlSubmit()
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{t('upload:addFile')}
|
||||
|
||||
@@ -32,6 +32,7 @@ export { Collapsible } from '../../elements/Collapsible/index.js'
|
||||
export { CopyToClipboard } from '../../elements/CopyToClipboard/index.js'
|
||||
export { DeleteMany } from '../../elements/DeleteMany/index.js'
|
||||
export { DocumentControls } from '../../elements/DocumentControls/index.js'
|
||||
export { Dropzone } from '../../elements/Dropzone/index.js'
|
||||
export { useDocumentDrawer } from '../../elements/DocumentDrawer/index.js'
|
||||
export { DocumentFields } from '../../elements/DocumentFields/index.js'
|
||||
export { Drawer, DrawerToggler, formatDrawerSlug } from '../../elements/Drawer/index.js'
|
||||
|
||||
@@ -21,5 +21,3 @@ export {
|
||||
} from '../../utilities/groupNavItems.js'
|
||||
export { hasSavePermission } from '../../utilities/hasSavePermission.js'
|
||||
export { isEditing } from '../../utilities/isEditing.js'
|
||||
|
||||
export const emptyComponent = () => null
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
import type { PasswordFieldValidation, PayloadRequest } from 'payload'
|
||||
|
||||
import { useConfig, useLocale, useTranslation } from '@payloadcms/ui'
|
||||
import { password } from 'payload/shared'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
@@ -9,6 +8,9 @@ import type { PasswordFieldProps } from './types.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'
|
||||
import { PasswordInput } from './input.js'
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
import type { ClientField, FieldPermissions } from 'payload'
|
||||
|
||||
import { HiddenField, useFieldComponents } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import { HiddenField } from '../../fields/Hidden/index.js'
|
||||
import { RenderComponent } from '../../providers/Config/RenderComponent.js'
|
||||
import { useFieldComponents } from '../../providers/FieldComponents/index.js'
|
||||
import { useOperation } from '../../providers/Operation/index.js'
|
||||
import { FieldPropsProvider, useFieldProps } from '../FieldPropsProvider/index.js'
|
||||
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
import { usePathname } from 'next/navigation.js'
|
||||
import React from 'react'
|
||||
|
||||
import { useAuth } from '../../providers/Auth/index.js'
|
||||
import { RenderComponent } from '../../providers/Config/RenderComponent.js'
|
||||
import { useConfig } from '../../providers/Config/index.js'
|
||||
import { formatAdminURL } from '../../utilities/formatAdminURL.js'
|
||||
import { GravatarAccountIcon } from './Gravatar/index.js'
|
||||
import { useAuth } from '@payloadcms/ui'
|
||||
import { DefaultAccountIcon } from './Default/index.js'
|
||||
import { GravatarAccountIcon } from './Gravatar/index.js'
|
||||
|
||||
export const Account = () => {
|
||||
const {
|
||||
config: {
|
||||
admin: {
|
||||
avatar,
|
||||
routes: { account: accountRoute },
|
||||
components: { Avatar: CustomAvatar },
|
||||
routes: { account: accountRoute },
|
||||
},
|
||||
routes: { admin: adminRoute },
|
||||
},
|
||||
|
||||
@@ -26,6 +26,6 @@ export const ChevronIcon: React.FC<{
|
||||
width={20}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path className="stroke" d="M6 9L10 13L14 9" strokeLinecap="square" />
|
||||
<path className="stroke" d="M6 8L10 12.5L14 8" strokeLinecap="square" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -13,7 +13,8 @@ export const LogOutIcon: React.FC = () => (
|
||||
>
|
||||
<path
|
||||
className="stroke"
|
||||
d="M8 16H5.33333C4.97971 16 4.64057 15.8595 4.39052 15.6095C4.14048 15.3594 4 15.0203 4 14.6667V5.33333C4 4.97971 4.14048 4.64057 4.39052 4.39052C4.64057 4.14048 4.97971 4 5.33333 4H8M12.6667 13.3333L16 10M16 10L12.6667 6.66667M16 10H8"
|
||||
d="M12 16H14.6667C15.0203 16 15.3594 15.8595 15.6095 15.6095C15.8595 15.3594 16 15.0203 16 14.6667V5.33333C16 4.97971 15.8595 4.64057 15.6095 4.39052C15.3594 4.14048 15.0203 4 14.6667 4H12M7.33333 13.3333L4 10M4 10L7.33333 6.66667M4 10H12"
|
||||
strokeLinecap="square"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
'use client'
|
||||
import type { MappedComponent } from 'payload'
|
||||
|
||||
import { useConfig } from '@payloadcms/ui'
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react'
|
||||
|
||||
import { useConfig } from '../../providers/Config/index.js'
|
||||
|
||||
export { SetViewActions } from './SetViewActions/index.js'
|
||||
|
||||
type ActionsContextType = {
|
||||
@@ -18,7 +19,9 @@ const ActionsContext = createContext<ActionsContextType>({
|
||||
|
||||
export const useActions = () => useContext(ActionsContext)
|
||||
|
||||
export const ActionsProvider = ({ children }) => {
|
||||
export const ActionsProvider: React.FC<{
|
||||
readonly children: React.ReactNode
|
||||
}> = ({ children }) => {
|
||||
const [viewActions, setViewActions] = useState([])
|
||||
const [adminActions, setAdminActions] = useState([])
|
||||
|
||||
|
||||
@@ -263,6 +263,11 @@ export function AuthProvider({
|
||||
}
|
||||
}, [debouncedLocationChange, refreshCookie, id])
|
||||
|
||||
// When initialUser changes, reset in state
|
||||
useEffect(() => {
|
||||
setUser(initialUser)
|
||||
}, [initialUser])
|
||||
|
||||
useEffect(() => {
|
||||
setLastLocationChange(Date.now())
|
||||
}, [pathname])
|
||||
|
||||
@@ -58,6 +58,10 @@ export const RenderComponent: React.FC<{
|
||||
))
|
||||
}
|
||||
|
||||
if (mappedComponent.type === 'empty') {
|
||||
return null
|
||||
}
|
||||
|
||||
if (mappedComponent.RenderedComponent) {
|
||||
return mappedComponent.RenderedComponent
|
||||
}
|
||||
|
||||
@@ -257,7 +257,9 @@ export const createClientCollectionConfig = ({
|
||||
Component: createMappedComponent(
|
||||
hasEditView &&
|
||||
'Component' in collection.admin.components.views.edit.default &&
|
||||
collection.admin.components.views.edit.default.Component,
|
||||
collection.admin.components.views.edit.default.Component
|
||||
? collection.admin.components.views.edit.default.Component
|
||||
: null,
|
||||
{
|
||||
collectionSlug: collection.slug,
|
||||
},
|
||||
@@ -312,7 +314,9 @@ export const createClientCollectionConfig = ({
|
||||
clientCollection.admin.components.views.list.Component = createMappedComponent(
|
||||
hasListView &&
|
||||
'Component' in collection.admin.components.views.list &&
|
||||
collection.admin.components.views.list.Component,
|
||||
collection.admin.components.views.list.Component
|
||||
? collection.admin.components.views.list.Component
|
||||
: null,
|
||||
{
|
||||
collectionSlug: collection.slug,
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ImportMap, PayloadComponent, ResolvedComponent } from 'payload'
|
||||
import { parsePayloadComponent } from 'payload/shared'
|
||||
|
||||
/**
|
||||
* Gets th resolved React component from `PayloadComponent` from the importMap
|
||||
* Gets the resolved React component from `PayloadComponent` from the importMap
|
||||
*/
|
||||
export const getComponent = <
|
||||
TComponentServerProps extends object,
|
||||
@@ -23,6 +23,7 @@ export const getComponent = <
|
||||
silent?: boolean
|
||||
}): ResolvedComponent<TComponentServerProps, TComponentClientProps> => {
|
||||
if (!payloadComponent) {
|
||||
// undefined, null or false
|
||||
return {
|
||||
Component: undefined,
|
||||
clientProps: undefined,
|
||||
@@ -37,11 +38,15 @@ export const getComponent = <
|
||||
const Component = importMap[key]
|
||||
|
||||
if (!Component && !silent) {
|
||||
console.error(`getComponent: Component not found in importMap`, {
|
||||
identifier,
|
||||
key,
|
||||
payloadComponent,
|
||||
})
|
||||
console.error(
|
||||
`getComponent: Component not found in importMap`,
|
||||
{
|
||||
identifier,
|
||||
key,
|
||||
payloadComponent,
|
||||
},
|
||||
'You may need to run the `payload generate:importmap` command to generate the importMap ahead of runtime.',
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -31,7 +31,7 @@ export function getCreateMappedComponent({
|
||||
Fallback: React.FC<any>,
|
||||
identifier: string,
|
||||
): MappedComponent => {
|
||||
if (!payloadComponent) {
|
||||
if (payloadComponent === undefined || payloadComponent === null) {
|
||||
if (!Fallback) {
|
||||
return undefined
|
||||
}
|
||||
@@ -55,6 +55,12 @@ export function getCreateMappedComponent({
|
||||
}
|
||||
}
|
||||
|
||||
if (payloadComponent === false) {
|
||||
return {
|
||||
type: 'empty',
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedComponent =
|
||||
payloadComponent &&
|
||||
typeof payloadComponent === 'object' &&
|
||||
@@ -107,7 +113,7 @@ export function getCreateMappedComponent({
|
||||
fallback,
|
||||
identifier,
|
||||
) => {
|
||||
if (!payloadComponent && !fallback) {
|
||||
if ((payloadComponent === undefined || payloadComponent === null) && !fallback) {
|
||||
return undefined as any
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,9 @@ export const createClientGlobalConfig = ({
|
||||
Component: createMappedComponent(
|
||||
hasEditView &&
|
||||
'Component' in global.admin.components.views.edit.default &&
|
||||
global.admin.components.views.edit.default.Component,
|
||||
global.admin.components.views.edit.default.Component
|
||||
? global.admin.components.views.edit.default.Component
|
||||
: null,
|
||||
{
|
||||
globalSlug: global.slug,
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
position: absolute;
|
||||
order: 3;
|
||||
left: unset;
|
||||
inset-inline-end: base(0.5);
|
||||
inset-inline-end: base(0.8);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--theme-elevation-600);
|
||||
@@ -16,8 +16,8 @@
|
||||
border: none;
|
||||
|
||||
svg {
|
||||
width: base(0.75);
|
||||
height: base(0.75);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -33,10 +33,11 @@
|
||||
|
||||
.toast-title {
|
||||
line-height: base(1);
|
||||
margin-right: base(1);
|
||||
}
|
||||
|
||||
.payload-toast-item {
|
||||
padding: base(0.5);
|
||||
padding: base(0.8);
|
||||
color: var(--theme-elevation-800);
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
@@ -69,8 +70,8 @@
|
||||
}
|
||||
|
||||
.toast-icon {
|
||||
width: base(1);
|
||||
height: base(1);
|
||||
width: base(0.8);
|
||||
height: base(0.8);
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -84,8 +85,8 @@
|
||||
|
||||
&.toast-warning {
|
||||
color: var(--theme-warning-800);
|
||||
border-color: var(--theme-warning-150);
|
||||
background-color: var(--theme-warning-50);
|
||||
border-color: var(--theme-warning-250);
|
||||
background-color: var(--theme-warning-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-warning-600);
|
||||
@@ -98,8 +99,8 @@
|
||||
|
||||
&.toast-error {
|
||||
color: var(--theme-error-800);
|
||||
border-color: var(--theme-error-150);
|
||||
background-color: var(--theme-error-50);
|
||||
border-color: var(--theme-error-250);
|
||||
background-color: var(--theme-error-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-error-600);
|
||||
@@ -112,8 +113,8 @@
|
||||
|
||||
&.toast-success {
|
||||
color: var(--theme-success-800);
|
||||
border-color: var(--theme-success-150);
|
||||
background-color: var(--theme-success-50);
|
||||
border-color: var(--theme-success-250);
|
||||
background-color: var(--theme-success-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-success-600);
|
||||
@@ -126,8 +127,8 @@
|
||||
|
||||
&.toast-info {
|
||||
color: var(--theme-elevation-800);
|
||||
border-color: var(--theme-elevation-150);
|
||||
background-color: var(--theme-elevation-50);
|
||||
border-color: var(--theme-elevation-250);
|
||||
background-color: var(--theme-elevation-100);
|
||||
|
||||
.payload-toast-close-button {
|
||||
color: var(--theme-elevation-600);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user