Compare commits
22 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 |
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
|
||||
|
||||
@@ -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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-beta.81",
|
||||
"version": "3.0.0-beta.84",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-react",
|
||||
"version": "3.0.0-beta.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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);
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
#!/usr/bin/env node --no-deprecation
|
||||
#!/usr/bin/env -S node --no-deprecation
|
||||
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.0.0-beta.81",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
|
||||
"keywords": [
|
||||
"admin panel",
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud-storage",
|
||||
"version": "3.0.0-beta.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"version": "3.0.0-beta.84",
|
||||
"description": "The officially supported Slate 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/storage-azure",
|
||||
"version": "3.0.0-beta.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"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.81",
|
||||
"version": "3.0.0-beta.84",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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 @@
|
||||
import type { Data, FormState } from 'payload'
|
||||
|
||||
import { unflatten as flatleyUnflatten } from '../../../payload/src/utilities/unflatten.js'
|
||||
import { unflatten as flatleyUnflatten } from 'payload/shared'
|
||||
|
||||
type ReturnType = {
|
||||
data: Data
|
||||
|
||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -30,6 +30,9 @@ importers:
|
||||
'@next/bundle-analyzer':
|
||||
specifier: 15.0.0-canary.104
|
||||
version: 15.0.0-canary.104
|
||||
'@payloadcms/db-postgres':
|
||||
specifier: workspace:*
|
||||
version: link:packages/db-postgres
|
||||
'@payloadcms/eslint-config':
|
||||
specifier: workspace:*
|
||||
version: link:packages/eslint-config
|
||||
@@ -99,6 +102,9 @@ importers:
|
||||
dotenv:
|
||||
specifier: 16.4.5
|
||||
version: 16.4.5
|
||||
drizzle-kit:
|
||||
specifier: 0.23.2-df9e596
|
||||
version: 0.23.2-df9e596
|
||||
drizzle-orm:
|
||||
specifier: 0.32.1
|
||||
version: 0.32.1(@libsql/client@0.6.2)(@types/pg@8.10.2)(pg@8.11.3)(react@19.0.0-rc-06d0b89e-20240801)(types-react@19.0.0-rc.0)
|
||||
@@ -1672,6 +1678,9 @@ importers:
|
||||
dotenv:
|
||||
specifier: 16.4.5
|
||||
version: 16.4.5
|
||||
drizzle-kit:
|
||||
specifier: 0.23.2-df9e596
|
||||
version: 0.23.2-df9e596
|
||||
eslint-plugin-playwright:
|
||||
specifier: 1.6.2
|
||||
version: 1.6.2(eslint-plugin-jest@28.6.0(@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@9.6.0)(typescript@5.5.4))(eslint@9.6.0)(typescript@5.5.4))(eslint@9.6.0)(jest@29.7.0(@types/node@20.12.5)(babel-plugin-macros@3.1.0))(typescript@5.5.4))(eslint@9.6.0)
|
||||
|
||||
@@ -120,7 +120,7 @@ describe('auth', () => {
|
||||
await ensureCompilationIsDone({ page, serverURL })
|
||||
})
|
||||
|
||||
describe('authenticated users', () => {
|
||||
describe('passwords', () => {
|
||||
beforeAll(() => {
|
||||
url = new AdminUrlUtil(serverURL, slug)
|
||||
})
|
||||
@@ -155,6 +155,29 @@ describe('auth', () => {
|
||||
await expect(page.locator('#field-email')).toHaveValue(emailBeforeSave)
|
||||
})
|
||||
|
||||
test('should prevent new user creation without confirm password', async () => {
|
||||
await page.goto(url.create)
|
||||
await page.locator('#field-email').fill('dev2@payloadcms.com')
|
||||
await page.locator('#field-password').fill('password')
|
||||
// should fail to save without confirm password
|
||||
await page.locator('#action-save').click()
|
||||
await expect(
|
||||
page.locator('.field-type.confirm-password .tooltip--show', {
|
||||
hasText: exactText('This field is required.'),
|
||||
}),
|
||||
).toBeVisible()
|
||||
|
||||
// should succeed with matching confirm password
|
||||
await page.locator('#field-confirm-password').fill('password')
|
||||
await saveDocAndAssert(page, '#action-save')
|
||||
})
|
||||
})
|
||||
|
||||
describe('authenticated users', () => {
|
||||
beforeAll(() => {
|
||||
url = new AdminUrlUtil(serverURL, slug)
|
||||
})
|
||||
|
||||
test('should have up-to-date user in `useAuth` hook', async () => {
|
||||
await page.goto(url.account)
|
||||
await page.waitForURL(url.account)
|
||||
|
||||
@@ -5,11 +5,14 @@ import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import open from 'open'
|
||||
import { loadEnv } from 'payload/node'
|
||||
|
||||
import { getNextJSRootDir } from './helpers/getNextJSRootDir.js'
|
||||
import { runInit } from './runInit.js'
|
||||
import { createTestHooks } from './testHooks.js'
|
||||
|
||||
loadEnv()
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
"qs-esm": "7.0.2",
|
||||
"server-only": "^0.0.1",
|
||||
"slate": "0.91.4",
|
||||
"drizzle-kit": "0.23.2-df9e596",
|
||||
"tempy": "^1.0.1",
|
||||
"ts-essentials": "7.0.3",
|
||||
"typescript": "5.5.4",
|
||||
|
||||
Reference in New Issue
Block a user