Compare commits
24 Commits
db-postgre
...
db-postgre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
769bee82cd | ||
|
|
55eb6e7583 | ||
|
|
a907480a94 | ||
|
|
9c25754eed | ||
|
|
7c9ec9c4e0 | ||
|
|
a0bd7060c4 | ||
|
|
169da5c3d8 | ||
|
|
25932c0db6 | ||
|
|
3bce3d4240 | ||
|
|
e2a13deff6 | ||
|
|
5d99adfd38 | ||
|
|
819753a637 | ||
|
|
b7d65ab717 | ||
|
|
e365300bee | ||
|
|
4d9f494a80 | ||
|
|
fa6d4596dc | ||
|
|
08b02ecba2 | ||
|
|
eba777c3a0 | ||
|
|
bfe6918681 | ||
|
|
e5d6cdae38 | ||
|
|
218f2ead03 | ||
|
|
e9c1222182 | ||
|
|
c8ed6454a7 | ||
|
|
4077598777 |
13
.github/ISSUE_TEMPLATE/1.bug_report_v3.yml
vendored
13
.github/ISSUE_TEMPLATE/1.bug_report_v3.yml
vendored
@@ -1,6 +1,6 @@
|
||||
name: Bug Report v3
|
||||
description: Create a bug report for Payload v3 (beta)
|
||||
labels: ['status: needs-triage', 'v3']
|
||||
name: Functionality Bug
|
||||
description: '[REPRODUCTION REQUIRED] - Create a bug report'
|
||||
labels: ['status: needs-triage', 'v3', 'validate-reproduction']
|
||||
body:
|
||||
|
||||
- type: textarea
|
||||
@@ -14,8 +14,8 @@ body:
|
||||
attributes:
|
||||
label: Link to the code that reproduces this issue
|
||||
description: >-
|
||||
Required: Please provide a link to your reproduction. Note, if the URL is invalid (404 or a private repository), we may close the issue.
|
||||
Either use `npx create-payload-app@beta -t blank` or follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
|
||||
_REQUIRED_: Please provide a link to your reproduction. Note, if the URL is invalid (404 or a private repository), we may close the issue.
|
||||
Either use `npx create-payload-app@beta -t blank` then push to a repo or follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -33,6 +33,7 @@ body:
|
||||
options:
|
||||
- 'Not sure'
|
||||
- 'area: core'
|
||||
- 'area: docs'
|
||||
- 'area: templates'
|
||||
- 'area: ui'
|
||||
- 'db-mongodb'
|
||||
@@ -57,7 +58,7 @@ body:
|
||||
attributes:
|
||||
label: Environment Info
|
||||
description: Paste output from `pnpm payload info` (>= beta.92) _or_ Payload, Node.js, and Next.js versions.
|
||||
render: bash
|
||||
render: text
|
||||
placeholder: |
|
||||
Payload:
|
||||
Node.js:
|
||||
|
||||
41
.github/ISSUE_TEMPLATE/2.design_issue.yml
vendored
Normal file
41
.github/ISSUE_TEMPLATE/2.design_issue.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Design Issue
|
||||
description: '[SCREENSHOT REQUIRED] - Create a design issue report'
|
||||
labels: ['status: needs-triage', 'v3', 'area: ui']
|
||||
body:
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the Bug.
|
||||
description: >-
|
||||
_REQUIRED:_ Please a screenshot/video of the issue along with a detailed description of the problem.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Environment Info
|
||||
description: Paste output from `pnpm payload info` (>= beta.92) _or_ Payload, Node.js, and Next.js versions.
|
||||
render: text
|
||||
placeholder: |
|
||||
Payload:
|
||||
Node.js:
|
||||
Next.js:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
|
||||
@@ -1,11 +1,11 @@
|
||||
name: Bug Report
|
||||
description: Create a bug report for Payload
|
||||
name: v2 Bug Report
|
||||
description: Report a bug for Payload v2. ONLY CRITICAL bugs will be fixed in v2.
|
||||
labels: ['status: needs-triage', 'v2']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
*Note:* Feature requests should be opened as [discussions](https://github.com/payloadcms/payload/discussions/new?category=feature-requests-ideas).
|
||||
ONLY CRITICAL bugs will be fixed in v2.
|
||||
- type: input
|
||||
id: reproduction-link
|
||||
attributes:
|
||||
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,10 +1,23 @@
|
||||
<!--
|
||||
|
||||
For external contributors, please include:
|
||||
Thank you for the PR! Please go through the checklist below and make sure you've completed all the steps.
|
||||
|
||||
- A summary of the pull request and any related issues it fixes.
|
||||
- Reasoning for the changes made or any additional context that may be useful.
|
||||
Please review the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository if you haven't already.
|
||||
|
||||
Ensure you have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository.
|
||||
The following items will ensure that your PR is handled as smoothly as possible:
|
||||
|
||||
-->
|
||||
- PR Title must follow conventional commits format. For example, `feat: my new feature`, `fix(plugin-seo): my fix`.
|
||||
- Minimal description explained as if explained to someone not immediately familiar with the code.
|
||||
- Provide before/after screenshots or code diffs if applicable.
|
||||
- Link any related issues/discussions from GitHub or Discord.
|
||||
- Add review comments if necessary to explain to the reviewer the logic behind a change
|
||||
|
||||
### What?
|
||||
|
||||
### Why?
|
||||
|
||||
### How?
|
||||
|
||||
Fixes #
|
||||
|
||||
-->
|
||||
|
||||
13
.github/actions/triage/.eslintrc.js
vendored
Normal file
13
.github/actions/triage/.eslintrc.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint'],
|
||||
}
|
||||
8
.github/actions/triage/.prettierrc.js
vendored
Normal file
8
.github/actions/triage/.prettierrc.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
printWidth: 100,
|
||||
parser: 'typescript',
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
arrowParens: 'avoid',
|
||||
}
|
||||
22
.github/actions/triage/LICENSE
vendored
Normal file
22
.github/actions/triage/LICENSE
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Payload <info@payloadcms.com>. All modification and additions are copyright of Payload.
|
||||
|
||||
---
|
||||
|
||||
Original license:
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2023, Balázs Orbán
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
21
.github/actions/triage/README.md
vendored
Normal file
21
.github/actions/triage/README.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Triage
|
||||
|
||||
Modified version of https://github.com/balazsorban44/nissuer
|
||||
|
||||
## Modifications
|
||||
|
||||
- Port to TypeScript
|
||||
- Remove issue locking
|
||||
- Remove reproduction blocklist
|
||||
- Uses `@vercel/ncc` for packaging
|
||||
|
||||
## Development
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Whenever a modification is made to the action, the action built to `dist` must be committed to the repository.
|
||||
|
||||
This is done by running:
|
||||
|
||||
```sh
|
||||
pnpm build
|
||||
```
|
||||
40
.github/actions/triage/action.yml
vendored
Normal file
40
.github/actions/triage/action.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Triage
|
||||
description: Initial triage for issues
|
||||
|
||||
inputs:
|
||||
reproduction-comment:
|
||||
description: 'Either a string or a path to a .md file inside the repository. Example: ".github/invalid-reproduction.md"'
|
||||
default: '.github/invalid-reproduction.md'
|
||||
reproduction-hosts:
|
||||
description: 'Comma-separated list of hostnames that are allowed for reproductions. Example: "github.com,codesandbox.io"'
|
||||
default: github.com
|
||||
reproduction-invalid-label:
|
||||
description: 'Label to apply to issues without a valid reproduction. Example: "invalid-reproduction"'
|
||||
default: 'invalid-reproduction'
|
||||
reproduction-issue-labels:
|
||||
description: 'Comma-separated list of issue labels. If configured, only verify reproduction URLs of issues with one of these labels present. Adding a comma at the end will handle non-labeled issues as invalid. Example: "bug,", will consider issues with the label "bug" or no label.'
|
||||
default: ''
|
||||
reproduction-link-section:
|
||||
description: 'A regular expression string with "(.*)" matching a valid URL in the issue body. The result is trimmed. Example: "### Link to reproduction(.*)### To reproduce"'
|
||||
default: '### Link to reproduction(.*)### To reproduce'
|
||||
tag-only:
|
||||
description: Log and tag only. Do not perform closing or commenting actions.
|
||||
default: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: actions/checkout@v4
|
||||
- name: Run action
|
||||
run: node ${{ github.action_path }}/dist/index.js
|
||||
shell: sh
|
||||
# https://github.com/actions/runner/issues/665#issuecomment-676581170
|
||||
env:
|
||||
"INPUT_REPRODUCTION_COMMENT": ${{inputs.reproduction-comment}}
|
||||
"INPUT_REPRODUCTION_HOSTS": ${{inputs.reproduction-hosts}}
|
||||
"INPUT_REPRODUCTION_INVALID_LABEL": ${{inputs.reproduction-invalid-label}}
|
||||
"INPUT_REPRODUCTION_ISSUE_LABELS": ${{inputs.reproduction-issue-labels}}
|
||||
"INPUT_REPRODUCTION_LINK_SECTION": ${{inputs.reproduction-link-section}}
|
||||
"INPUT_TAG_ONLY": ${{inputs.tag-only}}
|
||||
34048
.github/actions/triage/dist/index.js
vendored
Normal file
34048
.github/actions/triage/dist/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
.github/actions/triage/jest.config.js
vendored
Normal file
7
.github/actions/triage/jest.config.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
testEnvironment: 'node',
|
||||
testPathIgnorePatterns: ['/node_modules/', '<rootDir>/dist/'],
|
||||
transform: {
|
||||
'^.+\\.(t|j)sx?$': ['@swc/jest'],
|
||||
},
|
||||
}
|
||||
34
.github/actions/triage/package.json
vendored
Normal file
34
.github/actions/triage/package.json
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "triage",
|
||||
"version": "0.0.0",
|
||||
"description": "GitHub Action to triage new issues",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"build": "pnpm build:typecheck && pnpm build:ncc",
|
||||
"build:ncc": "ncc build src/index.ts -t -o dist",
|
||||
"build:typecheck": "tsc",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.3.0",
|
||||
"@actions/github": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@octokit/webhooks-types": "^7.5.1",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^20.16.5",
|
||||
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
||||
"@typescript-eslint/parser": "^4.33.0",
|
||||
"@vercel/ncc": "0.38.1",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^7.32.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.3.3",
|
||||
"ts-jest": "^26.5.6",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
5419
.github/actions/triage/pnpm-lock.yaml
generated
vendored
Normal file
5419
.github/actions/triage/pnpm-lock.yaml
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
195
.github/actions/triage/src/index.ts
vendored
Normal file
195
.github/actions/triage/src/index.ts
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
import { debug, error, getBooleanInput, getInput, info, setFailed } from '@actions/core'
|
||||
|
||||
import { context, getOctokit } from '@actions/github'
|
||||
import { readFile, access } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
|
||||
// Ensure GITHUB_TOKEN and GITHUB_WORKSPACE are present
|
||||
if (!process.env.GITHUB_TOKEN) throw new TypeError('No GITHUB_TOKEN provided')
|
||||
if (!process.env.GITHUB_WORKSPACE) throw new TypeError('Not a GitHub workspace')
|
||||
|
||||
// Define the configuration object
|
||||
interface Config {
|
||||
invalidLink: {
|
||||
comment: string
|
||||
bugLabels: string[]
|
||||
hosts: string[]
|
||||
label: string
|
||||
linkSection: string
|
||||
}
|
||||
tagOnly: boolean
|
||||
token: string
|
||||
workspace: string
|
||||
}
|
||||
|
||||
const config: Config = {
|
||||
invalidLink: {
|
||||
comment: getInput('reproduction_comment') || '.github/invalid-reproduction.md',
|
||||
bugLabels: getInput('reproduction_issue_labels')
|
||||
.split(',')
|
||||
.map(l => l.trim()),
|
||||
hosts: (getInput('reproduction_hosts') || 'github.com').split(',').map(h => h.trim()),
|
||||
label: getInput('reproduction_invalid_label') || 'invalid-reproduction',
|
||||
linkSection:
|
||||
getInput('reproduction_link_section') || '### Link to reproduction(.*)### To reproduce',
|
||||
},
|
||||
tagOnly: getBooleanOrUndefined('tag_only') || false,
|
||||
token: process.env.GITHUB_TOKEN,
|
||||
workspace: process.env.GITHUB_WORKSPACE,
|
||||
}
|
||||
|
||||
// Attempt to parse JSON, return parsed object or error
|
||||
function tryParse(json: string): Record<string, unknown> {
|
||||
try {
|
||||
return JSON.parse(json)
|
||||
} catch (e) {
|
||||
setFailed(`Could not parse JSON: ${e instanceof Error ? e.message : e}`)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieves a boolean input or undefined based on environment variables
|
||||
function getBooleanOrUndefined(value: string): boolean | undefined {
|
||||
const variable = process.env[`INPUT_${value.toUpperCase()}`]
|
||||
return variable === undefined || variable === '' ? undefined : getBooleanInput(value)
|
||||
}
|
||||
|
||||
// Returns the appropriate label match type
|
||||
function getLabelMatch(value: string | undefined): 'name' | 'description' {
|
||||
return value === 'name' ? 'name' : 'description'
|
||||
}
|
||||
|
||||
// Function to check if an issue contains a valid reproduction link
|
||||
async function checkValidReproduction(): Promise<void> {
|
||||
const { issue, action } = context.payload as {
|
||||
issue: { number: number; body: string; labels: { name: string }[] } | undefined
|
||||
action: string
|
||||
}
|
||||
|
||||
if (action !== 'opened' || !issue?.body) return
|
||||
|
||||
const labels = issue.labels.map(l => l.name)
|
||||
|
||||
const issueMatchingLabel =
|
||||
labels.length &&
|
||||
config.invalidLink.bugLabels.length &&
|
||||
labels.some(l => config.invalidLink.bugLabels.includes(l))
|
||||
|
||||
if (!issueMatchingLabel) {
|
||||
info(
|
||||
`Issue #${issue.number} does not match required labels: ${config.invalidLink.bugLabels.join(', ')}`,
|
||||
)
|
||||
info(`Issue labels: ${labels.join(', ')}`)
|
||||
return
|
||||
}
|
||||
|
||||
info(`Issue #${issue.number} labels: ${labels.join(', ')}`)
|
||||
|
||||
const { rest: client } = getOctokit(config.token)
|
||||
const common = { ...context.repo, issue_number: issue.number }
|
||||
|
||||
const labelsToRemove = labels.filter(l => config.invalidLink.bugLabels.includes(l))
|
||||
|
||||
if (await isValidReproduction(issue.body)) {
|
||||
await Promise.all(
|
||||
labelsToRemove.map(label => client.issues.removeLabel({ ...common, name: label })),
|
||||
)
|
||||
|
||||
return info(`Issue #${issue.number} contains a valid reproduction 💚`)
|
||||
}
|
||||
|
||||
info(`Invalid reproduction, issue will be closed/labeled/commented...`)
|
||||
|
||||
// Adjust labels
|
||||
await Promise.all(
|
||||
labelsToRemove.map(label => client.issues.removeLabel({ ...common, name: label })),
|
||||
)
|
||||
info(`Issue #${issue.number} - validate label removed`)
|
||||
await client.issues.addLabels({ ...common, labels: [config.invalidLink.label] })
|
||||
info(`Issue #${issue.number} - labeled`)
|
||||
|
||||
// If tagOnly, do not close or comment
|
||||
if (config.tagOnly) {
|
||||
info('Tag-only enabled, no closing/commenting actions taken')
|
||||
return
|
||||
}
|
||||
|
||||
// Perform closing and commenting actions
|
||||
await client.issues.update({ ...common, state: 'closed' })
|
||||
info(`Issue #${issue.number} - closed`)
|
||||
|
||||
const comment = join(config.workspace, config.invalidLink.comment)
|
||||
await client.issues.createComment({ ...common, body: await getCommentBody(comment) })
|
||||
info(`Issue #${issue.number} - commented`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an issue contains a valid/accessible link to a reproduction.
|
||||
*
|
||||
* Returns `true` if the link is valid.
|
||||
* @param body - The body content of the issue
|
||||
*/
|
||||
async function isValidReproduction(body: string): Promise<boolean> {
|
||||
const linkSectionRe = new RegExp(config.invalidLink.linkSection, 'is')
|
||||
const link = body.match(linkSectionRe)?.[1]?.trim()
|
||||
|
||||
if (!link) {
|
||||
info('Missing link')
|
||||
info(`Link section regex: ${linkSectionRe}`)
|
||||
info(`Link section: ${body}`)
|
||||
return false
|
||||
}
|
||||
|
||||
info(`Checking validity of link: ${link}`)
|
||||
|
||||
if (!URL.canParse(link)) {
|
||||
info(`Invalid URL: ${link}`)
|
||||
return false
|
||||
}
|
||||
|
||||
const url = new URL(link)
|
||||
|
||||
if (!config.invalidLink.hosts.includes(url.hostname)) {
|
||||
info('Link did not match allowed reproduction hosts')
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify that the link can be accessed
|
||||
const response = await fetch(link)
|
||||
const isOk = response.status < 400 || response.status >= 500
|
||||
|
||||
info(`Link status: ${response.status}`)
|
||||
if (!isOk) {
|
||||
info(`Link returned status ${response.status}`)
|
||||
}
|
||||
return isOk
|
||||
} catch (error) {
|
||||
info(`Error fetching link: ${(error as Error).message}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return either a file's content or a string
|
||||
* @param {string} pathOrComment
|
||||
*/
|
||||
async function getCommentBody(pathOrComment: string) {
|
||||
try {
|
||||
await access(pathOrComment)
|
||||
return await readFile(pathOrComment, 'utf8')
|
||||
} catch (error: any) {
|
||||
if (error.code === 'ENOENT') return pathOrComment
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const { token, workspace, ...safeConfig } = config
|
||||
info('Configuration:')
|
||||
info(JSON.stringify(safeConfig, null, 2))
|
||||
|
||||
await checkValidReproduction()
|
||||
}
|
||||
|
||||
run().catch(setFailed)
|
||||
15
.github/actions/triage/tsconfig.json
vendored
Normal file
15
.github/actions/triage/tsconfig.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["es2020.string"],
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": false, // Undo this
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
},
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
}
|
||||
49
.github/pnpm-lock.yaml
generated
vendored
49
.github/pnpm-lock.yaml
generated
vendored
@@ -55,6 +55,55 @@ importers:
|
||||
specifier: ^4.9.5
|
||||
version: 4.9.5
|
||||
|
||||
actions/triage:
|
||||
dependencies:
|
||||
'@actions/core':
|
||||
specifier: ^1.3.0
|
||||
version: 1.10.1
|
||||
'@actions/github':
|
||||
specifier: ^5.0.0
|
||||
version: 5.1.1
|
||||
devDependencies:
|
||||
'@octokit/webhooks-types':
|
||||
specifier: ^7.5.1
|
||||
version: 7.5.1
|
||||
'@swc/jest':
|
||||
specifier: ^0.2.36
|
||||
version: 0.2.36(@swc/core@1.7.23)
|
||||
'@types/jest':
|
||||
specifier: ^27.5.2
|
||||
version: 27.5.2
|
||||
'@types/node':
|
||||
specifier: ^20.16.5
|
||||
version: 20.16.5
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^4.33.0
|
||||
version: 4.33.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^4.33.0
|
||||
version: 4.33.0(eslint@7.32.0)(typescript@4.9.5)
|
||||
'@vercel/ncc':
|
||||
specifier: 0.38.1
|
||||
version: 0.38.1
|
||||
concurrently:
|
||||
specifier: ^8.2.2
|
||||
version: 8.2.2
|
||||
eslint:
|
||||
specifier: ^7.32.0
|
||||
version: 7.32.0
|
||||
jest:
|
||||
specifier: ^29.7.0
|
||||
version: 29.7.0(@types/node@20.16.5)(node-notifier@8.0.2)
|
||||
prettier:
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
ts-jest:
|
||||
specifier: ^26.5.6
|
||||
version: 26.5.6(jest@29.7.0(@types/node@20.16.5)(node-notifier@8.0.2))(typescript@4.9.5)
|
||||
typescript:
|
||||
specifier: ^4.9.5
|
||||
version: 4.9.5
|
||||
|
||||
packages:
|
||||
|
||||
'@actions/core@1.10.1':
|
||||
|
||||
80
.github/workflows/label-author.yml
vendored
80
.github/workflows/label-author.yml
vendored
@@ -1,80 +0,0 @@
|
||||
name: label-author
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
debug-context:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: View context attributes
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: console.log(context)
|
||||
|
||||
label-created-by:
|
||||
name: Label pr/issue on opening
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Tag with 'created-by'
|
||||
uses: actions/github-script@v7
|
||||
if: github.event.action == 'opened'
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const payloadTeamUsernames = [
|
||||
'denolfe',
|
||||
'jmikrut',
|
||||
'DanRibbens',
|
||||
'jacobsfletch',
|
||||
'JarrodMFlesch',
|
||||
'AlessioGr',
|
||||
'JessChowdhury',
|
||||
'kendelljoseph',
|
||||
'PatrikKozak',
|
||||
'tylandavis',
|
||||
'paulpopus',
|
||||
];
|
||||
|
||||
const type = context.payload.pull_request ? 'pull_request' : 'issue';
|
||||
|
||||
const isTeamMember = payloadTeamUsernames
|
||||
.map(n => n.toLowerCase())
|
||||
.includes(context.payload[type].user.login.toLowerCase());
|
||||
|
||||
if (isTeamMember) {
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['created-by: Payload team'],
|
||||
});
|
||||
console.log(`Added 'created-by: Payload team' label`);
|
||||
return;
|
||||
}
|
||||
|
||||
const association = context.payload[type].author_association;
|
||||
let label = ''
|
||||
if (association === 'MEMBER' || association === 'OWNER') {
|
||||
label = 'created-by: Payload team';
|
||||
} else if (association === 'CONTRIBUTOR') {
|
||||
label = 'created-by: Contributor';
|
||||
}
|
||||
|
||||
if (!label) return;
|
||||
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: [label],
|
||||
});
|
||||
console.log(`Added '${label}' label.`);
|
||||
93
.github/workflows/triage.yml
vendored
93
.github/workflows/triage.yml
vendored
@@ -1,6 +1,9 @@
|
||||
name: triage
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
@@ -9,21 +12,91 @@ env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
name: nissuer
|
||||
if: false # Disable after adjusting scenarios which this should be applied
|
||||
debug-context:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: balazsorban44/nissuer@1.10.0
|
||||
- name: View context attributes
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: console.log({ context })
|
||||
|
||||
label-created-by:
|
||||
name: label-on-open
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Tag with 'created-by'
|
||||
uses: actions/github-script@v7
|
||||
if: github.event.action == 'opened'
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const payloadTeamUsernames = [
|
||||
'denolfe',
|
||||
'jmikrut',
|
||||
'DanRibbens',
|
||||
'jacobsfletch',
|
||||
'JarrodMFlesch',
|
||||
'AlessioGr',
|
||||
'JessChowdhury',
|
||||
'kendelljoseph',
|
||||
'PatrikKozak',
|
||||
'tylandavis',
|
||||
'paulpopus',
|
||||
'r1tsuu',
|
||||
'GermanJablo',
|
||||
];
|
||||
|
||||
const type = context.payload.pull_request ? 'pull_request' : 'issue';
|
||||
|
||||
const isTeamMember = payloadTeamUsernames
|
||||
.map(n => n.toLowerCase())
|
||||
.includes(context.payload[type].user.login.toLowerCase());
|
||||
|
||||
if (isTeamMember) {
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['created-by: Payload team'],
|
||||
});
|
||||
console.log(`Added 'created-by: Payload team' label`);
|
||||
return;
|
||||
}
|
||||
|
||||
const association = context.payload[type].author_association;
|
||||
let label = ''
|
||||
if (association === 'MEMBER' || association === 'OWNER') {
|
||||
label = 'created-by: Payload team';
|
||||
} else if (association === 'CONTRIBUTOR') {
|
||||
label = 'created-by: Contributor';
|
||||
}
|
||||
|
||||
if (!label) return;
|
||||
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: [label],
|
||||
});
|
||||
console.log(`Added '${label}' label.`);
|
||||
|
||||
triage:
|
||||
name: initial-triage
|
||||
if: github.event_name == 'issues'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: ./.github/actions/triage
|
||||
with:
|
||||
label-area-prefix: ""
|
||||
label-area-match: "name"
|
||||
label-area-section: 'Which area\(s\) are affected\? \(Select all that apply\)(.*)### Environment Info'
|
||||
reproduction-comment: '.github/comments/invalid-reproduction.md'
|
||||
reproduction-blocklist: 'github.com/\\w*/?$,github.com$'
|
||||
reproduction-link-section: '### Link to the code that reproduces this issue(.*)### Reproduction Steps'
|
||||
reproduction-invalid-label: 'invalid-reproduction'
|
||||
reproduction-issue-labels: 'status: needs-triage,'
|
||||
reproduction-issue-labels: 'validate-reproduction'
|
||||
tag-only: 'true'
|
||||
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,3 +1,27 @@
|
||||
## [2.30.4](https://github.com/payloadcms/payload/compare/v2.30.3...v2.30.4) (2024-11-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **plugin-seo:** add Turkish translation ([#8918](https://github.com/payloadcms/payload/issues/8918)) ([7c9ec9c](https://github.com/payloadcms/payload/commit/7c9ec9c4e0bafd19eb0ef94e9bb4aa07df3e097e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **db-postgres:** sort by localized fields ([#9016](https://github.com/payloadcms/payload/issues/9016)) ([9c25754](https://github.com/payloadcms/payload/commit/9c25754eed87e70b053231693102378150b8b80d))
|
||||
* edit many modal draft action button order and style ([#9046](https://github.com/payloadcms/payload/issues/9046)) ([a907480](https://github.com/payloadcms/payload/commit/a907480a94f07b4afa0e0723a3738c8bd457c51f)), closes [#9045](https://github.com/payloadcms/payload/issues/9045)
|
||||
* error saving after duplicating blocks with nested items ([#8814](https://github.com/payloadcms/payload/issues/8814)) ([eba777c](https://github.com/payloadcms/payload/commit/eba777c3a0b4c489d87d3c6154d835a105fef4a2))
|
||||
* list drawer relationship not displaying ([#9011](https://github.com/payloadcms/payload/issues/9011)) ([169da5c](https://github.com/payloadcms/payload/commit/169da5c3d83bfe3559227504929aa62721ded1d9))
|
||||
* querying relationships by `id` path with REST ([#9014](https://github.com/payloadcms/payload/issues/9014)) ([a0bd706](https://github.com/payloadcms/payload/commit/a0bd7060c45df3037ee074bd83400837c0adb83a))
|
||||
|
||||
## [2.30.3](https://github.com/payloadcms/payload/compare/v2.30.2...v2.30.3) (2024-10-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **db-postgres:** migrate:create errors with previous schemas ([#8786](https://github.com/payloadcms/payload/issues/8786)) ([e9c1222](https://github.com/payloadcms/payload/commit/e9c12221824a9a180991722135d22ff91d07ef11))
|
||||
* duplicate with select hasMany fields ([#8734](https://github.com/payloadcms/payload/issues/8734)) ([c8ed645](https://github.com/payloadcms/payload/commit/c8ed6454a733bea09ae620517c4894701999e119))
|
||||
|
||||
## [2.30.2](https://github.com/payloadcms/payload/compare/v2.30.1...v2.30.2) (2024-10-17)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -66,8 +66,8 @@ export default buildConfig({
|
||||
admin: {
|
||||
bundler: webpackBundler(), // or viteBundler()
|
||||
},
|
||||
db: mongooseAdapter({}) // or postgresAdapter({}),
|
||||
editor: lexicalEditor({}) // or slateEditor({})
|
||||
db: mongooseAdapter({}), // or postgresAdapter({})
|
||||
editor: lexicalEditor({}), // or slateEditor({})
|
||||
collections: [
|
||||
{
|
||||
slug: 'pages',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"license": "MIT",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"bin": {
|
||||
|
||||
@@ -16,38 +16,38 @@ export function getValidTemplates(): ProjectTemplate[] {
|
||||
return [
|
||||
{
|
||||
name: 'blank',
|
||||
description: 'Blank Template',
|
||||
type: 'starter',
|
||||
url: 'https://github.com/payloadcms/payload/templates/blank',
|
||||
description: 'Blank Template',
|
||||
url: 'https://github.com/payloadcms/payload/templates/blank#v2.30.3',
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
description: 'Website Template',
|
||||
type: 'starter',
|
||||
url: 'https://github.com/payloadcms/payload/templates/website',
|
||||
description: 'Website Template',
|
||||
url: 'https://github.com/payloadcms/payload/templates/website#v2.30.3',
|
||||
},
|
||||
{
|
||||
name: 'ecommerce',
|
||||
description: 'E-commerce Template',
|
||||
type: 'starter',
|
||||
url: 'https://github.com/payloadcms/payload/templates/ecommerce',
|
||||
description: 'E-commerce Template',
|
||||
url: 'https://github.com/payloadcms/payload/templates/ecommerce#v2.30.3',
|
||||
},
|
||||
{
|
||||
name: 'plugin',
|
||||
description: 'Template for creating a Payload plugin',
|
||||
type: 'plugin',
|
||||
description: 'Template for creating a Payload plugin',
|
||||
url: 'https://github.com/payloadcms/payload-plugin-template',
|
||||
},
|
||||
{
|
||||
name: 'payload-demo',
|
||||
description: 'Payload demo site at https://demo.payloadcms.com',
|
||||
type: 'starter',
|
||||
description: 'Payload demo site at https://demo.payloadcms.com',
|
||||
url: 'https://github.com/payloadcms/public-demo',
|
||||
},
|
||||
{
|
||||
name: 'payload-website',
|
||||
description: 'Payload website CMS at https://payloadcms.com',
|
||||
type: 'starter',
|
||||
description: 'Payload website CMS at https://payloadcms.com',
|
||||
url: 'https://github.com/payloadcms/website-cms',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "0.8.8",
|
||||
"version": "0.8.10",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Count } from 'payload/database'
|
||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
import { sql, count as sqlCount } from 'drizzle-orm'
|
||||
import { count as sqlCount } from 'drizzle-orm'
|
||||
import toSnakeCase from 'to-snake-case'
|
||||
|
||||
import type { ChainedMethods } from './find/chainMethods'
|
||||
@@ -51,11 +51,7 @@ export const count: Count = async function count(
|
||||
methods: selectCountMethods,
|
||||
query: db
|
||||
.select({
|
||||
count:
|
||||
selectCountMethods.length > 0
|
||||
? sql<number>`count
|
||||
(DISTINCT ${this.tables[tableName].id})`
|
||||
: sqlCount(),
|
||||
count: sqlCount(),
|
||||
})
|
||||
.from(table)
|
||||
.where(where),
|
||||
|
||||
@@ -61,7 +61,7 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
fs.mkdirSync(dir)
|
||||
}
|
||||
|
||||
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/api')
|
||||
const { generateDrizzleJson, generateMigration, upPgSnapshot } = require('drizzle-kit/api')
|
||||
|
||||
const [yyymmdd, hhmmss] = new Date().toISOString().split('T')
|
||||
const formattedDate = yyymmdd.replace(/\D/g, '')
|
||||
@@ -99,6 +99,11 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
}
|
||||
|
||||
const drizzleJsonAfter = generateDrizzleJson(this.schema)
|
||||
|
||||
if (drizzleJsonBefore.version < drizzleJsonAfter.version) {
|
||||
drizzleJsonBefore = upPgSnapshot(drizzleJsonBefore)
|
||||
}
|
||||
|
||||
const sqlStatementsUp = await generateMigration(drizzleJsonBefore, drizzleJsonAfter)
|
||||
const sqlStatementsDown = await generateMigration(drizzleJsonAfter, drizzleJsonBefore)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { FindArgs } from 'payload/database'
|
||||
import type { Field, PayloadRequest, TypeWithID } from 'payload/types'
|
||||
|
||||
import { inArray, sql, count as sqlCount } from 'drizzle-orm'
|
||||
import { inArray, count as sqlCount } from 'drizzle-orm'
|
||||
|
||||
import type { PostgresAdapter } from '../types'
|
||||
import type { ChainedMethods } from './chainMethods'
|
||||
@@ -143,11 +143,7 @@ export const findMany = async function find({
|
||||
methods: selectCountMethods,
|
||||
query: db
|
||||
.select({
|
||||
count:
|
||||
selectCountMethods.length > 0
|
||||
? sql<number>`count
|
||||
(DISTINCT ${adapter.tables[tableName].id})`
|
||||
: sqlCount(),
|
||||
count: sqlCount(),
|
||||
})
|
||||
.from(table)
|
||||
.where(where),
|
||||
|
||||
@@ -185,17 +185,12 @@ export const getTableColumnFromPath = ({
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
newTableName = `${tableName}${adapter.localesSuffix}`
|
||||
|
||||
joins[tableName] = eq(
|
||||
adapter.tables[tableName].id,
|
||||
adapter.tables[newTableName]._parentID,
|
||||
)
|
||||
let condition = eq(adapter.tables[tableName].id, adapter.tables[newTableName]._parentID)
|
||||
if (locale !== 'all') {
|
||||
constraints.push({
|
||||
columnName: '_locale',
|
||||
table: adapter.tables[newTableName],
|
||||
value: locale,
|
||||
})
|
||||
condition = and(condition, eq(adapter.tables[newTableName]._locale, locale))
|
||||
}
|
||||
|
||||
joins[tableName] = condition
|
||||
}
|
||||
return getTableColumnFromPath({
|
||||
adapter,
|
||||
@@ -224,17 +219,15 @@ export const getTableColumnFromPath = ({
|
||||
)
|
||||
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
joins[newTableName] = and(
|
||||
const conditions = [
|
||||
eq(adapter.tables[tableName].id, adapter.tables[newTableName].parent),
|
||||
eq(adapter.tables[newTableName]._locale, locale),
|
||||
)
|
||||
]
|
||||
if (locale !== 'all') {
|
||||
constraints.push({
|
||||
columnName: '_locale',
|
||||
table: adapter.tables[newTableName],
|
||||
value: locale,
|
||||
})
|
||||
conditions.push(eq(adapter.tables[newTableName]._locale, locale))
|
||||
}
|
||||
|
||||
joins[newTableName] = and(...conditions)
|
||||
} else {
|
||||
joins[newTableName] = eq(
|
||||
adapter.tables[tableName].id,
|
||||
@@ -268,17 +261,12 @@ export const getTableColumnFromPath = ({
|
||||
]
|
||||
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
joins[newTableName] = and(
|
||||
...joinConstraints,
|
||||
eq(adapter.tables[newTableName]._locale, locale),
|
||||
)
|
||||
const conditions = [...joinConstraints]
|
||||
if (locale !== 'all') {
|
||||
constraints.push({
|
||||
columnName: 'locale',
|
||||
table: adapter.tables[newTableName],
|
||||
value: locale,
|
||||
})
|
||||
conditions.push(eq(adapter.tables[newTableName]._locale, locale))
|
||||
}
|
||||
|
||||
joins[newTableName] = and(...conditions)
|
||||
} else {
|
||||
joins[newTableName] = and(...joinConstraints)
|
||||
}
|
||||
@@ -302,17 +290,12 @@ export const getTableColumnFromPath = ({
|
||||
|
||||
constraintPath = `${constraintPath}${field.name}.%.`
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
joins[newTableName] = and(
|
||||
eq(arrayParentTable.id, adapter.tables[newTableName]._parentID),
|
||||
eq(adapter.tables[newTableName]._locale, locale),
|
||||
)
|
||||
const conditions = [eq(arrayParentTable.id, adapter.tables[newTableName]._parentID)]
|
||||
if (locale !== 'all') {
|
||||
constraints.push({
|
||||
columnName: '_locale',
|
||||
table: adapter.tables[newTableName],
|
||||
value: locale,
|
||||
})
|
||||
conditions.push(eq(adapter.tables[newTableName]._locale, locale))
|
||||
}
|
||||
|
||||
joins[newTableName] = and(...conditions)
|
||||
} else {
|
||||
joins[newTableName] = eq(arrayParentTable.id, adapter.tables[newTableName]._parentID)
|
||||
}
|
||||
@@ -399,17 +382,18 @@ export const getTableColumnFromPath = ({
|
||||
constraints = constraints.concat(blockConstraints)
|
||||
selectFields = { ...selectFields, ...blockSelectFields }
|
||||
if (field.localized && adapter.payload.config.localization) {
|
||||
joins[newTableName] = and(
|
||||
eq(adapter.tables[tableName].id, adapter.tables[newTableName]._parentID),
|
||||
eq(adapter.tables[newTableName]._locale, locale),
|
||||
)
|
||||
if (locale) {
|
||||
constraints.push({
|
||||
columnName: '_locale',
|
||||
table: adapter.tables[newTableName],
|
||||
value: locale,
|
||||
})
|
||||
const conditions = [
|
||||
eq(
|
||||
(aliasTable || adapter.tables[tableName]).id,
|
||||
adapter.tables[newTableName]._parentID,
|
||||
),
|
||||
]
|
||||
|
||||
if (locale !== 'all') {
|
||||
conditions.push(eq(adapter.tables[newTableName]._locale, locale))
|
||||
}
|
||||
|
||||
joins[newTableName] = and(...conditions)
|
||||
} else {
|
||||
joins[newTableName] = eq(
|
||||
adapter.tables[tableName].id,
|
||||
@@ -444,21 +428,20 @@ export const getTableColumnFromPath = ({
|
||||
|
||||
// Join in the relationships table
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
const conditions = [
|
||||
eq((aliasTable || adapter.tables[rootTableName]).id, aliasRelationshipTable.parent),
|
||||
eq(aliasRelationshipTable.locale, locale),
|
||||
like(aliasRelationshipTable.path, `${constraintPath}${field.name}`),
|
||||
]
|
||||
|
||||
if (locale !== 'all') {
|
||||
conditions.push(eq(aliasRelationshipTable.locale, locale))
|
||||
}
|
||||
|
||||
joinAliases.push({
|
||||
condition: and(
|
||||
eq((aliasTable || adapter.tables[rootTableName]).id, aliasRelationshipTable.parent),
|
||||
eq(aliasRelationshipTable.locale, locale),
|
||||
like(aliasRelationshipTable.path, `${constraintPath}${field.name}`),
|
||||
),
|
||||
condition: and(...conditions),
|
||||
table: aliasRelationshipTable,
|
||||
})
|
||||
if (locale !== 'all') {
|
||||
constraints.push({
|
||||
columnName: 'locale',
|
||||
table: aliasRelationshipTable,
|
||||
value: locale,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Join in the relationships table
|
||||
joinAliases.push({
|
||||
@@ -554,17 +537,14 @@ export const getTableColumnFromPath = ({
|
||||
|
||||
const parentTable = aliasTable || adapter.tables[tableName]
|
||||
|
||||
joins[newTableName] = eq(parentTable.id, adapter.tables[newTableName]._parentID)
|
||||
|
||||
aliasTable = undefined
|
||||
let condition = eq(parentTable.id, adapter.tables[newTableName]._parentID)
|
||||
|
||||
if (locale !== 'all') {
|
||||
constraints.push({
|
||||
columnName: '_locale',
|
||||
table: adapter.tables[newTableName],
|
||||
value: locale,
|
||||
})
|
||||
condition = and(condition, eq(adapter.tables[newTableName]._locale, locale))
|
||||
}
|
||||
joins[newTableName] = condition
|
||||
|
||||
aliasTable = undefined
|
||||
}
|
||||
|
||||
const targetTable = aliasTable || adapter.tables[newTableName]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "2.30.2",
|
||||
"version": "2.30.4",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -76,6 +76,8 @@ const Duplicate: React.FC<Props> = ({ id, slug, collection }) => {
|
||||
})
|
||||
}
|
||||
|
||||
delete data['id']
|
||||
|
||||
if (!duplicateID) {
|
||||
if ('createdAt' in data) delete data.createdAt
|
||||
if ('updatedAt' in data) delete data.updatedAt
|
||||
|
||||
@@ -77,7 +77,7 @@ const SaveDraft: React.FC<{ action: string; disabled: boolean }> = ({ action, di
|
||||
}, [action, submit])
|
||||
|
||||
return (
|
||||
<FormSubmit className={`${baseClass}__draft`} disabled={disabled} onClick={save}>
|
||||
<FormSubmit buttonStyle="secondary" className={`${baseClass}__draft`} disabled={disabled} onClick={save}>
|
||||
{t('saveDraft')}
|
||||
</FormSubmit>
|
||||
)
|
||||
@@ -147,11 +147,11 @@ const EditMany: React.FC<Props> = (props) => {
|
||||
<div className={`${baseClass}__document-actions`}>
|
||||
{collection.versions ? (
|
||||
<React.Fragment>
|
||||
<Publish
|
||||
<SaveDraft
|
||||
action={`${serverURL}${api}/${slug}${getQueryParams()}&draft=true`}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
<SaveDraft
|
||||
<Publish
|
||||
action={`${serverURL}${api}/${slug}${getQueryParams()}&draft=true`}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
|
||||
@@ -228,6 +228,15 @@ export function fieldReducer(state: Fields, action: FieldAction): Fields {
|
||||
const duplicateRowState = deepCopyObject(rows[rowIndex])
|
||||
if (duplicateRowState.id) duplicateRowState.id = new ObjectID().toHexString()
|
||||
|
||||
for (const key of Object.keys(duplicateRowState).filter((key) => key.endsWith('.id'))) {
|
||||
const idState = duplicateRowState[key]
|
||||
|
||||
if (idState && typeof idState.value === 'string' && ObjectID.isValid(idState.value)) {
|
||||
duplicateRowState[key].value = new ObjectID().toHexString()
|
||||
duplicateRowState[key].initialValue = new ObjectID().toHexString()
|
||||
}
|
||||
}
|
||||
|
||||
// If there are subfields
|
||||
if (Object.keys(duplicateRowState).length > 0) {
|
||||
// Add new object containing subfield names to unflattenedRows array
|
||||
|
||||
@@ -48,6 +48,11 @@ const RelationshipCell: React.FC<CellComponentProps<RelationshipField | UploadFi
|
||||
relationTo: field.relationTo,
|
||||
value: cell,
|
||||
})
|
||||
} else if (typeof cell.id !== 'undefined' && typeof field.relationTo === 'string') {
|
||||
formattedValues.push({
|
||||
relationTo: field.relationTo,
|
||||
value: cell.id,
|
||||
})
|
||||
}
|
||||
})
|
||||
getRelationships(formattedValues)
|
||||
|
||||
@@ -74,6 +74,19 @@ export async function validateSearchParam({
|
||||
})
|
||||
}
|
||||
const promises = []
|
||||
|
||||
// Sanitize relation.otherRelation.id to relation.otherRelation
|
||||
if (paths.at(-1)?.path === 'id') {
|
||||
const previousField = paths.at(-2)?.field
|
||||
if (
|
||||
previousField &&
|
||||
(previousField.type === 'relationship' || previousField.type === 'upload') &&
|
||||
typeof previousField.relationTo === 'string'
|
||||
) {
|
||||
paths.pop()
|
||||
}
|
||||
}
|
||||
|
||||
promises.push(
|
||||
...paths.map(async ({ collectionSlug, field, invalid, path }, i) => {
|
||||
if (invalid) {
|
||||
@@ -110,6 +123,7 @@ export async function validateSearchParam({
|
||||
if (field.type === 'relationship' && Array.isArray(field.relationTo)) {
|
||||
fieldPath = fieldPath.replace('.value', '')
|
||||
}
|
||||
|
||||
const entityType: 'collections' | 'globals' = globalConfig ? 'globals' : 'collections'
|
||||
const entitySlug = collectionSlug || globalConfig.slug
|
||||
const segments = fieldPath.split('.')
|
||||
|
||||
@@ -4,6 +4,7 @@ import fa from './fa.json'
|
||||
import fr from './fr.json'
|
||||
import nb from './nb.json'
|
||||
import pl from './pl.json'
|
||||
import tr from './tr.json'
|
||||
import ua from './ua.json'
|
||||
import zh from './zh.json'
|
||||
import zhTw from './zh-tw.json'
|
||||
@@ -14,7 +15,8 @@ export default {
|
||||
fa,
|
||||
fr,
|
||||
nb,
|
||||
pl,
|
||||
pl,
|
||||
tr,
|
||||
ua,
|
||||
zh,
|
||||
zhTw,
|
||||
|
||||
23
packages/plugin-seo/src/translations/tr.json
Normal file
23
packages/plugin-seo/src/translations/tr.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "./translation-schema.json",
|
||||
"plugin-seo": {
|
||||
"autoGenerate": "Otomatik oluştur",
|
||||
"imageAutoGenerationTip": "Otomatik oluşturma, seçilen ana görseli alacaktır.",
|
||||
"bestPractices": "en iyi uygulamalar",
|
||||
"lengthTipTitle": "{{minLength}} ile {{maxLength}} karakter arasında olmalıdır. Kaliteli meta başlıkları yazmak için yardım almak isterseniz, bkz. ",
|
||||
"lengthTipDescription": "{{minLength}} ile {{maxLength}} karakter arasında olmalıdır. Kaliteli meta açıklamaları yazmak için yardım almak isterseniz, bkz. ",
|
||||
"good": "İyi",
|
||||
"tooLong": "Çok uzun",
|
||||
"tooShort": "Çok kısa",
|
||||
"almostThere": "Neredeyse tamam",
|
||||
"characterCount": "{{current}}/{{minLength}}-{{maxLength}} karakter, ",
|
||||
"charactersToGo": "{{characters}} karakter kaldı",
|
||||
"charactersLeftOver": "{{characters}} karakter kaldı",
|
||||
"charactersTooMany": "{{characters}} karakter fazla",
|
||||
"noImage": "Görsel yok",
|
||||
"checksPassing": "{{current}}/{{max}} kontrol geçiyor",
|
||||
"preview": "Önizleme",
|
||||
"previewDescription": "Kesin sonuç listeleri içeriğe ve arama alaka düzeyine bağlı olarak değişebilir."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-lexical",
|
||||
"version": "0.11.3",
|
||||
"version": "0.11.4",
|
||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
3
test/database/.gitignore
vendored
3
test/database/.gitignore
vendored
@@ -1 +1,4 @@
|
||||
migrations
|
||||
v5_migrations/*
|
||||
!v5_migrations/20241018_162142_test_v5.ts
|
||||
!v5_migrations/20241018_162142_test_v5.json
|
||||
@@ -59,7 +59,7 @@ describe('database', () => {
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
removeFiles(path.normalize(payload.db.migrationDir))
|
||||
removeFiles(path.normalize(payload.db.migrationDir), (name) => !name.includes('test_v5'))
|
||||
})
|
||||
|
||||
it('should run migrate:create', async () => {
|
||||
@@ -74,6 +74,32 @@ describe('database', () => {
|
||||
expect(migrationFile).toContain('_test')
|
||||
})
|
||||
|
||||
it('should run migrate:create with older drizzle version schema', async () => {
|
||||
const db = payload.db as unknown as PostgresAdapter
|
||||
|
||||
// eslint-disable-next-line jest/no-if
|
||||
if (db.name !== 'postgres') return
|
||||
|
||||
// eslint-disable-next-line jest/no-if
|
||||
if (db.schemaName && db.schemaName !== 'public') {
|
||||
return
|
||||
}
|
||||
|
||||
const args = {
|
||||
_: ['migrate:create', 'test'],
|
||||
forceAcceptWarning: true,
|
||||
}
|
||||
const ogMigrationDir = payload.db.migrationDir
|
||||
payload.db.migrationDir = path.resolve(__dirname, 'v5_migrations')
|
||||
await migrate(args)
|
||||
|
||||
// read files names in migrationsDir
|
||||
const migrationFile = path.normalize(fs.readdirSync(payload.db.migrationDir)[2])
|
||||
expect(migrationFile).toContain('_test')
|
||||
removeFiles(path.normalize(payload.db.migrationDir), (name) => !name.includes('test_v5'))
|
||||
payload.db.migrationDir = ogMigrationDir
|
||||
})
|
||||
|
||||
it('should run migrate', async () => {
|
||||
const args = {
|
||||
_: ['migrate'],
|
||||
|
||||
1866
test/database/v5_migrations/20241018_162142_test_v5.json
Normal file
1866
test/database/v5_migrations/20241018_162142_test_v5.json
Normal file
File diff suppressed because it is too large
Load Diff
476
test/database/v5_migrations/20241018_162142_test_v5.ts
Normal file
476
test/database/v5_migrations/20241018_162142_test_v5.ts
Normal file
@@ -0,0 +1,476 @@
|
||||
import { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/db-postgres'
|
||||
import { sql } from 'drizzle-orm'
|
||||
|
||||
export async function up({ payload }: MigrateUpArgs): Promise<void> {
|
||||
await payload.db.drizzle.execute(sql`
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "_locales" AS ENUM('en', 'es');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "selectEnum" AS ENUM('a', 'b', 'c');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "radioEnum" AS ENUM('a', 'b', 'c');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "enum_customs_status" AS ENUM('draft', 'published');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "enum__customs_v_version_status" AS ENUM('draft', 'published');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "posts" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"title" varchar NOT NULL,
|
||||
"throw_after_change" boolean,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "relation_a" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"rich_text" jsonb,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "relation_a_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"relation_b_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "relation_b" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"rich_text" jsonb,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "relation_b_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"relation_a_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customs_customSelect" (
|
||||
"order" integer NOT NULL,
|
||||
"parent_id" integer NOT NULL,
|
||||
"value" "selectEnum",
|
||||
"id" serial PRIMARY KEY NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customArrays" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"text" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customArrays_locales" (
|
||||
"localized_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" varchar NOT NULL,
|
||||
CONSTRAINT "customArrays_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customBlocks" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"_path" text NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"text" varchar,
|
||||
"block_name" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customBlocks_locales" (
|
||||
"localized_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" varchar NOT NULL,
|
||||
CONSTRAINT "customBlocks_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customs" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"text" varchar,
|
||||
"radio" "radioEnum",
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"_status" "enum_customs_status"
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customs_locales" (
|
||||
"localized_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
CONSTRAINT "customs_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customs_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"relation_a_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customs_v_version_customSelect" (
|
||||
"order" integer NOT NULL,
|
||||
"parent_id" integer NOT NULL,
|
||||
"value" "selectEnum",
|
||||
"id" serial PRIMARY KEY NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customArrays_v" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"text" varchar,
|
||||
"_uuid" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customArrays_v_locales" (
|
||||
"localized_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
CONSTRAINT "_customArrays_v_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customBlocks_v" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"_path" text NOT NULL,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"text" varchar,
|
||||
"_uuid" varchar,
|
||||
"block_name" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customBlocks_v_locales" (
|
||||
"localized_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
CONSTRAINT "_customBlocks_v_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customs_v" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"version_text" varchar,
|
||||
"version_radio" "radioEnum",
|
||||
"version_updated_at" timestamp(3) with time zone,
|
||||
"version_created_at" timestamp(3) with time zone,
|
||||
"version__status" "enum__customs_v_version_status",
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"latest" boolean
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customs_v_locales" (
|
||||
"version_localized_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
CONSTRAINT "_customs_v_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customs_v_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"customs_id" integer,
|
||||
"relation_a_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "users" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"email" varchar NOT NULL,
|
||||
"reset_password_token" varchar,
|
||||
"reset_password_expiration" timestamp(3) with time zone,
|
||||
"salt" varchar,
|
||||
"hash" varchar,
|
||||
"login_attempts" numeric,
|
||||
"lock_until" timestamp(3) with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "payload_preferences" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"key" varchar,
|
||||
"value" jsonb,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "payload_preferences_rels" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"order" integer,
|
||||
"parent_id" integer NOT NULL,
|
||||
"path" varchar NOT NULL,
|
||||
"users_id" integer
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "payload_migrations" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" varchar,
|
||||
"batch" numeric,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "customGlobal" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"text" varchar,
|
||||
"updated_at" timestamp(3) with time zone,
|
||||
"created_at" timestamp(3) with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "_customGlobal_v" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"version_text" varchar,
|
||||
"version_updated_at" timestamp(3) with time zone,
|
||||
"version_created_at" timestamp(3) with time zone,
|
||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "posts_created_at_idx" ON "posts" ("created_at");
|
||||
CREATE INDEX IF NOT EXISTS "relation_a_created_at_idx" ON "relation_a" ("created_at");
|
||||
CREATE INDEX IF NOT EXISTS "relation_a_rels_order_idx" ON "relation_a_rels" ("order");
|
||||
CREATE INDEX IF NOT EXISTS "relation_a_rels_parent_idx" ON "relation_a_rels" ("parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "relation_a_rels_path_idx" ON "relation_a_rels" ("path");
|
||||
CREATE INDEX IF NOT EXISTS "relation_b_created_at_idx" ON "relation_b" ("created_at");
|
||||
CREATE INDEX IF NOT EXISTS "relation_b_rels_order_idx" ON "relation_b_rels" ("order");
|
||||
CREATE INDEX IF NOT EXISTS "relation_b_rels_parent_idx" ON "relation_b_rels" ("parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "relation_b_rels_path_idx" ON "relation_b_rels" ("path");
|
||||
CREATE INDEX IF NOT EXISTS "customs_customSelect_order_idx" ON "customs_customSelect" ("order");
|
||||
CREATE INDEX IF NOT EXISTS "customs_customSelect_parent_idx" ON "customs_customSelect" ("parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "customArrays_order_idx" ON "customArrays" ("_order");
|
||||
CREATE INDEX IF NOT EXISTS "customArrays_parent_id_idx" ON "customArrays" ("_parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "customBlocks_order_idx" ON "customBlocks" ("_order");
|
||||
CREATE INDEX IF NOT EXISTS "customBlocks_parent_id_idx" ON "customBlocks" ("_parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "customBlocks_path_idx" ON "customBlocks" ("_path");
|
||||
CREATE INDEX IF NOT EXISTS "customs_created_at_idx" ON "customs" ("created_at");
|
||||
CREATE INDEX IF NOT EXISTS "customs__status_idx" ON "customs" ("_status");
|
||||
CREATE INDEX IF NOT EXISTS "customs_rels_order_idx" ON "customs_rels" ("order");
|
||||
CREATE INDEX IF NOT EXISTS "customs_rels_parent_idx" ON "customs_rels" ("parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "customs_rels_path_idx" ON "customs_rels" ("path");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_version_customSelect_order_idx" ON "_customs_v_version_customSelect" ("order");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_version_customSelect_parent_idx" ON "_customs_v_version_customSelect" ("parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "_customArrays_v_order_idx" ON "_customArrays_v" ("_order");
|
||||
CREATE INDEX IF NOT EXISTS "_customArrays_v_parent_id_idx" ON "_customArrays_v" ("_parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "_customBlocks_v_order_idx" ON "_customBlocks_v" ("_order");
|
||||
CREATE INDEX IF NOT EXISTS "_customBlocks_v_parent_id_idx" ON "_customBlocks_v" ("_parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "_customBlocks_v_path_idx" ON "_customBlocks_v" ("_path");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_version_version_created_at_idx" ON "_customs_v" ("version_created_at");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_version_version__status_idx" ON "_customs_v" ("version__status");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_created_at_idx" ON "_customs_v" ("created_at");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_updated_at_idx" ON "_customs_v" ("updated_at");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_latest_idx" ON "_customs_v" ("latest");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_rels_order_idx" ON "_customs_v_rels" ("order");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_rels_parent_idx" ON "_customs_v_rels" ("parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "_customs_v_rels_path_idx" ON "_customs_v_rels" ("path");
|
||||
CREATE INDEX IF NOT EXISTS "users_created_at_idx" ON "users" ("created_at");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "users_email_idx" ON "users" ("email");
|
||||
CREATE INDEX IF NOT EXISTS "payload_preferences_key_idx" ON "payload_preferences" ("key");
|
||||
CREATE INDEX IF NOT EXISTS "payload_preferences_created_at_idx" ON "payload_preferences" ("created_at");
|
||||
CREATE INDEX IF NOT EXISTS "payload_preferences_rels_order_idx" ON "payload_preferences_rels" ("order");
|
||||
CREATE INDEX IF NOT EXISTS "payload_preferences_rels_parent_idx" ON "payload_preferences_rels" ("parent_id");
|
||||
CREATE INDEX IF NOT EXISTS "payload_preferences_rels_path_idx" ON "payload_preferences_rels" ("path");
|
||||
CREATE INDEX IF NOT EXISTS "payload_migrations_created_at_idx" ON "payload_migrations" ("created_at");
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "relation_a_rels" ADD CONSTRAINT "relation_a_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "relation_a"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "relation_a_rels" ADD CONSTRAINT "relation_a_rels_relation_b_fk" FOREIGN KEY ("relation_b_id") REFERENCES "relation_b"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "relation_b_rels" ADD CONSTRAINT "relation_b_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "relation_b"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "relation_b_rels" ADD CONSTRAINT "relation_b_rels_relation_a_fk" FOREIGN KEY ("relation_a_id") REFERENCES "relation_a"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customs_customSelect" ADD CONSTRAINT "customs_customSelect_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "customs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customArrays" ADD CONSTRAINT "customArrays_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "customs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customArrays_locales" ADD CONSTRAINT "customArrays_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "customArrays"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customBlocks" ADD CONSTRAINT "customBlocks_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "customs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customBlocks_locales" ADD CONSTRAINT "customBlocks_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "customBlocks"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customs_locales" ADD CONSTRAINT "customs_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "customs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customs_rels" ADD CONSTRAINT "customs_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "customs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "customs_rels" ADD CONSTRAINT "customs_rels_relation_a_fk" FOREIGN KEY ("relation_a_id") REFERENCES "relation_a"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customs_v_version_customSelect" ADD CONSTRAINT "_customs_v_version_customSelect_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "_customs_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customArrays_v" ADD CONSTRAINT "_customArrays_v_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "_customs_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customArrays_v_locales" ADD CONSTRAINT "_customArrays_v_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "_customArrays_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customBlocks_v" ADD CONSTRAINT "_customBlocks_v_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "_customs_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customBlocks_v_locales" ADD CONSTRAINT "_customBlocks_v_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "_customBlocks_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customs_v_locales" ADD CONSTRAINT "_customs_v_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "_customs_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customs_v_rels" ADD CONSTRAINT "_customs_v_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "_customs_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customs_v_rels" ADD CONSTRAINT "_customs_v_rels_custom_schema_fk" FOREIGN KEY ("customs_id") REFERENCES "customs"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_customs_v_rels" ADD CONSTRAINT "_customs_v_rels_relation_a_fk" FOREIGN KEY ("relation_a_id") REFERENCES "relation_a"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
`)
|
||||
}
|
||||
|
||||
export async function down({ payload }: MigrateDownArgs): Promise<void> {
|
||||
await payload.db.drizzle.execute(sql`
|
||||
|
||||
DROP TABLE "posts";
|
||||
DROP TABLE "relation_a";
|
||||
DROP TABLE "relation_a_rels";
|
||||
DROP TABLE "relation_b";
|
||||
DROP TABLE "relation_b_rels";
|
||||
DROP TABLE "customs_customSelect";
|
||||
DROP TABLE "customArrays";
|
||||
DROP TABLE "customArrays_locales";
|
||||
DROP TABLE "customBlocks";
|
||||
DROP TABLE "customBlocks_locales";
|
||||
DROP TABLE "customs";
|
||||
DROP TABLE "customs_locales";
|
||||
DROP TABLE "customs_rels";
|
||||
DROP TABLE "_customs_v_version_customSelect";
|
||||
DROP TABLE "_customArrays_v";
|
||||
DROP TABLE "_customArrays_v_locales";
|
||||
DROP TABLE "_customBlocks_v";
|
||||
DROP TABLE "_customBlocks_v_locales";
|
||||
DROP TABLE "_customs_v";
|
||||
DROP TABLE "_customs_v_locales";
|
||||
DROP TABLE "_customs_v_rels";
|
||||
DROP TABLE "users";
|
||||
DROP TABLE "payload_preferences";
|
||||
DROP TABLE "payload_preferences_rels";
|
||||
DROP TABLE "payload_migrations";
|
||||
DROP TABLE "customGlobal";
|
||||
DROP TABLE "_customGlobal_v";`)
|
||||
}
|
||||
@@ -767,6 +767,39 @@ describe('fields', () => {
|
||||
await expect(page.locator('.Toastify')).toContainText('Please correct invalid fields')
|
||||
})
|
||||
|
||||
test('should duplicate block', async () => {
|
||||
await page.goto(url.create)
|
||||
const firstRow = page.locator('#field-blocks #blocks-row-0')
|
||||
const rowActions = firstRow.locator('.collapsible__actions')
|
||||
await expect(rowActions).toBeVisible()
|
||||
|
||||
await rowActions.locator('.array-actions__button').click()
|
||||
const duplicateButton = rowActions.locator('.array-actions__action.array-actions__duplicate')
|
||||
await expect(duplicateButton).toBeVisible()
|
||||
await duplicateButton.click()
|
||||
|
||||
const blocks = page.locator('#field-blocks > .blocks-field__rows > div')
|
||||
expect(await blocks.count()).toEqual(4)
|
||||
})
|
||||
|
||||
test('should save when duplicating subblocks', async () => {
|
||||
await page.goto(url.create)
|
||||
const subblocksRow = page.locator('#field-blocks #blocks-row-2')
|
||||
const rowActions = subblocksRow.locator('.collapsible__actions').first()
|
||||
await expect(rowActions).toBeVisible()
|
||||
|
||||
await rowActions.locator('.array-actions__button').click()
|
||||
const duplicateButton = rowActions.locator('.array-actions__action.array-actions__duplicate')
|
||||
await expect(duplicateButton).toBeVisible()
|
||||
await duplicateButton.click()
|
||||
|
||||
const blocks = page.locator('#field-blocks > .blocks-field__rows > div')
|
||||
expect(await blocks.count()).toEqual(4)
|
||||
|
||||
await page.click('#action-save')
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||
})
|
||||
|
||||
describe('row manipulation', () => {
|
||||
describe('react hooks', () => {
|
||||
test('should add 2 new block rows', async () => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import fs from 'fs'
|
||||
|
||||
const removeFiles = (dir) => {
|
||||
const removeFiles = (dir, nameFilter?: (name: string) => boolean) => {
|
||||
if (!fs.existsSync(dir)) return
|
||||
|
||||
fs.readdirSync(dir).forEach((f) => {
|
||||
if (nameFilter && !nameFilter(f)) return
|
||||
return fs.rmSync(`${dir}/${f}`, { recursive: true })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { GraphQLClient } from 'graphql-request'
|
||||
|
||||
import type { Config } from '../../packages/payload/src/config/types'
|
||||
import type { Where } from '../../packages/payload/src/types'
|
||||
import type { LocalizedPost, WithLocalizedRelationship } from './payload-types'
|
||||
import type { LocalizedPost, LocalizedSort, WithLocalizedRelationship } from './payload-types'
|
||||
|
||||
import payload from '../../packages/payload/src'
|
||||
import { devUser } from '../credentials'
|
||||
@@ -359,6 +359,7 @@ describe('Localization', () => {
|
||||
|
||||
describe('Localized Sort Count', () => {
|
||||
const expectedTotalDocs = 5
|
||||
const posts: LocalizedSort[] = []
|
||||
beforeAll(async () => {
|
||||
for (let i = 1; i <= expectedTotalDocs; i++) {
|
||||
const post = await payload.create({
|
||||
@@ -370,6 +371,8 @@ describe('Localization', () => {
|
||||
locale: englishLocale,
|
||||
})
|
||||
|
||||
posts.push(post)
|
||||
|
||||
await payload.update({
|
||||
id: post.id,
|
||||
collection: localizedSortSlug,
|
||||
@@ -409,6 +412,101 @@ describe('Localization', () => {
|
||||
expect(sortByTitleQuery.totalDocs).toEqual(expectedTotalDocs)
|
||||
expect(sortByDateQuery.totalDocs).toEqual(expectedTotalDocs)
|
||||
})
|
||||
|
||||
it('should return correct order when sorted by localized fields', async () => {
|
||||
const { docs: docsAsc } = await payload.find({ collection: localizedSortSlug, sort: 'title' })
|
||||
docsAsc.forEach((doc, i) => {
|
||||
expect(posts[i].id).toBe(doc.id)
|
||||
})
|
||||
const { docs: docsDesc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: '-title',
|
||||
})
|
||||
docsDesc.forEach((doc, i) => {
|
||||
expect(posts.at(posts.length - i - 1).id).toBe(doc.id)
|
||||
})
|
||||
// Test with words
|
||||
const randomWords = [
|
||||
'sunset',
|
||||
'whisper',
|
||||
'lighthouse',
|
||||
'harmony',
|
||||
'crystal',
|
||||
'thunder',
|
||||
'meadow',
|
||||
'voyage',
|
||||
'echo',
|
||||
'quicksand',
|
||||
]
|
||||
const randomWordsSpanish = [
|
||||
'atardecer',
|
||||
'susurro',
|
||||
'faro',
|
||||
'armonía',
|
||||
'cristal',
|
||||
'trueno',
|
||||
'pradera',
|
||||
'viaje',
|
||||
'eco',
|
||||
'arenas movedizas',
|
||||
]
|
||||
expect(randomWords).toHaveLength(randomWordsSpanish.length)
|
||||
const randomWordsPosts: (number | string)[] = []
|
||||
for (let i = 0; i < randomWords.length; i++) {
|
||||
const en = randomWords[i]
|
||||
const post = await payload.create({ collection: 'localized-sort', data: { title: en } })
|
||||
const es = randomWordsSpanish[i]
|
||||
await payload.update({
|
||||
collection: 'localized-sort',
|
||||
data: { title: es },
|
||||
id: post.id,
|
||||
locale: 'es',
|
||||
})
|
||||
randomWordsPosts.push(post.id)
|
||||
}
|
||||
const ascSortedWordsEn = randomWords.toSorted((a, b) => a.localeCompare(b))
|
||||
const descSortedWordsEn = randomWords.toSorted((a, b) => b.localeCompare(a))
|
||||
const q = { id: { in: randomWordsPosts } }
|
||||
const { docs: randomWordsEnAsc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: 'title',
|
||||
where: q,
|
||||
})
|
||||
randomWordsEnAsc.forEach((doc, i) => {
|
||||
expect(ascSortedWordsEn[i]).toBe(doc.title)
|
||||
})
|
||||
const { docs: randomWordsEnDesc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: '-title',
|
||||
where: q,
|
||||
})
|
||||
randomWordsEnDesc.forEach((doc, i) => {
|
||||
expect(descSortedWordsEn[i]).toBe(doc.title)
|
||||
})
|
||||
// Test sorting for Spanish locale
|
||||
const ascSortedWordsEs = randomWordsSpanish.toSorted((a, b) => a.localeCompare(b))
|
||||
const descSortedWordsEs = randomWordsSpanish.toSorted((a, b) => b.localeCompare(a))
|
||||
// Fetch sorted words in Spanish (ascending)
|
||||
const { docs: randomWordsEsAsc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: 'title',
|
||||
where: q,
|
||||
locale: 'es',
|
||||
})
|
||||
randomWordsEsAsc.forEach((doc, i) => {
|
||||
expect(ascSortedWordsEs[i]).toBe(doc.title)
|
||||
})
|
||||
// Fetch sorted words in Spanish (descending)
|
||||
const { docs: randomWordsEsDesc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: '-title',
|
||||
where: q,
|
||||
locale: 'es',
|
||||
})
|
||||
randomWordsEsDesc.forEach((doc, i) => {
|
||||
expect(descSortedWordsEs[i]).toBe(doc.title)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Localized Relationship', () => {
|
||||
|
||||
@@ -667,6 +667,32 @@ describe('Relationships', () => {
|
||||
expect(query.docs[0].id).toStrictEqual(firstLevelID)
|
||||
})
|
||||
|
||||
it('should allow querying on id two levels deep', async () => {
|
||||
const query = await payload.find({
|
||||
collection: 'chained',
|
||||
where: {
|
||||
'relation.relation.id': {
|
||||
equals: thirdLevelID,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(query.docs).toHaveLength(1)
|
||||
expect(query.docs[0].id).toStrictEqual(firstLevelID)
|
||||
|
||||
const { result: queryREST } = await client.find({
|
||||
slug: 'chained',
|
||||
query: {
|
||||
'relation.relation.id': {
|
||||
equals: thirdLevelID,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(queryREST.docs).toHaveLength(1)
|
||||
expect(queryREST.docs[0].id).toStrictEqual(firstLevelID)
|
||||
})
|
||||
|
||||
it('should allow querying within array nesting', async () => {
|
||||
const page = await payload.create({
|
||||
collection: 'pages',
|
||||
|
||||
Reference in New Issue
Block a user