Compare commits
30 Commits
chore/driz
...
feat/beta-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
008437d62f | ||
|
|
95112a873b | ||
|
|
25da9b62d1 | ||
|
|
1e5e07489c | ||
|
|
bcb1d4eb57 | ||
|
|
268fff2645 | ||
|
|
349d68c719 | ||
|
|
9fefe79998 | ||
|
|
9f73743806 | ||
|
|
cb00bc5856 | ||
|
|
bd22bb28aa | ||
|
|
ed1e460ae7 | ||
|
|
78ac4fd89e | ||
|
|
c328c42b72 | ||
|
|
8ede4d0098 | ||
|
|
31ad34595e | ||
|
|
33278aa8d8 | ||
|
|
aad186c8b4 | ||
|
|
b5b2bb1907 | ||
|
|
6f5cf5d916 | ||
|
|
aaf3a39f7e | ||
|
|
5ef2951829 | ||
|
|
a943487fca | ||
|
|
3a941c7c8a | ||
|
|
354588898f | ||
|
|
ada9978a8c | ||
|
|
874279c530 | ||
|
|
7ed6634bc5 | ||
|
|
09a0ee3ab9 | ||
|
|
67acab2cd5 |
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@@ -196,7 +196,6 @@ jobs:
|
||||
- postgres-custom-schema
|
||||
- postgres-uuid
|
||||
- supabase
|
||||
- sqlite
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
@@ -33,6 +33,9 @@ export default buildConfig({
|
||||
| Option | Description |
|
||||
| -------------------- | ----------- |
|
||||
| `autoPluralization` | Tell Mongoose to auto-pluralize any collection names if it encounters any singular words used as collection `slug`s. |
|
||||
| `schemaOptions` | Customize schema options for all Mongoose schemas created internally. |
|
||||
| `collections` | Options on a collection-by-collection basis. [More](#collections-options) |
|
||||
| `globals` | Options for the Globals collection created by Payload. [More](#globals-options) |
|
||||
| `connectOptions` | Customize MongoDB connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose. |
|
||||
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
|
||||
| `migrationDir` | Customize the directory that migrations are stored. |
|
||||
@@ -49,3 +52,27 @@ You can access Mongoose models as follows:
|
||||
- Collection models - `payload.db.collections[myCollectionSlug]`
|
||||
- Globals model - `payload.db.globals`
|
||||
- Versions model (both collections and globals) - `payload.db.versions[myEntitySlug]`
|
||||
|
||||
### Collections Options
|
||||
|
||||
You can configure the way the MongoDB adapter works on a collection-by-collection basis, including customizing Mongoose `schemaOptions` for each collection schema created.
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
const db = mongooseAdapter({
|
||||
url: 'your-url-here',
|
||||
collections: {
|
||||
users: {
|
||||
//
|
||||
schemaOptions: {
|
||||
strict: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Global Options
|
||||
|
||||
Payload automatically creates a single `globals` collection that correspond with any Payload globals that you define. When you initialize the `mongooseAdapter`, you can specify settings here for your globals in a similar manner to how you can for collections above. Right now, the only property available is `schemaOptions` but more may be added in the future.
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
"create-payload-app": "workspace:*",
|
||||
"cross-env": "7.0.3",
|
||||
"dotenv": "16.4.5",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"escape-html": "^1.0.3",
|
||||
"execa": "5.1.1",
|
||||
"form-data": "3.0.1",
|
||||
@@ -150,7 +150,7 @@
|
||||
"tempy": "1.0.1",
|
||||
"tsx": "4.16.2",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.0.0 || ^19.0.0-rc-6230622a1a-20240610",
|
||||
|
||||
@@ -240,25 +240,63 @@ async function installDeps(projectDir: string, packageManager: PackageManager, d
|
||||
export async function getNextAppDetails(projectDir: string): Promise<NextAppDetails> {
|
||||
const isSrcDir = fs.existsSync(path.resolve(projectDir, 'src'))
|
||||
|
||||
// Match next.config.js, next.config.ts, next.config.mjs, next.config.cjs
|
||||
const nextConfigPath: string | undefined = (
|
||||
await globby('next.config.*(t|j)s', { absolute: true, cwd: projectDir })
|
||||
await globby('next.config.(\\w)?(t|j)s', { absolute: true, cwd: projectDir })
|
||||
)?.[0]
|
||||
|
||||
if (!nextConfigPath || nextConfigPath.length === 0) {
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion: false,
|
||||
nextConfigPath: undefined,
|
||||
nextVersion: null,
|
||||
}
|
||||
}
|
||||
|
||||
const packageObj = await fse.readJson(path.resolve(projectDir, 'package.json'))
|
||||
// Check if Next.js version is new enough
|
||||
let nextVersion = null
|
||||
if (packageObj.dependencies?.next) {
|
||||
nextVersion = packageObj.dependencies.next
|
||||
// Match versions using regex matching groups
|
||||
const versionMatch = /(?<major>\d+)/.exec(nextVersion)
|
||||
if (!versionMatch) {
|
||||
p.log.warn(`Could not determine Next.js version from ${nextVersion}`)
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion: false,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
}
|
||||
}
|
||||
|
||||
const { major } = versionMatch.groups as { major: string }
|
||||
const majorVersion = parseInt(major)
|
||||
if (majorVersion < 15) {
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion: false,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isSupportedNextVersion = true
|
||||
|
||||
// Check if Payload already installed
|
||||
if (packageObj.dependencies?.payload) {
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isPayloadInstalled: true,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +319,15 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
|
||||
? fs.existsSync(path.resolve(nextAppDir, 'layout.tsx'))
|
||||
: false
|
||||
|
||||
return { hasTopLevelLayout, isSrcDir, nextAppDir, nextConfigPath, nextConfigType: configType }
|
||||
return {
|
||||
hasTopLevelLayout,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion,
|
||||
nextAppDir,
|
||||
nextConfigPath,
|
||||
nextConfigType: configType,
|
||||
nextVersion,
|
||||
}
|
||||
}
|
||||
|
||||
function getProjectType(args: {
|
||||
|
||||
@@ -85,7 +85,22 @@ export class Main {
|
||||
|
||||
// Detect if inside Next.js project
|
||||
const nextAppDetails = await getNextAppDetails(process.cwd())
|
||||
const { hasTopLevelLayout, isPayloadInstalled, nextAppDir, nextConfigPath } = nextAppDetails
|
||||
const {
|
||||
hasTopLevelLayout,
|
||||
isPayloadInstalled,
|
||||
isSupportedNextVersion,
|
||||
nextAppDir,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
} = nextAppDetails
|
||||
|
||||
if (nextConfigPath && !isSupportedNextVersion) {
|
||||
p.log.warn(
|
||||
`Next.js v${nextVersion} is unsupported. Next.js >= 15 is required to use Payload.`,
|
||||
)
|
||||
p.outro(feedbackOutro())
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Upgrade Payload in existing project
|
||||
if (isPayloadInstalled && nextConfigPath) {
|
||||
|
||||
@@ -70,9 +70,11 @@ export type NextAppDetails = {
|
||||
hasTopLevelLayout: boolean
|
||||
isPayloadInstalled?: boolean
|
||||
isSrcDir: boolean
|
||||
isSupportedNextVersion: boolean
|
||||
nextAppDir?: string
|
||||
nextConfigPath?: string
|
||||
nextConfigType?: NextConfigType
|
||||
nextVersion: null | string
|
||||
}
|
||||
|
||||
export type NextConfigType = 'cjs' | 'esm' | 'ts'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CollationOptions, TransactionOptions } from 'mongodb'
|
||||
import type { MongoMemoryReplSet } from 'mongodb-memory-server'
|
||||
import type { ClientSession, ConnectOptions, Connection } from 'mongoose'
|
||||
import type { ClientSession, ConnectOptions, Connection, SchemaOptions } from 'mongoose'
|
||||
import type { BaseDatabaseAdapter, DatabaseAdapterObj, Payload } from 'payload'
|
||||
|
||||
import fs from 'fs'
|
||||
@@ -66,6 +66,15 @@ export interface Args {
|
||||
* Defaults to disabled.
|
||||
*/
|
||||
collation?: Omit<CollationOptions, 'locale'>
|
||||
/** Define Mongoose options on a collection-by-collection basis.
|
||||
*/
|
||||
collections?: {
|
||||
[slug: string]: {
|
||||
/** Define Mongoose schema options for a given collection.
|
||||
*/
|
||||
schemaOptions?: SchemaOptions
|
||||
}
|
||||
}
|
||||
/** Extra configuration options */
|
||||
connectOptions?: {
|
||||
/** Set false to disable $facet aggregation in non-supporting databases, Defaults to true */
|
||||
@@ -73,23 +82,40 @@ export interface Args {
|
||||
} & ConnectOptions
|
||||
/** Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false */
|
||||
disableIndexHints?: boolean
|
||||
/** Define Mongoose options for the globals collection.
|
||||
*/
|
||||
globals?: {
|
||||
schemaOptions?: SchemaOptions
|
||||
}
|
||||
migrationDir?: string
|
||||
/**
|
||||
* typed as any to avoid dependency
|
||||
*/
|
||||
mongoMemoryServer?: MongoMemoryReplSet
|
||||
/** Define default Mongoose schema options for all schemas created.
|
||||
*/
|
||||
schemaOptions?: SchemaOptions
|
||||
transactionOptions?: TransactionOptions | false
|
||||
/** The URL to connect to MongoDB or false to start payload and prevent connecting */
|
||||
url: false | string
|
||||
}
|
||||
|
||||
export type MongooseAdapter = {
|
||||
collectionOptions: {
|
||||
[slug: string]: {
|
||||
schemaOptions?: SchemaOptions
|
||||
}
|
||||
}
|
||||
collections: {
|
||||
[slug: string]: CollectionModel
|
||||
}
|
||||
connection: Connection
|
||||
globals: GlobalModel
|
||||
globalsOptions: {
|
||||
schemaOptions?: SchemaOptions
|
||||
}
|
||||
mongoMemoryServer: MongoMemoryReplSet
|
||||
schemaOptions?: SchemaOptions
|
||||
sessions: Record<number | string, ClientSession>
|
||||
versions: {
|
||||
[slug: string]: CollectionModel
|
||||
@@ -100,13 +126,22 @@ export type MongooseAdapter = {
|
||||
declare module 'payload' {
|
||||
export interface DatabaseAdapter
|
||||
extends Omit<BaseDatabaseAdapter, 'sessions'>,
|
||||
Omit<Args, 'migrationDir'> {
|
||||
Omit<Args, 'collections' | 'globals' | 'migrationDir'> {
|
||||
collectionOptions: {
|
||||
[slug: string]: {
|
||||
schemaOptions?: SchemaOptions
|
||||
}
|
||||
}
|
||||
collections: {
|
||||
[slug: string]: CollectionModel
|
||||
}
|
||||
connection: Connection
|
||||
globals: GlobalModel
|
||||
globalsOptions: {
|
||||
schemaOptions?: SchemaOptions
|
||||
}
|
||||
mongoMemoryServer: MongoMemoryReplSet
|
||||
schemaOptions?: SchemaOptions
|
||||
sessions: Record<number | string, ClientSession>
|
||||
transactionOptions: TransactionOptions
|
||||
versions: {
|
||||
@@ -117,10 +152,13 @@ declare module 'payload' {
|
||||
|
||||
export function mongooseAdapter({
|
||||
autoPluralization = true,
|
||||
collections,
|
||||
connectOptions,
|
||||
disableIndexHints = false,
|
||||
globals,
|
||||
migrationDir: migrationDirArg,
|
||||
mongoMemoryServer,
|
||||
schemaOptions,
|
||||
transactionOptions = {},
|
||||
url,
|
||||
}: Args): DatabaseAdapterObj {
|
||||
@@ -133,17 +171,21 @@ export function mongooseAdapter({
|
||||
|
||||
// Mongoose-specific
|
||||
autoPluralization,
|
||||
collectionOptions: collections || {},
|
||||
collections: {},
|
||||
connectOptions: connectOptions || {},
|
||||
connection: undefined,
|
||||
count,
|
||||
disableIndexHints,
|
||||
globals: undefined,
|
||||
globalsOptions: globals || {},
|
||||
mongoMemoryServer,
|
||||
schemaOptions: schemaOptions || {},
|
||||
sessions: {},
|
||||
transactionOptions: transactionOptions === false ? undefined : transactionOptions,
|
||||
url,
|
||||
versions: {},
|
||||
|
||||
// DatabaseAdapter
|
||||
beginTransaction: transactionOptions ? beginTransaction : undefined,
|
||||
commitTransaction,
|
||||
|
||||
@@ -16,20 +16,22 @@ import { getDBName } from './utilities/getDBName.js'
|
||||
|
||||
export const init: Init = function init(this: MongooseAdapter) {
|
||||
this.payload.config.collections.forEach((collection: SanitizedCollectionConfig) => {
|
||||
const schema = buildCollectionSchema(collection, this.payload.config)
|
||||
const schema = buildCollectionSchema(collection, this)
|
||||
|
||||
if (collection.versions) {
|
||||
const versionModelName = getDBName({ config: collection, versions: true })
|
||||
|
||||
const versionCollectionFields = buildVersionCollectionFields(collection)
|
||||
|
||||
const versionSchema = buildSchema(this.payload.config, versionCollectionFields, {
|
||||
const versionSchema = buildSchema(this, versionCollectionFields, {
|
||||
disableUnique: true,
|
||||
draftsEnabled: true,
|
||||
indexSortableFields: this.payload.config.indexSortableFields,
|
||||
options: {
|
||||
minimize: false,
|
||||
timestamps: false,
|
||||
...this.schemaOptions,
|
||||
...(this.collectionOptions[collection.slug]?.schemaOptions || {}),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -57,7 +59,7 @@ export const init: Init = function init(this: MongooseAdapter) {
|
||||
this.collections[collection.slug] = model
|
||||
})
|
||||
|
||||
const model = buildGlobalModel(this.payload.config)
|
||||
const model = buildGlobalModel(this)
|
||||
this.globals = model
|
||||
|
||||
this.payload.config.globals.forEach((global) => {
|
||||
@@ -66,13 +68,15 @@ export const init: Init = function init(this: MongooseAdapter) {
|
||||
|
||||
const versionGlobalFields = buildVersionGlobalFields(global)
|
||||
|
||||
const versionSchema = buildSchema(this.payload.config, versionGlobalFields, {
|
||||
const versionSchema = buildSchema(this, versionGlobalFields, {
|
||||
disableUnique: true,
|
||||
draftsEnabled: true,
|
||||
indexSortableFields: this.payload.config.indexSortableFields,
|
||||
options: {
|
||||
minimize: false,
|
||||
timestamps: false,
|
||||
...this.schemaOptions,
|
||||
...(this.globalsOptions.schemaOptions || {}),
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
import type { PaginateOptions, Schema } from 'mongoose'
|
||||
import type { SanitizedCollectionConfig, SanitizedConfig } from 'payload'
|
||||
import type { SanitizedCollectionConfig } from 'payload'
|
||||
|
||||
import paginate from 'mongoose-paginate-v2'
|
||||
|
||||
import type { MongooseAdapter } from '../index.js'
|
||||
|
||||
import getBuildQueryPlugin from '../queries/buildQuery.js'
|
||||
import buildSchema from './buildSchema.js'
|
||||
|
||||
const buildCollectionSchema = (
|
||||
collection: SanitizedCollectionConfig,
|
||||
config: SanitizedConfig,
|
||||
schemaOptions = {},
|
||||
adapter: MongooseAdapter,
|
||||
): Schema => {
|
||||
const schema = buildSchema(config, collection.fields, {
|
||||
const schema = buildSchema(adapter, collection.fields, {
|
||||
draftsEnabled: Boolean(typeof collection?.versions === 'object' && collection.versions.drafts),
|
||||
indexSortableFields: config.indexSortableFields,
|
||||
indexSortableFields: adapter.payload.config.indexSortableFields,
|
||||
options: {
|
||||
minimize: false,
|
||||
timestamps: collection.timestamps !== false,
|
||||
...schemaOptions,
|
||||
...adapter.schemaOptions,
|
||||
...(adapter.collectionOptions[collection.slug]?.schemaOptions || {}),
|
||||
},
|
||||
})
|
||||
|
||||
if (config.indexSortableFields && collection.timestamps !== false) {
|
||||
if (adapter.payload.config.indexSortableFields && collection.timestamps !== false) {
|
||||
schema.index({ updatedAt: 1 })
|
||||
schema.index({ createdAt: 1 })
|
||||
}
|
||||
|
||||
@@ -1,27 +1,34 @@
|
||||
import type { SanitizedConfig } from 'payload'
|
||||
|
||||
import mongoose from 'mongoose'
|
||||
|
||||
import type { MongooseAdapter } from '../index.js'
|
||||
import type { GlobalModel } from '../types.js'
|
||||
|
||||
import getBuildQueryPlugin from '../queries/buildQuery.js'
|
||||
import buildSchema from './buildSchema.js'
|
||||
|
||||
export const buildGlobalModel = (config: SanitizedConfig): GlobalModel | null => {
|
||||
if (config.globals && config.globals.length > 0) {
|
||||
export const buildGlobalModel = (adapter: MongooseAdapter): GlobalModel | null => {
|
||||
if (adapter.payload.config.globals && adapter.payload.config.globals.length > 0) {
|
||||
const globalsSchema = new mongoose.Schema(
|
||||
{},
|
||||
{ discriminatorKey: 'globalType', minimize: false, timestamps: true },
|
||||
{
|
||||
discriminatorKey: 'globalType',
|
||||
minimize: false,
|
||||
...adapter.schemaOptions,
|
||||
...(adapter.globalsOptions.schemaOptions || {}),
|
||||
timestamps: true,
|
||||
},
|
||||
)
|
||||
|
||||
globalsSchema.plugin(getBuildQueryPlugin())
|
||||
|
||||
const Globals = mongoose.model('globals', globalsSchema, 'globals') as unknown as GlobalModel
|
||||
|
||||
Object.values(config.globals).forEach((globalConfig) => {
|
||||
const globalSchema = buildSchema(config, globalConfig.fields, {
|
||||
Object.values(adapter.payload.config.globals).forEach((globalConfig) => {
|
||||
const globalSchema = buildSchema(adapter, globalConfig.fields, {
|
||||
options: {
|
||||
minimize: false,
|
||||
...adapter.schemaOptions,
|
||||
...(adapter.globalsOptions.schemaOptions || {}),
|
||||
},
|
||||
})
|
||||
Globals.discriminator(globalConfig.slug, globalSchema)
|
||||
|
||||
@@ -19,7 +19,6 @@ import type {
|
||||
RelationshipField,
|
||||
RichTextField,
|
||||
RowField,
|
||||
SanitizedConfig,
|
||||
SanitizedLocalizationConfig,
|
||||
SelectField,
|
||||
Tab,
|
||||
@@ -37,6 +36,8 @@ import {
|
||||
tabHasName,
|
||||
} from 'payload/shared'
|
||||
|
||||
import type { MongooseAdapter } from '../index.js'
|
||||
|
||||
export type BuildSchemaOptions = {
|
||||
allowIDField?: boolean
|
||||
disableUnique?: boolean
|
||||
@@ -48,7 +49,7 @@ export type BuildSchemaOptions = {
|
||||
type FieldSchemaGenerator = (
|
||||
field: Field,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
) => void
|
||||
|
||||
@@ -87,10 +88,10 @@ const localizeSchema = (
|
||||
if (fieldIsLocalized(entity) && localization && Array.isArray(localization.locales)) {
|
||||
return {
|
||||
type: localization.localeCodes.reduce(
|
||||
(localeSchema, locale) => ({
|
||||
...localeSchema,
|
||||
[locale]: schema,
|
||||
}),
|
||||
(localeSchema, locale) => {
|
||||
localeSchema[locale] = schema
|
||||
return localeSchema
|
||||
},
|
||||
{
|
||||
_id: false,
|
||||
},
|
||||
@@ -102,7 +103,7 @@ const localizeSchema = (
|
||||
}
|
||||
|
||||
const buildSchema = (
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
configFields: Field[],
|
||||
buildSchemaOptions: BuildSchemaOptions = {},
|
||||
): Schema => {
|
||||
@@ -130,7 +131,7 @@ const buildSchema = (
|
||||
const addFieldSchema: FieldSchemaGenerator = fieldToSchemaMap[field.type]
|
||||
|
||||
if (addFieldSchema) {
|
||||
addFieldSchema(field, schema, config, buildSchemaOptions)
|
||||
addFieldSchema(field, schema, adapter, buildSchemaOptions)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -142,20 +143,22 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
array: (
|
||||
field: ArrayField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
) => {
|
||||
const baseSchema = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
type: [
|
||||
buildSchema(config, field.fields, {
|
||||
buildSchema(adapter, field.fields, {
|
||||
allowIDField: true,
|
||||
disableUnique: buildSchemaOptions.disableUnique,
|
||||
draftsEnabled: buildSchemaOptions.draftsEnabled,
|
||||
options: {
|
||||
minimize: false,
|
||||
...(buildSchemaOptions.options || {}),
|
||||
_id: false,
|
||||
id: false,
|
||||
minimize: false,
|
||||
timestamps: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
@@ -163,36 +166,54 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
blocks: (
|
||||
field: BlockField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const fieldSchema = {
|
||||
type: [new mongoose.Schema({}, { _id: false, discriminatorKey: 'blockType' })],
|
||||
type: [
|
||||
new mongoose.Schema(
|
||||
{},
|
||||
{
|
||||
_id: false,
|
||||
discriminatorKey: 'blockType',
|
||||
...(buildSchemaOptions.options || {}),
|
||||
timestamps: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
default: undefined,
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, fieldSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, fieldSchema, adapter.payload.config.localization),
|
||||
})
|
||||
|
||||
field.blocks.forEach((blockItem: Block) => {
|
||||
const blockSchema = new mongoose.Schema({}, { _id: false, id: false })
|
||||
const blockSchema = new mongoose.Schema(
|
||||
{},
|
||||
{
|
||||
...(buildSchemaOptions.options || {}),
|
||||
_id: false,
|
||||
id: false,
|
||||
timestamps: false,
|
||||
},
|
||||
)
|
||||
|
||||
blockItem.fields.forEach((blockField) => {
|
||||
const addFieldSchema: FieldSchemaGenerator = fieldToSchemaMap[blockField.type]
|
||||
if (addFieldSchema) {
|
||||
addFieldSchema(blockField, blockSchema, config, buildSchemaOptions)
|
||||
addFieldSchema(blockField, blockSchema, adapter, buildSchemaOptions)
|
||||
}
|
||||
})
|
||||
|
||||
if (field.localized && config.localization) {
|
||||
config.localization.localeCodes.forEach((localeCode) => {
|
||||
if (field.localized && adapter.payload.config.localization) {
|
||||
adapter.payload.config.localization.localeCodes.forEach((localeCode) => {
|
||||
// @ts-expect-error Possible incorrect typing in mongoose types, this works
|
||||
schema.path(`${field.name}.${localeCode}`).discriminator(blockItem.slug, blockSchema)
|
||||
})
|
||||
@@ -205,69 +226,69 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
checkbox: (
|
||||
field: CheckboxField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = { ...formatBaseSchema(field, buildSchemaOptions), type: Boolean }
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
code: (
|
||||
field: CodeField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = { ...formatBaseSchema(field, buildSchemaOptions), type: String }
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
collapsible: (
|
||||
field: CollapsibleField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
field.fields.forEach((subField: Field) => {
|
||||
const addFieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type]
|
||||
|
||||
if (addFieldSchema) {
|
||||
addFieldSchema(subField, schema, config, buildSchemaOptions)
|
||||
addFieldSchema(subField, schema, adapter, buildSchemaOptions)
|
||||
}
|
||||
})
|
||||
},
|
||||
date: (
|
||||
field: DateField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = { ...formatBaseSchema(field, buildSchemaOptions), type: Date }
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
email: (
|
||||
field: EmailField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = { ...formatBaseSchema(field, buildSchemaOptions), type: String }
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
group: (
|
||||
field: GroupField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const formattedBaseSchema = formatBaseSchema(field, buildSchemaOptions)
|
||||
@@ -280,26 +301,28 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
|
||||
const baseSchema = {
|
||||
...formattedBaseSchema,
|
||||
type: buildSchema(config, field.fields, {
|
||||
type: buildSchema(adapter, field.fields, {
|
||||
disableUnique: buildSchemaOptions.disableUnique,
|
||||
draftsEnabled: buildSchemaOptions.draftsEnabled,
|
||||
indexSortableFields,
|
||||
options: {
|
||||
minimize: false,
|
||||
...(buildSchemaOptions.options || {}),
|
||||
_id: false,
|
||||
id: false,
|
||||
minimize: false,
|
||||
timestamps: false,
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
json: (
|
||||
field: JSONField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
@@ -308,13 +331,13 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
number: (
|
||||
field: NumberField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
@@ -323,13 +346,13 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
point: (
|
||||
field: PointField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema: SchemaTypeOptions<unknown> = {
|
||||
@@ -348,7 +371,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
|
||||
if (field.index === true || field.index === undefined) {
|
||||
@@ -357,8 +380,8 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
indexOptions.sparse = true
|
||||
indexOptions.unique = true
|
||||
}
|
||||
if (field.localized && config.localization) {
|
||||
config.localization.locales.forEach((locale) => {
|
||||
if (field.localized && adapter.payload.config.localization) {
|
||||
adapter.payload.config.localization.locales.forEach((locale) => {
|
||||
schema.index({ [`${field.name}.${locale.code}`]: '2dsphere' }, indexOptions)
|
||||
})
|
||||
} else {
|
||||
@@ -369,7 +392,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
radio: (
|
||||
field: RadioField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
@@ -382,21 +405,21 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
relationship: (
|
||||
field: RelationshipField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
) => {
|
||||
const hasManyRelations = Array.isArray(field.relationTo)
|
||||
let schemaToReturn: { [key: string]: any } = {}
|
||||
|
||||
if (field.localized && config.localization) {
|
||||
if (field.localized && adapter.payload.config.localization) {
|
||||
schemaToReturn = {
|
||||
type: config.localization.localeCodes.reduce((locales, locale) => {
|
||||
type: adapter.payload.config.localization.localeCodes.reduce((locales, locale) => {
|
||||
let localeSchema: { [key: string]: any } = {}
|
||||
|
||||
if (hasManyRelations) {
|
||||
@@ -465,7 +488,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
richText: (
|
||||
field: RichTextField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
@@ -474,27 +497,27 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
row: (
|
||||
field: RowField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
field.fields.forEach((subField: Field) => {
|
||||
const addFieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type]
|
||||
|
||||
if (addFieldSchema) {
|
||||
addFieldSchema(subField, schema, config, buildSchemaOptions)
|
||||
addFieldSchema(subField, schema, adapter, buildSchemaOptions)
|
||||
}
|
||||
})
|
||||
},
|
||||
select: (
|
||||
field: SelectField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
@@ -514,39 +537,41 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
[field.name]: localizeSchema(
|
||||
field,
|
||||
field.hasMany ? [baseSchema] : baseSchema,
|
||||
config.localization,
|
||||
adapter.payload.config.localization,
|
||||
),
|
||||
})
|
||||
},
|
||||
tabs: (
|
||||
field: TabsField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
field.tabs.forEach((tab) => {
|
||||
if (tabHasName(tab)) {
|
||||
const baseSchema = {
|
||||
type: buildSchema(config, tab.fields, {
|
||||
type: buildSchema(adapter, tab.fields, {
|
||||
disableUnique: buildSchemaOptions.disableUnique,
|
||||
draftsEnabled: buildSchemaOptions.draftsEnabled,
|
||||
options: {
|
||||
minimize: false,
|
||||
...(buildSchemaOptions.options || {}),
|
||||
_id: false,
|
||||
id: false,
|
||||
minimize: false,
|
||||
timestamps: false,
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[tab.name]: localizeSchema(tab, baseSchema, config.localization),
|
||||
[tab.name]: localizeSchema(tab, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
} else {
|
||||
tab.fields.forEach((subField: Field) => {
|
||||
const addFieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type]
|
||||
|
||||
if (addFieldSchema) {
|
||||
addFieldSchema(subField, schema, config, buildSchemaOptions)
|
||||
addFieldSchema(subField, schema, adapter, buildSchemaOptions)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -555,7 +580,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
text: (
|
||||
field: TextField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
@@ -564,25 +589,25 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
textarea: (
|
||||
field: TextareaField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = { ...formatBaseSchema(field, buildSchemaOptions), type: String }
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
upload: (
|
||||
field: UploadField,
|
||||
schema: Schema,
|
||||
config: SanitizedConfig,
|
||||
adapter: MongooseAdapter,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
@@ -592,7 +617,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
}
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
[field.name]: localizeSchema(field, baseSchema, adapter.payload.config.localization),
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
"dependencies": {
|
||||
"@payloadcms/drizzle": "workspace:*",
|
||||
"console-table-printer": "2.11.2",
|
||||
"drizzle-kit": "0.23.0-eb2ca29",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-kit": "0.20.14-1f2c838",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"pg": "8.11.3",
|
||||
"prompts": "2.4.2",
|
||||
"to-snake-case": "1.0.0",
|
||||
|
||||
@@ -7,11 +7,10 @@ export const defaultDrizzleSnapshot: DrizzleSnapshotJSON = {
|
||||
schemas: {},
|
||||
tables: {},
|
||||
},
|
||||
dialect: 'postgresql',
|
||||
dialect: 'pg',
|
||||
enums: {},
|
||||
prevId: '00000000-0000-0000-0000-00000000000',
|
||||
schemas: {},
|
||||
sequences: {},
|
||||
tables: {},
|
||||
version: '7',
|
||||
version: '5',
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ declare module 'payload' {
|
||||
export interface DatabaseAdapter
|
||||
extends Omit<Args, 'idType' | 'logger' | 'migrationDir' | 'pool'>,
|
||||
DrizzleAdapter {
|
||||
beginTransaction: (options?: PgTransactionConfig) => Promise<null | number | string>
|
||||
drizzle: PostgresDB
|
||||
enums: Record<string, GenericEnum>
|
||||
/**
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
"@libsql/client": "^0.6.2",
|
||||
"@payloadcms/drizzle": "workspace:*",
|
||||
"console-table-printer": "2.11.2",
|
||||
"drizzle-kit": "0.23.0-eb2ca29",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-kit": "0.20.14-1f2c838",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"prompts": "2.4.2",
|
||||
"to-snake-case": "1.0.0",
|
||||
"uuid": "9.0.0"
|
||||
|
||||
@@ -10,5 +10,5 @@ export const defaultDrizzleSnapshot: DrizzleSQLiteSnapshotJSON = {
|
||||
enums: {},
|
||||
prevId: '00000000-0000-0000-0000-00000000000',
|
||||
tables: {},
|
||||
version: '6',
|
||||
version: '5',
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { ColumnDataType, Relation } from 'drizzle-orm'
|
||||
import type {
|
||||
AnySQLiteColumn,
|
||||
ForeignKeyBuilder,
|
||||
IndexBuilder,
|
||||
SQLiteColumn,
|
||||
SQLiteColumnBuilder,
|
||||
SQLiteTableWithColumns,
|
||||
UniqueConstraintBuilder,
|
||||
@@ -31,7 +32,18 @@ import { traverseFields } from './traverseFields.js'
|
||||
export type BaseExtraConfig = Record<
|
||||
string,
|
||||
(cols: {
|
||||
[x: string]: AnySQLiteColumn
|
||||
[x: string]: SQLiteColumn<{
|
||||
baseColumn: never
|
||||
columnType: string
|
||||
data: unknown
|
||||
dataType: ColumnDataType
|
||||
driverParam: unknown
|
||||
enumValues: string[]
|
||||
hasDefault: false
|
||||
name: string
|
||||
notNull: false
|
||||
tableName: string
|
||||
}>
|
||||
}) => ForeignKeyBuilder | IndexBuilder | UniqueConstraintBuilder
|
||||
>
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { AnySQLiteColumn} from 'drizzle-orm/sqlite-core';
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { index, uniqueIndex } from 'drizzle-orm/sqlite-core'
|
||||
|
||||
import type { GenericColumn } from '../types.js'
|
||||
|
||||
type CreateIndexArgs = {
|
||||
columnName: string
|
||||
name: string | string[]
|
||||
@@ -10,7 +11,7 @@ type CreateIndexArgs = {
|
||||
}
|
||||
|
||||
export const createIndex = ({ name, columnName, tableName, unique }: CreateIndexArgs) => {
|
||||
return (table: { [x: string]: AnySQLiteColumn }) => {
|
||||
return (table: { [x: string]: GenericColumn }) => {
|
||||
let columns
|
||||
if (Array.isArray(name)) {
|
||||
columns = name
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { Client, Config, ResultSet } from '@libsql/client'
|
||||
import type { Operators } from '@payloadcms/drizzle'
|
||||
import type { BuildQueryJoinAliases, DrizzleAdapter } from '@payloadcms/drizzle/types'
|
||||
import type { DrizzleConfig, Relation, Relations, SQL } from 'drizzle-orm'
|
||||
import type { ColumnDataType, DrizzleConfig, Relation, Relations, SQL } from 'drizzle-orm'
|
||||
import type { LibSQLDatabase } from 'drizzle-orm/libsql'
|
||||
import type {
|
||||
AnySQLiteColumn,
|
||||
SQLiteColumn,
|
||||
SQLiteInsertOnConflictDoUpdateConfig,
|
||||
SQLiteTableWithColumns,
|
||||
SQLiteTransactionConfig,
|
||||
@@ -25,8 +25,24 @@ export type Args = {
|
||||
versionsSuffix?: string
|
||||
}
|
||||
|
||||
export type GenericColumn = SQLiteColumn<
|
||||
{
|
||||
baseColumn: never
|
||||
columnType: string
|
||||
data: unknown
|
||||
dataType: ColumnDataType
|
||||
driverParam: unknown
|
||||
enumValues: string[]
|
||||
hasDefault: false
|
||||
name: string
|
||||
notNull: false
|
||||
tableName: string
|
||||
},
|
||||
object
|
||||
>
|
||||
|
||||
export type GenericColumns = {
|
||||
[x: string]: AnySQLiteColumn
|
||||
[x: string]: GenericColumn
|
||||
}
|
||||
|
||||
export type GenericTable = SQLiteTableWithColumns<{
|
||||
@@ -128,6 +144,7 @@ declare module 'payload' {
|
||||
export interface DatabaseAdapter
|
||||
extends Omit<Args, 'idType' | 'logger' | 'migrationDir' | 'pool'>,
|
||||
DrizzleAdapter {
|
||||
beginTransaction: (options?: SQLiteTransactionConfig) => Promise<null | number | string>
|
||||
drizzle: LibSQLDatabase
|
||||
/**
|
||||
* An object keyed on each table, with a key value pair where the constraint name is the key, followed by the dot-notation field name
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"console-table-printer": "2.11.2",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"prompts": "2.4.2",
|
||||
"to-snake-case": "1.0.0",
|
||||
"uuid": "9.0.0"
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { DrizzleAdapter, DrizzleTransaction } from '../types.js'
|
||||
|
||||
export const beginTransaction: BeginTransaction = async function beginTransaction(
|
||||
this: DrizzleAdapter,
|
||||
options: DrizzleAdapter['transactionOptions'],
|
||||
) {
|
||||
let id
|
||||
try {
|
||||
@@ -41,7 +42,7 @@ export const beginTransaction: BeginTransaction = async function beginTransactio
|
||||
}
|
||||
transactionReady()
|
||||
})
|
||||
}, this.transactionOptions)
|
||||
}, options || this.transactionOptions)
|
||||
.catch(() => {
|
||||
// swallow
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ export const migrationTableExists = async (adapter: DrizzleAdapter): Promise<boo
|
||||
|
||||
if (adapter.name === 'postgres') {
|
||||
const prependSchema = adapter.schemaName ? `"${adapter.schemaName}".` : ''
|
||||
statement = `SELECT to_regclass('${prependSchema}"payload_migrations"') exists;`
|
||||
statement = `SELECT to_regclass('${prependSchema}"payload_migrations"') AS exists;`
|
||||
}
|
||||
|
||||
if (adapter.name === 'sqlite') {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"eslint-plugin-react-hooks": "5.1.0-rc-85acf2d195-20240711",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"globals": "15.8.0",
|
||||
"typescript": "5.5.3",
|
||||
"typescript": "5.5.4",
|
||||
"typescript-eslint": "7.16.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"eslint-plugin-react-hooks": "5.1.0-rc-85acf2d195-20240711",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"globals": "15.8.0",
|
||||
"typescript": "5.5.3",
|
||||
"typescript": "5.5.4",
|
||||
"typescript-eslint": "7.16.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { GraphQLJSON, GraphQLJSONObject } from '../packages/graphql-type-json/index.js'
|
||||
export { buildPaginatedListType } from '../schema/buildPaginatedListType.js'
|
||||
export { default as GraphQL } from 'graphql'
|
||||
export * as GraphQL from 'graphql'
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
|
||||
import { notFound } from 'next/navigation.js'
|
||||
|
||||
import { isAdminAuthRoute, isAdminRoute } from './shared.js'
|
||||
import { getRouteWithoutAdmin, isAdminAuthRoute, isAdminRoute } from './shared.js'
|
||||
|
||||
export const handleAdminPage = ({
|
||||
adminRoute,
|
||||
@@ -20,9 +20,9 @@ export const handleAdminPage = ({
|
||||
permissions: Permissions
|
||||
route: string
|
||||
}) => {
|
||||
if (isAdminRoute(route, adminRoute)) {
|
||||
const baseAdminRoute = adminRoute && adminRoute !== '/' ? route.replace(adminRoute, '') : route
|
||||
const routeSegments = baseAdminRoute.split('/').filter(Boolean)
|
||||
if (isAdminRoute({ adminRoute, config, route })) {
|
||||
const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route })
|
||||
const routeSegments = routeWithoutAdmin.split('/').filter(Boolean)
|
||||
const [entityType, entitySlug, createOrID] = routeSegments
|
||||
const collectionSlug = entityType === 'collections' ? entitySlug : undefined
|
||||
const globalSlug = entityType === 'globals' ? entitySlug : undefined
|
||||
@@ -47,7 +47,7 @@ export const handleAdminPage = ({
|
||||
}
|
||||
}
|
||||
|
||||
if (!permissions.canAccessAdmin && !isAdminAuthRoute(config, route, adminRoute)) {
|
||||
if (!permissions.canAccessAdmin && !isAdminAuthRoute({ adminRoute, config, route })) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export const handleAuthRedirect = ({
|
||||
routes: { admin: adminRoute },
|
||||
} = config
|
||||
|
||||
if (!isAdminAuthRoute(config, route, adminRoute)) {
|
||||
if (!isAdminAuthRoute({ adminRoute, config, route })) {
|
||||
if (searchParams && 'redirect' in searchParams) delete searchParams.redirect
|
||||
|
||||
const redirectRoute = encodeURIComponent(
|
||||
@@ -36,7 +36,7 @@ export const handleAuthRedirect = ({
|
||||
const customLoginRoute =
|
||||
typeof redirectUnauthenticatedUser === 'string' ? redirectUnauthenticatedUser : undefined
|
||||
|
||||
const loginRoute = isAdminRoute(route, adminRoute)
|
||||
const loginRoute = isAdminRoute({ adminRoute, config, route })
|
||||
? adminLoginRoute
|
||||
: customLoginRoute || loginRouteFromConfig
|
||||
|
||||
|
||||
@@ -11,16 +11,42 @@ const authRouteKeys: (keyof SanitizedConfig['admin']['routes'])[] = [
|
||||
'reset',
|
||||
]
|
||||
|
||||
export const isAdminRoute = (route: string, adminRoute: string) => {
|
||||
return route.startsWith(adminRoute)
|
||||
export const isAdminRoute = ({
|
||||
adminRoute,
|
||||
config,
|
||||
route,
|
||||
}: {
|
||||
adminRoute: string
|
||||
config: SanitizedConfig
|
||||
route: string
|
||||
}): boolean => {
|
||||
return route.startsWith(adminRoute) && !isAdminAuthRoute({ adminRoute, config, route })
|
||||
}
|
||||
|
||||
export const isAdminAuthRoute = (config: SanitizedConfig, route: string, adminRoute: string) => {
|
||||
export const isAdminAuthRoute = ({
|
||||
adminRoute,
|
||||
config,
|
||||
route,
|
||||
}: {
|
||||
adminRoute: string
|
||||
config: SanitizedConfig
|
||||
route: string
|
||||
}): boolean => {
|
||||
const authRoutes = config.admin?.routes
|
||||
? Object.entries(config.admin.routes)
|
||||
.filter(([key]) => authRouteKeys.includes(key as keyof SanitizedConfig['admin']['routes']))
|
||||
.map(([_, value]) => value)
|
||||
: []
|
||||
|
||||
return authRoutes.some((r) => route.replace(adminRoute, '').startsWith(r))
|
||||
return authRoutes.some((r) => getRouteWithoutAdmin({ adminRoute, route }).startsWith(r))
|
||||
}
|
||||
|
||||
export const getRouteWithoutAdmin = ({
|
||||
adminRoute,
|
||||
route,
|
||||
}: {
|
||||
adminRoute: string
|
||||
route: string
|
||||
}): string => {
|
||||
return adminRoute && adminRoute !== '/' ? route.replace(adminRoute, '') : route
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ import {
|
||||
EmailField,
|
||||
PasswordField,
|
||||
TextField,
|
||||
useAuth,
|
||||
useConfig,
|
||||
useDocumentInfo,
|
||||
useFormFields,
|
||||
useFormModified,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import type { Props } from './types.js'
|
||||
@@ -38,6 +39,7 @@ export const Auth: React.FC<Props> = (props) => {
|
||||
verify,
|
||||
} = props
|
||||
|
||||
const { permissions } = useAuth()
|
||||
const [changingPassword, setChangingPassword] = useState(requirePassword)
|
||||
const enableAPIKey = useFormFields(([fields]) => (fields && fields?.enableAPIKey) || null)
|
||||
const dispatchFields = useFormFields((reducer) => reducer[1])
|
||||
@@ -50,6 +52,23 @@ export const Auth: React.FC<Props> = (props) => {
|
||||
serverURL,
|
||||
} = useConfig()
|
||||
|
||||
const hasPermissionToUnlock: boolean = useMemo(() => {
|
||||
const collection = permissions?.collections?.[collectionSlug]
|
||||
|
||||
if (collection) {
|
||||
const unlock = 'unlock' in collection ? collection.unlock : undefined
|
||||
|
||||
if (unlock) {
|
||||
// current types for permissions do not include auth permissions, this will be fixed in another branch soon, for now we need to ignore the types
|
||||
// @todo: fix types
|
||||
// @ts-expect-error
|
||||
return unlock.permission
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}, [permissions, collectionSlug])
|
||||
|
||||
const handleChangePassword = useCallback(
|
||||
(state: boolean) => {
|
||||
if (!state) {
|
||||
@@ -153,11 +172,11 @@ export const Auth: React.FC<Props> = (props) => {
|
||||
{t('authentication:changePassword')}
|
||||
</Button>
|
||||
)}
|
||||
{operation === 'update' && (
|
||||
{operation === 'update' && hasPermissionToUnlock && (
|
||||
<Button
|
||||
buttonStyle="secondary"
|
||||
disabled={disabled}
|
||||
onClick={() => unlock()}
|
||||
onClick={() => void unlock()}
|
||||
size="small"
|
||||
>
|
||||
{t('authentication:forceUnlock')}
|
||||
|
||||
@@ -81,6 +81,8 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
|
||||
const canUpdate = docPermissions?.update?.permission
|
||||
|
||||
const localeValues = locales.map((locale) => locale.value)
|
||||
|
||||
return (
|
||||
<main className={baseClass}>
|
||||
<SetViewActions actions={componentMap?.actionsMap?.Edit?.Version} />
|
||||
@@ -136,11 +138,7 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
fieldMap={fieldMap}
|
||||
fieldPermissions={docPermissions?.fields}
|
||||
i18n={i18n}
|
||||
locales={
|
||||
locales
|
||||
? locales.map(({ label }) => (typeof label === 'string' ? label : undefined))
|
||||
: []
|
||||
}
|
||||
locales={localeValues}
|
||||
version={
|
||||
globalConfig
|
||||
? {
|
||||
|
||||
@@ -99,9 +99,8 @@ export const VersionView: EditViewComponent = async (props) => {
|
||||
|
||||
const localeOptions: OptionObject[] =
|
||||
localization &&
|
||||
localization?.locales &&
|
||||
localization.locales.map(({ code, label }) => ({
|
||||
label: typeof label === 'string' ? label : '',
|
||||
label,
|
||||
value: code,
|
||||
}))
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { AllOperations, PayloadRequest } from '../types/index.js'
|
||||
import type { Permissions } from './types.js'
|
||||
|
||||
import { getEntityPolicies } from '../utilities/getEntityPolicies.js'
|
||||
import isolateObjectProperty from '../utilities/isolateObjectProperty.js'
|
||||
|
||||
type GetAccessResultsArgs = {
|
||||
req: PayloadRequest
|
||||
@@ -45,9 +44,7 @@ export async function getAccessResults({ req }: GetAccessResultsArgs): Promise<P
|
||||
type: 'collection',
|
||||
entity: collection,
|
||||
operations: collectionOperations,
|
||||
// Do not re-use our existing req object, as we need a new req.transactionID. Cannot re-use our existing one, as this is run in parallel (Promise.all above) which is
|
||||
// not supported on the same transaction ID. Not passing a transaction ID here creates a new transaction ID.
|
||||
req: isolateObjectProperty(req, 'transactionID'),
|
||||
req,
|
||||
})
|
||||
results.collections = {
|
||||
...results.collections,
|
||||
@@ -68,9 +65,7 @@ export async function getAccessResults({ req }: GetAccessResultsArgs): Promise<P
|
||||
type: 'global',
|
||||
entity: global,
|
||||
operations: globalOperations,
|
||||
// Do not re-use our existing req object, as we need a new req.transactionID. Cannot re-use our existing one, as this is run in parallel (Promise.all above) which is
|
||||
// not supported on the same transaction ID. Not passing a transaction ID here creates a new transaction ID.
|
||||
req: isolateObjectProperty(req, 'transactionID'),
|
||||
req,
|
||||
})
|
||||
results.globals = {
|
||||
...results.globals,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
import type { Permissions } from '../types.js'
|
||||
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import { adminInit as adminInitTelemetry } from '../../utilities/telemetry/events/adminInit.js'
|
||||
import { getAccessResults } from '../getAccessResults.js'
|
||||
@@ -17,10 +15,7 @@ export const accessOperation = async (args: Arguments): Promise<Permissions> =>
|
||||
adminInitTelemetry(req)
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
const results = getAccessResults({ req })
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
return results
|
||||
return getAccessResults({ req })
|
||||
} catch (e: unknown) {
|
||||
await killTransaction(req)
|
||||
throw e
|
||||
|
||||
@@ -6,8 +6,6 @@ import type { Collection } from '../config/types.js'
|
||||
import executeAccess from '../../auth/executeAccess.js'
|
||||
import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { validateQueryPaths } from '../../database/queryValidation/validateQueryPaths.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import { buildAfterOperation } from './utils.js'
|
||||
|
||||
@@ -25,8 +23,6 @@ export const countOperation = async <TSlug extends CollectionSlug>(
|
||||
let args = incomingArgs
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(args.req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeOperation - Collection
|
||||
// /////////////////////////////////////
|
||||
@@ -102,8 +98,6 @@ export const countOperation = async <TSlug extends CollectionSlug>(
|
||||
// Return results
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(args.req)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import type { AccessResult } from '../../config/types.js'
|
||||
import type { CollectionSlug, GeneratedTypes } from '../../index.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest, Where } from '../../types/index.js'
|
||||
import type { BeforeOperationHook, Collection, DataFromCollectionSlug } from '../config/types.js'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionSlug, JsonObject, TypeWithID } from '../../index.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
import type { BeforeOperationHook, Collection, DataFromCollectionSlug } from '../config/types.js'
|
||||
|
||||
|
||||
@@ -2,9 +2,7 @@ import type { CollectionPermission } from '../../auth/index.js'
|
||||
import type { AllOperations, PayloadRequest } from '../../types/index.js'
|
||||
import type { Collection } from '../config/types.js'
|
||||
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { getEntityPolicies } from '../../utilities/getEntityPolicies.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
|
||||
const allOperations: AllOperations[] = ['create', 'read', 'update', 'delete']
|
||||
@@ -37,8 +35,6 @@ export async function docAccessOperation(args: Arguments): Promise<CollectionPer
|
||||
}
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
const result = await getEntityPolicies({
|
||||
id,
|
||||
type: 'collection',
|
||||
@@ -47,8 +43,6 @@ export async function docAccessOperation(args: Arguments): Promise<CollectionPer
|
||||
req,
|
||||
})
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (e: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -8,8 +8,6 @@ import executeAccess from '../../auth/executeAccess.js'
|
||||
import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { validateQueryPaths } from '../../database/queryValidation/validateQueryPaths.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields.js'
|
||||
import { appendVersionToQueryKey } from '../../versions/drafts/appendVersionToQueryKey.js'
|
||||
@@ -38,8 +36,6 @@ export const findOperation = async <TSlug extends CollectionSlug>(
|
||||
let args = incomingArgs
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(args.req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeOperation - Collection
|
||||
// /////////////////////////////////////
|
||||
@@ -253,8 +249,6 @@ export const findOperation = async <TSlug extends CollectionSlug>(
|
||||
// Return results
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(args.req)
|
||||
|
||||
@@ -7,8 +7,6 @@ import executeAccess from '../../auth/executeAccess.js'
|
||||
import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { NotFound } from '../../errors/index.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import replaceWithDraftIfAvailable from '../../versions/drafts/replaceWithDraftIfAvailable.js'
|
||||
import { buildAfterOperation } from './utils.js'
|
||||
@@ -31,8 +29,6 @@ export const findByIDOperation = async <TSlug extends CollectionSlug>(
|
||||
let args = incomingArgs
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(args.req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeOperation - Collection
|
||||
// /////////////////////////////////////
|
||||
@@ -182,8 +178,6 @@ export const findByIDOperation = async <TSlug extends CollectionSlug>(
|
||||
// Return results
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(args.req)
|
||||
|
||||
@@ -8,8 +8,6 @@ import executeAccess from '../../auth/executeAccess.js'
|
||||
import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { APIError, Forbidden, NotFound } from '../../errors/index.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
|
||||
export type Arguments = {
|
||||
@@ -43,8 +41,6 @@ export const findVersionByIDOperation = async <TData extends TypeWithID = any>(
|
||||
}
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Access
|
||||
// /////////////////////////////////////
|
||||
@@ -141,8 +137,6 @@ export const findVersionByIDOperation = async <TData extends TypeWithID = any>(
|
||||
// Return results
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -7,8 +7,6 @@ import executeAccess from '../../auth/executeAccess.js'
|
||||
import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { validateQueryPaths } from '../../database/queryValidation/validateQueryPaths.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields.js'
|
||||
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields.js'
|
||||
@@ -44,8 +42,6 @@ export const findVersionsOperation = async <TData extends TypeWithVersion<TData>
|
||||
} = args
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Access
|
||||
// /////////////////////////////////////
|
||||
@@ -175,8 +171,6 @@ export const findVersionsOperation = async <TData extends TypeWithVersion<TData>
|
||||
docs: result.docs.map((doc) => sanitizeInternalFields<TData>(doc)),
|
||||
}
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -10,8 +10,6 @@ import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { APIError, Forbidden, NotFound } from '../../errors/index.js'
|
||||
import { afterChange } from '../../fields/hooks/afterChange/index.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import { getLatestCollectionVersion } from '../../versions/getLatestCollectionVersion.js'
|
||||
|
||||
@@ -40,8 +38,6 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
} = args
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
if (!id) {
|
||||
throw new APIError('Missing ID of version to restore.', httpStatus.BAD_REQUEST)
|
||||
}
|
||||
@@ -200,8 +196,6 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
})) || result
|
||||
}, Promise.resolve())
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { DeepPartial } from 'ts-essentials'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import type { FindOneArgs } from '../../database/types.js'
|
||||
import type { CollectionSlug, GeneratedTypes } from '../../index.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
import type {
|
||||
Collection,
|
||||
|
||||
@@ -175,20 +175,22 @@ export type Labels = {
|
||||
singular: LabelFunction | LabelStatic
|
||||
}
|
||||
|
||||
export type BaseValidateOptions<TData, TSiblingData> = {
|
||||
export type BaseValidateOptions<TData, TSiblingData, TValue> = {
|
||||
data: Partial<TData>
|
||||
id?: number | string
|
||||
operation?: Operation
|
||||
preferences: DocumentPreferences
|
||||
previousValue?: TValue
|
||||
req: PayloadRequest
|
||||
siblingData: Partial<TSiblingData>
|
||||
}
|
||||
|
||||
export type ValidateOptions<TData, TSiblingData, TFieldConfig extends object> = BaseValidateOptions<
|
||||
export type ValidateOptions<
|
||||
TData,
|
||||
TSiblingData
|
||||
> &
|
||||
TFieldConfig
|
||||
TSiblingData,
|
||||
TFieldConfig extends object,
|
||||
TValue,
|
||||
> = BaseValidateOptions<TData, TSiblingData, TValue> & TFieldConfig
|
||||
|
||||
export type Validate<
|
||||
TValue = any,
|
||||
@@ -197,7 +199,7 @@ export type Validate<
|
||||
TFieldConfig extends object = object,
|
||||
> = (
|
||||
value: TValue,
|
||||
options: ValidateOptions<TData, TSiblingData, TFieldConfig>,
|
||||
options: ValidateOptions<TData, TSiblingData, TFieldConfig, TValue>,
|
||||
) => Promise<string | true> | string | true
|
||||
|
||||
export type ClientValidate = Omit<Validate, 'req'>
|
||||
@@ -266,11 +268,12 @@ export type NumberField = {
|
||||
/** Set a value for the number field to increment / decrement using browser controls. */
|
||||
step?: number
|
||||
} & Admin
|
||||
/** Maximum value accepted. Used in the default `validation` function. */
|
||||
/** Maximum value accepted. Used in the default `validate` function. */
|
||||
max?: number
|
||||
/** Minimum value accepted. Used in the default `validation` function. */
|
||||
/** Minimum value accepted. Used in the default `validate` function. */
|
||||
min?: number
|
||||
type: 'number'
|
||||
validate?: Validate<number | number[], unknown, unknown, NumberField>
|
||||
} & (
|
||||
| {
|
||||
/** Makes this field an ordered array of numbers instead of just a single number. */
|
||||
@@ -306,6 +309,7 @@ export type TextField = {
|
||||
maxLength?: number
|
||||
minLength?: number
|
||||
type: 'text'
|
||||
validate?: Validate<string | string[], unknown, unknown, TextField>
|
||||
} & (
|
||||
| {
|
||||
/** Makes this field an ordered array of strings instead of just a single string. */
|
||||
@@ -338,6 +342,7 @@ export type EmailField = {
|
||||
placeholder?: Record<string, string> | string
|
||||
} & Admin
|
||||
type: 'email'
|
||||
validate?: Validate<string, unknown, unknown, EmailField>
|
||||
} & FieldBase
|
||||
|
||||
export type TextareaField = {
|
||||
@@ -355,6 +360,7 @@ export type TextareaField = {
|
||||
maxLength?: number
|
||||
minLength?: number
|
||||
type: 'textarea'
|
||||
validate?: Validate<string, unknown, unknown, TextareaField>
|
||||
} & FieldBase
|
||||
|
||||
export type CheckboxField = {
|
||||
@@ -367,6 +373,7 @@ export type CheckboxField = {
|
||||
}
|
||||
} & Admin
|
||||
type: 'checkbox'
|
||||
validate?: Validate<unknown, unknown, unknown, CheckboxField>
|
||||
} & FieldBase
|
||||
|
||||
export type DateField = {
|
||||
@@ -381,6 +388,7 @@ export type DateField = {
|
||||
placeholder?: Record<string, string> | string
|
||||
} & Admin
|
||||
type: 'date'
|
||||
validate?: Validate<unknown, unknown, unknown, DateField>
|
||||
} & FieldBase
|
||||
|
||||
export type GroupField = {
|
||||
@@ -396,7 +404,8 @@ export type GroupField = {
|
||||
*/
|
||||
interfaceName?: string
|
||||
type: 'group'
|
||||
} & Omit<FieldBase, 'required' | 'validation'>
|
||||
validate?: Validate<unknown, unknown, unknown, GroupField>
|
||||
} & Omit<FieldBase, 'required'>
|
||||
|
||||
export type RowAdmin = Omit<Admin, 'description'>
|
||||
|
||||
@@ -404,7 +413,7 @@ export type RowField = {
|
||||
admin?: RowAdmin
|
||||
fields: Field[]
|
||||
type: 'row'
|
||||
} & Omit<FieldBase, 'admin' | 'label' | 'name'>
|
||||
} & Omit<FieldBase, 'admin' | 'label' | 'name' | 'validate'>
|
||||
|
||||
export type CollapsibleField = {
|
||||
fields: Field[]
|
||||
@@ -426,7 +435,7 @@ export type CollapsibleField = {
|
||||
label: Required<FieldBase['label']>
|
||||
}
|
||||
) &
|
||||
Omit<FieldBase, 'label' | 'name'>
|
||||
Omit<FieldBase, 'label' | 'name' | 'validate'>
|
||||
|
||||
export type TabsAdmin = Omit<Admin, 'description'>
|
||||
|
||||
@@ -435,7 +444,7 @@ type TabBase = {
|
||||
fields: Field[]
|
||||
interfaceName?: string
|
||||
saveToJWT?: boolean | string
|
||||
} & Omit<FieldBase, 'required' | 'validation'>
|
||||
} & Omit<FieldBase, 'required' | 'validate'>
|
||||
|
||||
export type NamedTab = {
|
||||
/** Customize generated GraphQL and Typescript schema names.
|
||||
@@ -521,6 +530,7 @@ export type UploadField = {
|
||||
maxDepth?: number
|
||||
relationTo: CollectionSlug
|
||||
type: 'upload'
|
||||
validate?: Validate<unknown, unknown, unknown, UploadField>
|
||||
} & FieldBase
|
||||
|
||||
type CodeAdmin = {
|
||||
@@ -537,6 +547,7 @@ export type CodeField = {
|
||||
maxLength?: number
|
||||
minLength?: number
|
||||
type: 'code'
|
||||
validate?: Validate<string, unknown, unknown, CodeField>
|
||||
} & Omit<FieldBase, 'admin'>
|
||||
|
||||
type JSONAdmin = {
|
||||
@@ -555,6 +566,7 @@ export type JSONField = {
|
||||
uri: string
|
||||
}
|
||||
type: 'json'
|
||||
validate?: Validate<Record<string, unknown>, unknown, unknown, JSONField>
|
||||
} & Omit<FieldBase, 'admin'>
|
||||
|
||||
export type SelectField = {
|
||||
@@ -577,6 +589,7 @@ export type SelectField = {
|
||||
hasMany?: boolean
|
||||
options: Option[]
|
||||
type: 'select'
|
||||
validate?: Validate<string, unknown, unknown, SelectField>
|
||||
} & FieldBase
|
||||
|
||||
type SharedRelationshipProperties = {
|
||||
@@ -589,6 +602,7 @@ type SharedRelationshipProperties = {
|
||||
*/
|
||||
maxDepth?: number
|
||||
type: 'relationship'
|
||||
validate?: Validate<unknown, unknown, unknown, SharedRelationshipProperties>
|
||||
} & (
|
||||
| {
|
||||
hasMany: true
|
||||
@@ -627,12 +641,14 @@ type RelationshipAdmin = {
|
||||
}
|
||||
isSortable?: boolean
|
||||
} & Admin
|
||||
|
||||
export type PolymorphicRelationshipField = {
|
||||
admin?: {
|
||||
sortOptions?: { [collectionSlug: CollectionSlug]: string }
|
||||
} & RelationshipAdmin
|
||||
relationTo: CollectionSlug[]
|
||||
} & SharedRelationshipProperties
|
||||
|
||||
export type SingleRelationshipField = {
|
||||
admin?: {
|
||||
sortOptions?: string
|
||||
@@ -707,6 +723,7 @@ export type ArrayField = {
|
||||
maxRows?: number
|
||||
minRows?: number
|
||||
type: 'array'
|
||||
validate?: Validate<unknown[], unknown, unknown, ArrayField>
|
||||
} & FieldBase
|
||||
|
||||
export type RadioField = {
|
||||
@@ -727,6 +744,7 @@ export type RadioField = {
|
||||
enumName?: DBIdentifierName
|
||||
options: Option[]
|
||||
type: 'radio'
|
||||
validate?: Validate<string, unknown, unknown, RadioField>
|
||||
} & FieldBase
|
||||
|
||||
export type Block = {
|
||||
@@ -781,10 +799,12 @@ export type BlockField = {
|
||||
maxRows?: number
|
||||
minRows?: number
|
||||
type: 'blocks'
|
||||
validate?: Validate<string, unknown, unknown, BlockField>
|
||||
} & FieldBase
|
||||
|
||||
export type PointField = {
|
||||
type: 'point'
|
||||
validate?: Validate<unknown, unknown, unknown, PointField>
|
||||
} & FieldBase
|
||||
|
||||
export type Field =
|
||||
|
||||
@@ -121,7 +121,7 @@ export const promise = async ({
|
||||
}
|
||||
|
||||
// Validate
|
||||
if (!skipValidationFromHere && field.validate) {
|
||||
if (!skipValidationFromHere && 'validate' in field && field.validate) {
|
||||
const valueToValidate = siblingData[field.name]
|
||||
let jsonError: object
|
||||
|
||||
@@ -140,9 +140,10 @@ export const promise = async ({
|
||||
jsonError,
|
||||
operation,
|
||||
preferences: { fields: {} },
|
||||
previousValue: siblingDoc[field.name],
|
||||
req,
|
||||
siblingData: deepMergeWithSourceArrays(siblingDoc, siblingData),
|
||||
} as ValidateOptions<any, any, { jsonError: object }>)
|
||||
} as ValidateOptions<any, any, { jsonError: object }, any>)
|
||||
|
||||
if (typeof validationResult === 'string') {
|
||||
errors.push({
|
||||
|
||||
@@ -33,6 +33,7 @@ type Args<T> = {
|
||||
* The original siblingData (not modified by any hooks)
|
||||
*/
|
||||
siblingDoc: JsonObject
|
||||
siblingDocKeys: Set<string>
|
||||
}
|
||||
|
||||
// This function is responsible for the following actions, in order:
|
||||
@@ -57,6 +58,7 @@ export const promise = async <T>({
|
||||
req,
|
||||
siblingData,
|
||||
siblingDoc,
|
||||
siblingDocKeys,
|
||||
}: Args<T>): Promise<void> => {
|
||||
const { path: fieldPath, schemaPath: fieldSchemaPath } = getFieldPaths({
|
||||
field,
|
||||
@@ -65,6 +67,15 @@ export const promise = async <T>({
|
||||
})
|
||||
|
||||
if (fieldAffectsData(field)) {
|
||||
// Remove the key from siblingDocKeys
|
||||
// the goal is to keep any existing data present
|
||||
// before updating, for users that want to maintain
|
||||
// external data in the same collections as Payload manages,
|
||||
// without having fields defined for them
|
||||
if (siblingDocKeys.has(field.name)) {
|
||||
siblingDocKeys.delete(field.name)
|
||||
}
|
||||
|
||||
if (field.name === 'id') {
|
||||
if (field.type === 'number' && typeof siblingData[field.name] === 'string') {
|
||||
const value = siblingData[field.name] as string
|
||||
@@ -308,6 +319,7 @@ export const promise = async <T>({
|
||||
schemaPath: fieldSchemaPath,
|
||||
siblingData: groupData as JsonObject,
|
||||
siblingDoc: groupDoc as JsonObject,
|
||||
siblingDocKeys,
|
||||
})
|
||||
|
||||
break
|
||||
@@ -335,6 +347,7 @@ export const promise = async <T>({
|
||||
schemaPath: fieldSchemaPath,
|
||||
siblingData: row as JsonObject,
|
||||
siblingDoc: getExistingRowDoc(row as JsonObject, siblingDoc[field.name]),
|
||||
siblingDocKeys,
|
||||
}),
|
||||
)
|
||||
})
|
||||
@@ -372,6 +385,7 @@ export const promise = async <T>({
|
||||
schemaPath: fieldSchemaPath,
|
||||
siblingData: row as JsonObject,
|
||||
siblingDoc: rowSiblingDoc,
|
||||
siblingDocKeys,
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -399,6 +413,7 @@ export const promise = async <T>({
|
||||
schemaPath: fieldSchemaPath,
|
||||
siblingData,
|
||||
siblingDoc,
|
||||
siblingDocKeys,
|
||||
})
|
||||
|
||||
break
|
||||
@@ -407,7 +422,10 @@ export const promise = async <T>({
|
||||
case 'tab': {
|
||||
let tabSiblingData
|
||||
let tabSiblingDoc
|
||||
if (tabHasName(field)) {
|
||||
|
||||
const isNamedTab = tabHasName(field)
|
||||
|
||||
if (isNamedTab) {
|
||||
if (typeof siblingData[field.name] !== 'object') siblingData[field.name] = {}
|
||||
if (typeof siblingDoc[field.name] !== 'object') siblingDoc[field.name] = {}
|
||||
|
||||
@@ -433,6 +451,7 @@ export const promise = async <T>({
|
||||
schemaPath: fieldSchemaPath,
|
||||
siblingData: tabSiblingData,
|
||||
siblingDoc: tabSiblingDoc,
|
||||
siblingDocKeys: isNamedTab ? undefined : siblingDocKeys,
|
||||
})
|
||||
|
||||
break
|
||||
@@ -454,6 +473,7 @@ export const promise = async <T>({
|
||||
schemaPath: fieldSchemaPath,
|
||||
siblingData,
|
||||
siblingDoc,
|
||||
siblingDocKeys,
|
||||
})
|
||||
|
||||
break
|
||||
|
||||
@@ -26,6 +26,7 @@ type Args<T> = {
|
||||
* The original siblingData (not modified by any hooks)
|
||||
*/
|
||||
siblingDoc: JsonObject
|
||||
siblingDocKeys?: Set<string>
|
||||
}
|
||||
|
||||
export const traverseFields = async <T>({
|
||||
@@ -43,8 +44,11 @@ export const traverseFields = async <T>({
|
||||
schemaPath,
|
||||
siblingData,
|
||||
siblingDoc,
|
||||
siblingDocKeys: incomingSiblingDocKeys,
|
||||
}: Args<T>): Promise<void> => {
|
||||
const promises = []
|
||||
const siblingDocKeys = incomingSiblingDocKeys || new Set(Object.keys(siblingDoc))
|
||||
|
||||
fields.forEach((field) => {
|
||||
promises.push(
|
||||
promise({
|
||||
@@ -62,8 +66,18 @@ export const traverseFields = async <T>({
|
||||
req,
|
||||
siblingData,
|
||||
siblingDoc,
|
||||
siblingDocKeys,
|
||||
}),
|
||||
)
|
||||
})
|
||||
await Promise.all(promises)
|
||||
|
||||
// For any siblingDocKeys that have not been deleted,
|
||||
// we will move the data to the siblingData object
|
||||
// to preserve it
|
||||
siblingDocKeys.forEach((key) => {
|
||||
if (!['createdAt', 'globalType', 'id', 'updatedAt'].includes(key)) {
|
||||
siblingData[key] = siblingDoc[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import type { SanitizedGlobalConfig } from '../config/types.js'
|
||||
|
||||
import executeAccess from '../../auth/executeAccess.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import replaceWithDraftIfAvailable from '../../versions/drafts/replaceWithDraftIfAvailable.js'
|
||||
|
||||
@@ -34,8 +32,6 @@ export const findOneOperation = async <T extends Record<string, unknown>>(
|
||||
} = args
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Retrieve and execute access
|
||||
// /////////////////////////////////////
|
||||
@@ -129,12 +125,6 @@ export const findOneOperation = async <T extends Record<string, unknown>>(
|
||||
// Return results
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Return results
|
||||
// /////////////////////////////////////
|
||||
|
||||
return doc
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -7,9 +7,7 @@ import executeAccess from '../../auth/executeAccess.js'
|
||||
import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { Forbidden, NotFound } from '../../errors/index.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { deepCopyObjectSimple } from '../../utilities/deepCopyObject.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
|
||||
export type Arguments = {
|
||||
@@ -39,8 +37,6 @@ export const findVersionByIDOperation = async <T extends TypeWithVersion<T> = an
|
||||
} = args
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Access
|
||||
// /////////////////////////////////////
|
||||
@@ -136,12 +132,6 @@ export const findVersionByIDOperation = async <T extends TypeWithVersion<T> = an
|
||||
})) || result.version
|
||||
}, Promise.resolve())
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Return results
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -7,8 +7,6 @@ import executeAccess from '../../auth/executeAccess.js'
|
||||
import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { validateQueryPaths } from '../../database/queryValidation/validateQueryPaths.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields.js'
|
||||
import { buildVersionGlobalFields } from '../../versions/buildGlobalFields.js'
|
||||
@@ -44,8 +42,6 @@ export const findVersionsOperation = async <T extends TypeWithVersion<T>>(
|
||||
const versionFields = buildVersionGlobalFields(globalConfig)
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Access
|
||||
// /////////////////////////////////////
|
||||
@@ -147,8 +143,6 @@ export const findVersionsOperation = async <T extends TypeWithVersion<T>>(
|
||||
docs: result.docs.map((doc) => sanitizeInternalFields<T>(doc)),
|
||||
}
|
||||
|
||||
if (shouldCommit) await commitTransaction(req)
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -6,7 +6,11 @@ import type { PayloadRequest } from '../types/index.js'
|
||||
export async function killTransaction(req: PayloadRequest): Promise<void> {
|
||||
const { payload, transactionID } = req
|
||||
if (transactionID && !(transactionID instanceof Promise)) {
|
||||
await payload.db.rollbackTransaction(req.transactionID)
|
||||
try {
|
||||
await payload.db.rollbackTransaction(req.transactionID)
|
||||
} catch (error) {
|
||||
// swallow any errors while attempting to rollback
|
||||
}
|
||||
delete req.transactionID
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,9 @@ export const syncWithSearch: SyncWithSearch = async (args) => {
|
||||
'doc.value': {
|
||||
equals: id,
|
||||
},
|
||||
'doc.relationTo': {
|
||||
equals: collection,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ export type NodeValidation<T extends SerializedLexicalNode = SerializedLexicalNo
|
||||
node: T
|
||||
nodeValidations: Map<string, Array<NodeValidation>>
|
||||
validation: {
|
||||
options: ValidateOptions<unknown, unknown, RichTextField>
|
||||
options: ValidateOptions<unknown, unknown, RichTextField, SerializedEditorState>
|
||||
value: SerializedEditorState
|
||||
}
|
||||
}) => Promise<string | true> | string | true
|
||||
|
||||
@@ -11,7 +11,7 @@ export async function validateNodes({
|
||||
nodeValidations: Map<string, Array<NodeValidation>>
|
||||
nodes: SerializedLexicalNode[]
|
||||
validation: {
|
||||
options: ValidateOptions<unknown, unknown, RichTextField>
|
||||
options: ValidateOptions<unknown, unknown, RichTextField, SerializedEditorState>
|
||||
value: SerializedEditorState
|
||||
}
|
||||
}): Promise<string | true> {
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"dotenv": "16.4.5",
|
||||
"prettier": "3.3.2",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
"exports": {
|
||||
|
||||
@@ -37,8 +37,8 @@ export const SortColumn: React.FC<SortColumnProps> = (props) => {
|
||||
if (sort === desc) descClasses.push(`${baseClass}--active`)
|
||||
|
||||
const setSort = useCallback(
|
||||
(newSort) => {
|
||||
refineListData({
|
||||
async (newSort: string) => {
|
||||
await refineListData({
|
||||
sort: newSort,
|
||||
})
|
||||
},
|
||||
@@ -56,7 +56,7 @@ export const SortColumn: React.FC<SortColumnProps> = (props) => {
|
||||
label,
|
||||
})}
|
||||
className={[...ascClasses, `${baseClass}__button`].filter(Boolean).join(' ')}
|
||||
onClick={() => setSort(asc)}
|
||||
onClick={() => void setSort(asc)}
|
||||
type="button"
|
||||
>
|
||||
<ChevronIcon direction="up" />
|
||||
@@ -67,7 +67,7 @@ export const SortColumn: React.FC<SortColumnProps> = (props) => {
|
||||
label,
|
||||
})}
|
||||
className={[...descClasses, `${baseClass}__button`].filter(Boolean).join(' ')}
|
||||
onClick={() => setSort(desc)}
|
||||
onClick={() => void setSort(desc)}
|
||||
type="button"
|
||||
>
|
||||
<ChevronIcon />
|
||||
|
||||
@@ -143,8 +143,11 @@ export const WhereBuilder: React.FC<WhereBuilderProps> = (props) => {
|
||||
|
||||
React.useEffect(() => {
|
||||
if (shouldUpdateQuery) {
|
||||
handleWhereChange({ or: conditions })
|
||||
setShouldUpdateQuery(false)
|
||||
async function handleChange() {
|
||||
await handleWhereChange({ or: conditions })
|
||||
setShouldUpdateQuery(false)
|
||||
}
|
||||
void handleChange()
|
||||
}
|
||||
}, [conditions, handleWhereChange, shouldUpdateQuery])
|
||||
|
||||
|
||||
@@ -13,12 +13,19 @@ import { useSearchParams } from '../SearchParams/index.js'
|
||||
|
||||
export type ColumnPreferences = Pick<Column, 'accessor' | 'active'>[]
|
||||
|
||||
type Handlers = {
|
||||
handlePageChange?: (page: number) => void
|
||||
handlePerPageChange?: (limit: number) => void
|
||||
handleSearchChange?: (search: string) => void
|
||||
handleSortChange?: (sort: string) => void
|
||||
handleWhereChange?: (where: Where) => void
|
||||
type PropHandlers = {
|
||||
handlePageChange?: (page: number) => Promise<void> | void
|
||||
handlePerPageChange?: (limit: number) => Promise<void> | void
|
||||
handleSearchChange?: (search: string) => Promise<void> | void
|
||||
handleSortChange?: (sort: string) => Promise<void> | void
|
||||
handleWhereChange?: (where: Where) => Promise<void> | void
|
||||
}
|
||||
type ContextHandlers = {
|
||||
handlePageChange?: (page: number) => Promise<void>
|
||||
handlePerPageChange?: (limit: number) => Promise<void>
|
||||
handleSearchChange?: (search: string) => Promise<void>
|
||||
handleSortChange?: (sort: string) => Promise<void>
|
||||
handleWhereChange?: (where: Where) => Promise<void>
|
||||
}
|
||||
|
||||
export type ListQueryProps = {
|
||||
@@ -28,14 +35,14 @@ export type ListQueryProps = {
|
||||
defaultSort?: string
|
||||
modifySearchParams?: boolean
|
||||
preferenceKey?: string
|
||||
} & Handlers
|
||||
} & PropHandlers
|
||||
|
||||
export type ListQueryContext = {
|
||||
data: PaginatedDocs
|
||||
defaultLimit?: number
|
||||
defaultSort?: string
|
||||
refineListData: (args: RefineOverrides) => void
|
||||
} & Handlers
|
||||
refineListData: (args: RefineOverrides) => Promise<void>
|
||||
} & ContextHandlers
|
||||
|
||||
const Context = createContext({} as ListQueryContext)
|
||||
|
||||
@@ -71,6 +78,9 @@ export const ListQueryProvider: React.FC<ListQueryProps> = ({
|
||||
async (query: RefineOverrides) => {
|
||||
if (!modifySearchParams) return
|
||||
|
||||
let pageQuery = 'page' in query ? query.page : currentQuery?.page
|
||||
if ('where' in query || 'search' in query) pageQuery = '1'
|
||||
|
||||
const updatedPreferences: Record<string, unknown> = {}
|
||||
let updatePreferences = false
|
||||
|
||||
@@ -88,7 +98,7 @@ export const ListQueryProvider: React.FC<ListQueryProps> = ({
|
||||
|
||||
const params = {
|
||||
limit: 'limit' in query ? query.limit : currentQuery?.limit,
|
||||
page: 'page' in query ? query.page : currentQuery?.page,
|
||||
page: pageQuery,
|
||||
search: 'search' in query ? query.search : currentQuery?.search,
|
||||
sort: 'sort' in query ? query.sort : currentQuery?.sort,
|
||||
where: 'where' in query ? query.where : currentQuery?.where,
|
||||
@@ -102,7 +112,7 @@ export const ListQueryProvider: React.FC<ListQueryProps> = ({
|
||||
const handlePageChange = React.useCallback(
|
||||
async (arg: number) => {
|
||||
if (typeof handlePageChangeFromProps === 'function') {
|
||||
handlePageChangeFromProps(arg)
|
||||
await handlePageChangeFromProps(arg)
|
||||
}
|
||||
await refineListData({ page: String(arg) })
|
||||
},
|
||||
@@ -111,7 +121,7 @@ export const ListQueryProvider: React.FC<ListQueryProps> = ({
|
||||
const handlePerPageChange = React.useCallback(
|
||||
async (arg: number) => {
|
||||
if (typeof handlePerPageChangeFromProps === 'function') {
|
||||
handlePerPageChangeFromProps(arg)
|
||||
await handlePerPageChangeFromProps(arg)
|
||||
}
|
||||
await refineListData({ limit: String(arg) })
|
||||
},
|
||||
@@ -120,7 +130,7 @@ export const ListQueryProvider: React.FC<ListQueryProps> = ({
|
||||
const handleSearchChange = React.useCallback(
|
||||
async (arg: string) => {
|
||||
if (typeof handleSearchChangeFromProps === 'function') {
|
||||
handleSearchChangeFromProps(arg)
|
||||
await handleSearchChangeFromProps(arg)
|
||||
}
|
||||
await refineListData({ search: arg })
|
||||
},
|
||||
@@ -129,7 +139,7 @@ export const ListQueryProvider: React.FC<ListQueryProps> = ({
|
||||
const handleSortChange = React.useCallback(
|
||||
async (arg: string) => {
|
||||
if (typeof handleSortChangeFromProps === 'function') {
|
||||
handleSortChangeFromProps(arg)
|
||||
await handleSortChangeFromProps(arg)
|
||||
}
|
||||
await refineListData({ sort: arg })
|
||||
},
|
||||
@@ -138,7 +148,7 @@ export const ListQueryProvider: React.FC<ListQueryProps> = ({
|
||||
const handleWhereChange = React.useCallback(
|
||||
async (arg: Where) => {
|
||||
if (typeof handleWhereChangeFromProps === 'function') {
|
||||
handleWhereChangeFromProps(arg)
|
||||
await handleWhereChangeFromProps(arg)
|
||||
}
|
||||
await refineListData({ where: arg })
|
||||
},
|
||||
|
||||
520
pnpm-lock.yaml
generated
520
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,7 @@
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.0-canary.53",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.0-canary.53",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.0-canary.53",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"eslint-config-next": "15.0.0-canary.53",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.0.3",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
198
templates/website/pnpm-lock.yaml
generated
198
templates/website/pnpm-lock.yaml
generated
@@ -17,7 +17,7 @@ dependencies:
|
||||
version: 3.0.0-beta.67(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
'@payloadcms/next':
|
||||
specifier: 3.0.0-beta.67
|
||||
version: 3.0.0-beta.67(graphql@16.9.0)(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)(typescript@5.5.3)
|
||||
version: 3.0.0-beta.67(graphql@16.9.0)(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)(typescript@5.5.4)
|
||||
'@payloadcms/plugin-cloud':
|
||||
specifier: 3.0.0-beta.67
|
||||
version: 3.0.0-beta.67(@aws-sdk/client-sso-oidc@3.614.0)(payload@3.0.0-beta.67)
|
||||
@@ -80,7 +80,7 @@ dependencies:
|
||||
version: 15.0.0-canary.58(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
payload:
|
||||
specifier: 3.0.0-beta.67
|
||||
version: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
version: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
payload-admin-bar:
|
||||
specifier: ^1.0.6
|
||||
version: 1.0.6(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
@@ -112,7 +112,7 @@ devDependencies:
|
||||
version: 13.5.6
|
||||
'@payloadcms/eslint-config':
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1(typescript@5.5.3)
|
||||
version: 1.1.1(typescript@5.5.4)
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.13
|
||||
version: 0.5.13(tailwindcss@3.4.4)
|
||||
@@ -139,7 +139,7 @@ devDependencies:
|
||||
version: 8.57.0
|
||||
eslint-config-next:
|
||||
specifier: 15.0.0-canary.58
|
||||
version: 15.0.0-canary.58(eslint@8.57.0)(typescript@5.5.3)
|
||||
version: 15.0.0-canary.58(eslint@8.57.0)(typescript@5.5.4)
|
||||
postcss:
|
||||
specifier: ^8.4.38
|
||||
version: 8.4.39
|
||||
@@ -150,8 +150,8 @@ devDependencies:
|
||||
specifier: ^3.4.3
|
||||
version: 3.4.4
|
||||
typescript:
|
||||
specifier: 5.5.3
|
||||
version: 5.5.3
|
||||
specifier: 5.5.4
|
||||
version: 5.5.4
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1947,7 +1947,7 @@ packages:
|
||||
http-status: 1.6.2
|
||||
mongoose: 6.12.3(@aws-sdk/client-sso-oidc@3.614.0)
|
||||
mongoose-paginate-v2: 1.7.22
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
prompts: 2.4.2
|
||||
uuid: 10.0.0
|
||||
transitivePeerDependencies:
|
||||
@@ -1963,23 +1963,23 @@ packages:
|
||||
payload: 3.0.0-beta.67
|
||||
dependencies:
|
||||
nodemailer: 6.9.10
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
dev: false
|
||||
|
||||
/@payloadcms/eslint-config@1.1.1(typescript@5.5.3):
|
||||
/@payloadcms/eslint-config@1.1.1(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-LSf9oEPb6aMEMqdTFqj1v+7p/bdrJWG6hp7748xjVO3RL3yQESTKLK/NbjsMYITN4tKFXjfPWDUtcwHv0hS6/A==}
|
||||
dependencies:
|
||||
'@types/eslint': 8.44.2
|
||||
'@typescript-eslint/eslint-plugin': 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/eslint-plugin': 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
eslint: 8.48.0
|
||||
eslint-config-prettier: 9.0.0(eslint@8.48.0)
|
||||
eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)
|
||||
eslint-plugin-jest: 27.2.3(@typescript-eslint/eslint-plugin@6.6.0)(eslint@8.48.0)(typescript@5.5.3)
|
||||
eslint-plugin-jest: 27.2.3(@typescript-eslint/eslint-plugin@6.6.0)(eslint@8.48.0)(typescript@5.5.4)
|
||||
eslint-plugin-jest-dom: 5.1.0(eslint@8.48.0)
|
||||
eslint-plugin-jsx-a11y: 6.7.1(eslint@8.48.0)
|
||||
eslint-plugin-node: 11.1.0(eslint@8.48.0)
|
||||
eslint-plugin-perfectionist: 2.0.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
eslint-plugin-perfectionist: 2.0.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
eslint-plugin-playwright: 0.16.0(eslint-plugin-jest@27.2.3)(eslint@8.48.0)
|
||||
eslint-plugin-react: 7.33.2(eslint@8.48.0)
|
||||
eslint-plugin-react-hooks: 4.6.0(eslint@8.48.0)
|
||||
@@ -1997,7 +1997,7 @@ packages:
|
||||
- vue-eslint-parser
|
||||
dev: true
|
||||
|
||||
/@payloadcms/graphql@3.0.0-beta.67(graphql@16.9.0)(payload@3.0.0-beta.67)(typescript@5.5.3):
|
||||
/@payloadcms/graphql@3.0.0-beta.67(graphql@16.9.0)(payload@3.0.0-beta.67)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-gvLd16Ndi2gLCA+Nt3RbkUJH2YdirloeHUzfvldTH7teeslsgYxxzAHopsKiHrQBB565+Q7aWBI2vrS01XF7SA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -2006,9 +2006,9 @@ packages:
|
||||
dependencies:
|
||||
graphql: 16.9.0
|
||||
graphql-scalars: 1.22.2(graphql@16.9.0)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
pluralize: 8.0.0
|
||||
ts-essentials: 7.0.3(typescript@5.5.3)
|
||||
ts-essentials: 7.0.3(typescript@5.5.4)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
dev: false
|
||||
@@ -2028,7 +2028,7 @@ packages:
|
||||
resolution: {integrity: sha512-fq/ntibiaP7kRAIuHgSoOSm/+3DD3MHQStlppPzRLyD3kvmizKtH71ngBZRx9wyg2aH2lqkTLDWLswyHp8KHzQ==}
|
||||
dev: false
|
||||
|
||||
/@payloadcms/next@3.0.0-beta.67(graphql@16.9.0)(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)(typescript@5.5.3):
|
||||
/@payloadcms/next@3.0.0-beta.67(graphql@16.9.0)(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-rmR8hX+W6ZNsFD7QxUXoV/6Yq71oDNZVy0GX4PHBXvw/C2EPeTRCuopBsRFPp8PyvooLt7l3WUskIEmfkMdnGw==}
|
||||
engines: {node: ^18.20.2 || >=20.9.0}
|
||||
peerDependencies:
|
||||
@@ -2037,7 +2037,7 @@ packages:
|
||||
payload: 3.0.0-beta.67
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
'@payloadcms/graphql': 3.0.0-beta.67(graphql@16.9.0)(payload@3.0.0-beta.67)(typescript@5.5.3)
|
||||
'@payloadcms/graphql': 3.0.0-beta.67(graphql@16.9.0)(payload@3.0.0-beta.67)(typescript@5.5.4)
|
||||
'@payloadcms/translations': 3.0.0-beta.67
|
||||
'@payloadcms/ui': 3.0.0-beta.67(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)
|
||||
busboy: 1.6.0
|
||||
@@ -2048,7 +2048,7 @@ packages:
|
||||
http-status: 1.6.2
|
||||
next: 15.0.0-canary.58(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
path-to-regexp: 6.2.2
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
qs-esm: 7.0.2
|
||||
react-diff-viewer-continued: 3.2.6(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
sass: 1.77.4
|
||||
@@ -2078,7 +2078,7 @@ packages:
|
||||
'@payloadcms/email-nodemailer': 3.0.0-beta.67(payload@3.0.0-beta.67)
|
||||
amazon-cognito-identity-js: 6.3.12
|
||||
nodemailer: 6.9.10
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
resend: 0.17.2
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/client-sso-oidc'
|
||||
@@ -2097,7 +2097,7 @@ packages:
|
||||
'@payloadcms/ui': 3.0.0-beta.67(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)
|
||||
deepmerge: 4.3.1
|
||||
escape-html: 1.0.3
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
react: 19.0.0-rc-6230622a1a-20240610
|
||||
react-dom: 19.0.0-rc-6230622a1a-20240610(react@19.0.0-rc-6230622a1a-20240610)
|
||||
transitivePeerDependencies:
|
||||
@@ -2112,7 +2112,7 @@ packages:
|
||||
peerDependencies:
|
||||
payload: 3.0.0-beta.67
|
||||
dependencies:
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
dev: false
|
||||
|
||||
/@payloadcms/plugin-redirects@3.0.0-beta.67(payload@3.0.0-beta.67):
|
||||
@@ -2120,7 +2120,7 @@ packages:
|
||||
peerDependencies:
|
||||
payload: 3.0.0-beta.67
|
||||
dependencies:
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
dev: false
|
||||
|
||||
/@payloadcms/plugin-seo@3.0.0-beta.67(@payloadcms/translations@3.0.0-beta.67)(@payloadcms/ui@3.0.0-beta.67)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610):
|
||||
@@ -2134,7 +2134,7 @@ packages:
|
||||
dependencies:
|
||||
'@payloadcms/translations': 3.0.0-beta.67
|
||||
'@payloadcms/ui': 3.0.0-beta.67(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
react: 19.0.0-rc-6230622a1a-20240610
|
||||
react-dom: 19.0.0-rc-6230622a1a-20240610(react@19.0.0-rc-6230622a1a-20240610)
|
||||
dev: false
|
||||
@@ -2175,14 +2175,14 @@ packages:
|
||||
'@lexical/selection': 0.16.1
|
||||
'@lexical/table': 0.16.1
|
||||
'@lexical/utils': 0.16.1
|
||||
'@payloadcms/next': 3.0.0-beta.67(graphql@16.9.0)(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)(typescript@5.5.3)
|
||||
'@payloadcms/next': 3.0.0-beta.67(graphql@16.9.0)(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)(typescript@5.5.4)
|
||||
'@payloadcms/translations': 3.0.0-beta.67
|
||||
'@payloadcms/ui': 3.0.0-beta.67(monaco-editor@0.50.0)(next@15.0.0-canary.58)(payload@3.0.0-beta.67)(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)(types-react@19.0.0-rc.0)
|
||||
'@types/uuid': 10.0.0
|
||||
bson-objectid: 2.0.4
|
||||
dequal: 2.0.3
|
||||
lexical: 0.16.1
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
react: 19.0.0-rc-6230622a1a-20240610
|
||||
react-dom: 19.0.0-rc-6230622a1a-20240610(react@19.0.0-rc-6230622a1a-20240610)
|
||||
react-error-boundary: 4.0.13(react@19.0.0-rc-6230622a1a-20240610)
|
||||
@@ -2218,7 +2218,7 @@ packages:
|
||||
md5: 2.3.0
|
||||
next: 15.0.0-canary.58(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
object-to-formdata: 4.5.1
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3)
|
||||
payload: 3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4)
|
||||
qs-esm: 7.0.2
|
||||
react: 19.0.0-rc-6230622a1a-20240610
|
||||
react-animate-height: 2.1.2(react-dom@19.0.0-rc-6230622a1a-20240610)(react@19.0.0-rc-6230622a1a-20240610)
|
||||
@@ -3471,7 +3471,7 @@ packages:
|
||||
'@types/webidl-conversions': 7.0.3
|
||||
dev: false
|
||||
|
||||
/@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -3483,10 +3483,10 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.11.0
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/scope-manager': 6.6.0
|
||||
'@typescript-eslint/type-utils': 6.6.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/type-utils': 6.6.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/visitor-keys': 6.6.0
|
||||
debug: 4.3.5
|
||||
eslint: 8.48.0
|
||||
@@ -3494,13 +3494,13 @@ packages:
|
||||
ignore: 5.3.1
|
||||
natural-compare: 1.4.0
|
||||
semver: 7.6.2
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0)(eslint@8.57.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0)(eslint@8.57.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
@@ -3512,22 +3512,22 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.11.0
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/scope-manager': 7.16.0
|
||||
'@typescript-eslint/type-utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/type-utils': 7.16.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/visitor-keys': 7.16.0
|
||||
eslint: 8.57.0
|
||||
graphemer: 1.4.0
|
||||
ignore: 5.3.1
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/parser@6.6.0(eslint@8.48.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/parser@6.6.0(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -3539,16 +3539,16 @@ packages:
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 6.6.0
|
||||
'@typescript-eslint/types': 6.6.0
|
||||
'@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.4)
|
||||
'@typescript-eslint/visitor-keys': 6.6.0
|
||||
debug: 4.3.5
|
||||
eslint: 8.48.0
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
@@ -3560,11 +3560,11 @@ packages:
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 7.16.0
|
||||
'@typescript-eslint/types': 7.16.0
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.4)
|
||||
'@typescript-eslint/visitor-keys': 7.16.0
|
||||
debug: 4.3.5
|
||||
eslint: 8.57.0
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -3601,7 +3601,7 @@ packages:
|
||||
'@typescript-eslint/visitor-keys': 7.16.0
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/type-utils@6.6.0(eslint@8.48.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/type-utils@6.6.0(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -3611,17 +3611,17 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.4)
|
||||
'@typescript-eslint/utils': 6.6.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
debug: 4.3.5
|
||||
eslint: 8.48.0
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/type-utils@7.16.0(eslint@8.57.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/type-utils@7.16.0(eslint@8.57.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
@@ -3631,12 +3631,12 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.4)
|
||||
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
debug: 4.3.5
|
||||
eslint: 8.57.0
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -3661,7 +3661,7 @@ packages:
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/typescript-estree@5.62.0(typescript@5.5.3):
|
||||
/@typescript-eslint/typescript-estree@5.62.0(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
@@ -3676,13 +3676,13 @@ packages:
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.6.2
|
||||
tsutils: 3.21.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
tsutils: 3.21.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/typescript-estree@6.21.0(typescript@5.5.3):
|
||||
/@typescript-eslint/typescript-estree@6.21.0(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -3698,13 +3698,13 @@ packages:
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.3
|
||||
semver: 7.6.2
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/typescript-estree@6.6.0(typescript@5.5.3):
|
||||
/@typescript-eslint/typescript-estree@6.6.0(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -3719,13 +3719,13 @@ packages:
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.6.2
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/typescript-estree@7.16.0(typescript@5.5.3):
|
||||
/@typescript-eslint/typescript-estree@7.16.0(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
@@ -3741,13 +3741,13 @@ packages:
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.5
|
||||
semver: 7.6.2
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
typescript: 5.5.3
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/utils@5.62.0(eslint@8.48.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/utils@5.62.0(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
@@ -3758,7 +3758,7 @@ packages:
|
||||
'@types/semver': 7.5.8
|
||||
'@typescript-eslint/scope-manager': 5.62.0
|
||||
'@typescript-eslint/types': 5.62.0
|
||||
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.5.4)
|
||||
eslint: 8.48.0
|
||||
eslint-scope: 5.1.1
|
||||
semver: 7.6.2
|
||||
@@ -3767,7 +3767,7 @@ packages:
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/utils@6.21.0(eslint@8.48.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/utils@6.21.0(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -3778,7 +3778,7 @@ packages:
|
||||
'@types/semver': 7.5.8
|
||||
'@typescript-eslint/scope-manager': 6.21.0
|
||||
'@typescript-eslint/types': 6.21.0
|
||||
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.4)
|
||||
eslint: 8.48.0
|
||||
semver: 7.6.2
|
||||
transitivePeerDependencies:
|
||||
@@ -3786,7 +3786,7 @@ packages:
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/utils@6.6.0(eslint@8.48.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/utils@6.6.0(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -3797,7 +3797,7 @@ packages:
|
||||
'@types/semver': 7.5.8
|
||||
'@typescript-eslint/scope-manager': 6.6.0
|
||||
'@typescript-eslint/types': 6.6.0
|
||||
'@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.4)
|
||||
eslint: 8.48.0
|
||||
semver: 7.6.2
|
||||
transitivePeerDependencies:
|
||||
@@ -3805,7 +3805,7 @@ packages:
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/utils@7.16.0(eslint@8.57.0)(typescript@5.5.3):
|
||||
/@typescript-eslint/utils@7.16.0(eslint@8.57.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
@@ -3814,7 +3814,7 @@ packages:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
|
||||
'@typescript-eslint/scope-manager': 7.16.0
|
||||
'@typescript-eslint/types': 7.16.0
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.4)
|
||||
eslint: 8.57.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5026,7 +5026,7 @@ packages:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
/eslint-config-next@15.0.0-canary.58(eslint@8.57.0)(typescript@5.5.3):
|
||||
/eslint-config-next@15.0.0-canary.58(eslint@8.57.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-/lXrLXcEQ2w8dmvFBtzpfTkakVyLSm4uYCyzkV3YSx2mhx/VW4UH8q1jnv7GPmnpZJdtDr7r5Hd5Ffh1+Qlkmg==}
|
||||
peerDependencies:
|
||||
eslint: ^7.23.0 || ^8.0.0
|
||||
@@ -5037,8 +5037,8 @@ packages:
|
||||
dependencies:
|
||||
'@next/eslint-plugin-next': 15.0.0-canary.58
|
||||
'@rushstack/eslint-patch': 1.10.3
|
||||
'@typescript-eslint/eslint-plugin': 7.16.0(@typescript-eslint/parser@7.16.0)(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/eslint-plugin': 7.16.0(@typescript-eslint/parser@7.16.0)(eslint@8.57.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.16.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
@@ -5046,7 +5046,7 @@ packages:
|
||||
eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0)
|
||||
eslint-plugin-react: 7.34.3(eslint@8.57.0)
|
||||
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
@@ -5115,7 +5115,7 @@ packages:
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
debug: 3.2.7
|
||||
eslint: 8.48.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
@@ -5144,7 +5144,7 @@ packages:
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
debug: 3.2.7
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
@@ -5174,7 +5174,7 @@ packages:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 6.6.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
array-includes: 3.1.8
|
||||
array.prototype.findlastindex: 1.2.5
|
||||
array.prototype.flat: 1.3.2
|
||||
@@ -5209,7 +5209,7 @@ packages:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
array-includes: 3.1.8
|
||||
array.prototype.findlastindex: 1.2.5
|
||||
array.prototype.flat: 1.3.2
|
||||
@@ -5249,7 +5249,7 @@ packages:
|
||||
requireindex: 1.2.0
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-jest@27.2.3(@typescript-eslint/eslint-plugin@6.6.0)(eslint@8.48.0)(typescript@5.5.3):
|
||||
/eslint-plugin-jest@27.2.3(@typescript-eslint/eslint-plugin@6.6.0)(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
peerDependencies:
|
||||
@@ -5262,8 +5262,8 @@ packages:
|
||||
jest:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 5.62.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/eslint-plugin': 6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.48.0)(typescript@5.5.4)
|
||||
'@typescript-eslint/utils': 5.62.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
eslint: 8.48.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5335,7 +5335,7 @@ packages:
|
||||
semver: 6.3.1
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-perfectionist@2.0.0(eslint@8.48.0)(typescript@5.5.3):
|
||||
/eslint-plugin-perfectionist@2.0.0(eslint@8.48.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-VqUk5WR7Dj8L0gNPqn7bl7NTHFYB8l5um4wo7hkMp0Dl+k8RHDAsOef4pPrty6G8vjnzvb3xIZNNshmDJI8SdA==}
|
||||
peerDependencies:
|
||||
astro-eslint-parser: ^0.14.0
|
||||
@@ -5353,7 +5353,7 @@ packages:
|
||||
vue-eslint-parser:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 6.21.0(eslint@8.48.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 6.21.0(eslint@8.48.0)(typescript@5.5.4)
|
||||
eslint: 8.48.0
|
||||
minimatch: 9.0.5
|
||||
natural-compare-lite: 1.4.0
|
||||
@@ -5372,7 +5372,7 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
eslint: 8.48.0
|
||||
eslint-plugin-jest: 27.2.3(@typescript-eslint/eslint-plugin@6.6.0)(eslint@8.48.0)(typescript@5.5.3)
|
||||
eslint-plugin-jest: 27.2.3(@typescript-eslint/eslint-plugin@6.6.0)(eslint@8.48.0)(typescript@5.5.4)
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-react-hooks@4.6.0(eslint@8.48.0):
|
||||
@@ -7265,7 +7265,7 @@ packages:
|
||||
react-dom: 19.0.0-rc-6230622a1a-20240610(react@19.0.0-rc-6230622a1a-20240610)
|
||||
dev: false
|
||||
|
||||
/payload@3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.3):
|
||||
/payload@3.0.0-beta.67(@swc/core@1.6.13)(@swc/types@0.1.9)(graphql@16.9.0)(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-VXJTJ/VRZzIdjTzzRBake63NXNnSZRNJ4hcTwkZZ3ZfRN123jzfqMg0DtAtMHOArC/W8PIIfnCWiBhN1YgWS8A==}
|
||||
engines: {node: ^18.20.2 || >=20.9.0}
|
||||
hasBin: true
|
||||
@@ -7303,7 +7303,7 @@ packages:
|
||||
pluralize: 8.0.0
|
||||
sanitize-filename: 1.6.3
|
||||
scmp: 2.1.0
|
||||
ts-essentials: 7.0.3(typescript@5.5.3)
|
||||
ts-essentials: 7.0.3(typescript@5.5.4)
|
||||
uuid: 10.0.0
|
||||
transitivePeerDependencies:
|
||||
- '@swc/types'
|
||||
@@ -8670,21 +8670,21 @@ packages:
|
||||
utf8-byte-length: 1.0.5
|
||||
dev: false
|
||||
|
||||
/ts-api-utils@1.3.0(typescript@5.5.3):
|
||||
/ts-api-utils@1.3.0(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
|
||||
engines: {node: '>=16'}
|
||||
peerDependencies:
|
||||
typescript: '>=4.2.0'
|
||||
dependencies:
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
dev: true
|
||||
|
||||
/ts-essentials@7.0.3(typescript@5.5.3):
|
||||
/ts-essentials@7.0.3(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==}
|
||||
peerDependencies:
|
||||
typescript: '>=3.7.0'
|
||||
dependencies:
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
dev: false
|
||||
|
||||
/ts-interface-checker@0.1.13:
|
||||
@@ -8706,14 +8706,14 @@ packages:
|
||||
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
|
||||
dev: false
|
||||
|
||||
/tsutils@3.21.0(typescript@5.5.3):
|
||||
/tsutils@3.21.0(typescript@5.5.4):
|
||||
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
||||
engines: {node: '>= 6'}
|
||||
peerDependencies:
|
||||
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
|
||||
dependencies:
|
||||
tslib: 1.14.1
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
dev: true
|
||||
|
||||
/tunnel-agent@0.6.0:
|
||||
@@ -8797,8 +8797,8 @@ packages:
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
|
||||
/typescript@5.5.3:
|
||||
resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==}
|
||||
/typescript@5.5.4:
|
||||
resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.0-canary.53",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.0-canary.53",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.0.0-canary.53",
|
||||
"typescript": "5.5.3"
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
closeNav,
|
||||
ensureCompilationIsDone,
|
||||
exactText,
|
||||
getAdminRoutes,
|
||||
getRoutes,
|
||||
initPageConsoleErrorCatch,
|
||||
login,
|
||||
openDocControls,
|
||||
@@ -99,7 +99,7 @@ describe('access control', () => {
|
||||
routes: { logout: logoutRoute },
|
||||
},
|
||||
routes: { admin: adminRoute },
|
||||
} = getAdminRoutes({})
|
||||
} = getRoutes({})
|
||||
|
||||
logoutURL = `${serverURL}${adminRoute}${logoutRoute}`
|
||||
})
|
||||
|
||||
BIN
test/admin-root/app/favicon.ico
Normal file
BIN
test/admin-root/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -12,6 +12,13 @@ const dirname = path.dirname(filename)
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
collections: [PostsCollection],
|
||||
admin: {
|
||||
autoLogin: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
prefillOnly: true,
|
||||
},
|
||||
},
|
||||
cors: ['http://localhost:3000', 'http://localhost:3001'],
|
||||
globals: [MenuGlobal],
|
||||
routes: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as path from 'path'
|
||||
import { adminRoute } from 'shared.js'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
|
||||
import { ensureCompilationIsDone, initPageConsoleErrorCatch, login } from '../helpers.js'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
||||
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
||||
@@ -29,6 +29,8 @@ test.describe('Admin Panel (Root)', () => {
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
|
||||
await login({ page, serverURL, customRoutes: { admin: adminRoute } })
|
||||
|
||||
await ensureCompilationIsDone({
|
||||
customRoutes: {
|
||||
admin: adminRoute,
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
checkPageTitle,
|
||||
ensureCompilationIsDone,
|
||||
exactText,
|
||||
getAdminRoutes,
|
||||
getRoutes,
|
||||
initPageConsoleErrorCatch,
|
||||
openDocControls,
|
||||
openNav,
|
||||
@@ -76,7 +76,7 @@ describe('admin1', () => {
|
||||
let customFieldsURL: AdminUrlUtil
|
||||
let disableDuplicateURL: AdminUrlUtil
|
||||
let serverURL: string
|
||||
let adminRoutes: ReturnType<typeof getAdminRoutes>
|
||||
let adminRoutes: ReturnType<typeof getRoutes>
|
||||
let loginURL: string
|
||||
|
||||
beforeAll(async ({ browser }, testInfo) => {
|
||||
@@ -106,7 +106,7 @@ describe('admin1', () => {
|
||||
|
||||
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
|
||||
|
||||
adminRoutes = getAdminRoutes({ customAdminRoutes })
|
||||
adminRoutes = getRoutes({ customAdminRoutes })
|
||||
|
||||
loginURL = `${serverURL}${adminRoutes.routes.admin}${adminRoutes.admin.routes.login}`
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@ import type { Config, Geo, Post } from '../../payload-types.js'
|
||||
import {
|
||||
ensureCompilationIsDone,
|
||||
exactText,
|
||||
getAdminRoutes,
|
||||
getRoutes,
|
||||
initPageConsoleErrorCatch,
|
||||
openDocDrawer,
|
||||
openNav,
|
||||
@@ -44,7 +44,7 @@ describe('admin2', () => {
|
||||
let postsUrl: AdminUrlUtil
|
||||
|
||||
let serverURL: string
|
||||
let adminRoutes: ReturnType<typeof getAdminRoutes>
|
||||
let adminRoutes: ReturnType<typeof getRoutes>
|
||||
|
||||
beforeAll(async ({ browser }, testInfo) => {
|
||||
const prebuild = Boolean(process.env.CI)
|
||||
@@ -69,7 +69,7 @@ describe('admin2', () => {
|
||||
|
||||
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
|
||||
|
||||
adminRoutes = getAdminRoutes({ customAdminRoutes })
|
||||
adminRoutes = getRoutes({ customAdminRoutes })
|
||||
})
|
||||
beforeEach(async () => {
|
||||
await reInitializeDB({
|
||||
@@ -421,6 +421,42 @@ describe('admin2', () => {
|
||||
await expect(page.getByPlaceholder('Enter a value')).toHaveValue('[object Object]')
|
||||
await expect(page.locator(tableRowLocator)).toHaveCount(1)
|
||||
})
|
||||
|
||||
test('should reset page when filters are applied', async () => {
|
||||
await deleteAllPosts()
|
||||
await mapAsync([...Array(6)], async () => {
|
||||
await createPost()
|
||||
})
|
||||
await page.reload()
|
||||
await mapAsync([...Array(6)], async () => {
|
||||
await createPost({ title: 'test' })
|
||||
})
|
||||
await page.reload()
|
||||
|
||||
const pageInfo = page.locator('.collection-list__page-info')
|
||||
const perPage = page.locator('.per-page')
|
||||
const tableItems = page.locator(tableRowLocator)
|
||||
|
||||
await expect(tableItems).toHaveCount(10)
|
||||
await expect(pageInfo).toHaveText('1-10 of 12')
|
||||
await expect(perPage).toContainText('Per Page: 10')
|
||||
|
||||
// go to page 2
|
||||
await page.goto(`${postsUrl.list}?limit=10&page=2`)
|
||||
|
||||
// add filter
|
||||
await page.locator('.list-controls__toggle-where').click()
|
||||
await page.locator('.where-builder__add-first-filter').click()
|
||||
await page.locator('.condition__field .rs__control').click()
|
||||
const options = page.locator('.rs__option')
|
||||
await options.locator('text=Tab 1 > Title').click()
|
||||
await page.locator('.condition__operator .rs__control').click()
|
||||
await options.locator('text=equals').click()
|
||||
await page.locator('.condition__value input').fill('test')
|
||||
|
||||
// expect to be on page 1
|
||||
await expect(pageInfo).toHaveText('1-6 of 6')
|
||||
})
|
||||
})
|
||||
|
||||
describe('table columns', () => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import type { Config } from './payload-types.js'
|
||||
|
||||
import {
|
||||
ensureCompilationIsDone,
|
||||
getAdminRoutes,
|
||||
getRoutes,
|
||||
initPageConsoleErrorCatch,
|
||||
saveDocAndAssert,
|
||||
} from '../helpers.js'
|
||||
@@ -49,7 +49,7 @@ const createFirstUser = async ({
|
||||
routes: { createFirstUser: createFirstUserRoute },
|
||||
},
|
||||
routes: { admin: adminRoute },
|
||||
} = getAdminRoutes({
|
||||
} = getRoutes({
|
||||
customAdminRoutes,
|
||||
customRoutes,
|
||||
})
|
||||
|
||||
@@ -1,264 +1,308 @@
|
||||
import type { Config } from 'payload'
|
||||
|
||||
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'path'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { devUser } from '../credentials.js'
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
collections: [
|
||||
{
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'throwAfterChange',
|
||||
type: 'checkbox',
|
||||
defaultValue: false,
|
||||
hooks: {
|
||||
afterChange: [
|
||||
({ value }) => {
|
||||
if (value) {
|
||||
throw new Error('throw after change')
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
const [testSuiteDir] = process.argv.slice(4)
|
||||
const migrationDir = path.resolve(
|
||||
(process.env.PAYLOAD_CONFIG_PATH
|
||||
? path.join(process.env.PAYLOAD_CONFIG_PATH, '..')
|
||||
: testSuiteDir) || dirname,
|
||||
'migrations',
|
||||
)
|
||||
|
||||
const createDatabaseTestConfig = async () => {
|
||||
const config: Partial<Config> = {
|
||||
collections: [
|
||||
{
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'throwAfterChange',
|
||||
type: 'checkbox',
|
||||
defaultValue: false,
|
||||
hooks: {
|
||||
afterChange: [
|
||||
({ value }) => {
|
||||
if (value) {
|
||||
throw new Error('throw after change')
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
beforeOperation: [
|
||||
({ args, operation, req }) => {
|
||||
if (operation === 'update') {
|
||||
const defaultIDType = req.payload.db.defaultIDType
|
||||
|
||||
if (defaultIDType === 'number' && typeof args.id === 'string') {
|
||||
throw new Error('ID was not sanitized to a number properly')
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'relation-a',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Relation As',
|
||||
singular: 'Relation A',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'relation-b',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-a',
|
||||
},
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Relation Bs',
|
||||
singular: 'Relation B',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'pg-migrations',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation1',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-a',
|
||||
},
|
||||
{
|
||||
name: 'myArray',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation2',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
{
|
||||
name: 'mySubArray',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation3',
|
||||
type: 'relationship',
|
||||
localized: true,
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
beforeOperation: [
|
||||
({ args, operation, req }) => {
|
||||
if (operation === 'update') {
|
||||
const defaultIDType = req.payload.db.defaultIDType
|
||||
|
||||
if (defaultIDType === 'number' && typeof args.id === 'string') {
|
||||
throw new Error('ID was not sanitized to a number properly')
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
{
|
||||
name: 'myGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation4',
|
||||
type: 'relationship',
|
||||
localized: true,
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'myBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'myBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation5',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-a',
|
||||
},
|
||||
{
|
||||
name: 'relation6',
|
||||
type: 'relationship',
|
||||
localized: true,
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
versions: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'relation-a',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
{
|
||||
slug: 'custom-schema',
|
||||
dbName: 'customs',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
hasMany: true,
|
||||
relationTo: 'relation-a',
|
||||
},
|
||||
{
|
||||
name: 'select',
|
||||
type: 'select',
|
||||
dbName: ({ tableName }) => `${tableName}_customSelect`,
|
||||
enumName: 'selectEnum',
|
||||
hasMany: true,
|
||||
options: ['a', 'b', 'c'],
|
||||
},
|
||||
{
|
||||
name: 'radio',
|
||||
type: 'select',
|
||||
enumName: 'radioEnum',
|
||||
options: ['a', 'b', 'c'],
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
type: 'array',
|
||||
dbName: 'customArrays',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'block',
|
||||
dbName: 'customBlocks',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
versions: {
|
||||
drafts: true,
|
||||
},
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Relation As',
|
||||
singular: 'Relation A',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'relation-b',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-a',
|
||||
},
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Relation Bs',
|
||||
singular: 'Relation B',
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
slug: 'global',
|
||||
dbName: 'customGlobal',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
versions: true,
|
||||
},
|
||||
],
|
||||
localization: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'es'],
|
||||
},
|
||||
{
|
||||
slug: 'pg-migrations',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation1',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-a',
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
{
|
||||
name: 'myArray',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation2',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
{
|
||||
name: 'mySubArray',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation3',
|
||||
type: 'relationship',
|
||||
localized: true,
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'myGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation4',
|
||||
type: 'relationship',
|
||||
localized: true,
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'myBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'myBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'relation5',
|
||||
type: 'relationship',
|
||||
relationTo: 'relation-a',
|
||||
},
|
||||
{
|
||||
name: 'relation6',
|
||||
type: 'relationship',
|
||||
localized: true,
|
||||
relationTo: 'relation-b',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
versions: true,
|
||||
})
|
||||
},
|
||||
{
|
||||
slug: 'custom-schema',
|
||||
dbName: 'customs',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
hasMany: true,
|
||||
relationTo: 'relation-a',
|
||||
},
|
||||
{
|
||||
name: 'select',
|
||||
type: 'select',
|
||||
dbName: ({ tableName }) => `${tableName}_customSelect`,
|
||||
enumName: 'selectEnum',
|
||||
hasMany: true,
|
||||
options: ['a', 'b', 'c'],
|
||||
},
|
||||
{
|
||||
name: 'radio',
|
||||
type: 'select',
|
||||
enumName: 'radioEnum',
|
||||
options: ['a', 'b', 'c'],
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
type: 'array',
|
||||
dbName: 'customArrays',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'block',
|
||||
dbName: 'customBlocks',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
versions: {
|
||||
drafts: true,
|
||||
},
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
||||
},
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
slug: 'global',
|
||||
dbName: 'customGlobal',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
versions: true,
|
||||
},
|
||||
],
|
||||
localization: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'es'],
|
||||
},
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
}
|
||||
|
||||
const configWithDefaults = await buildConfigWithDefaults(config)
|
||||
|
||||
if (
|
||||
process.env.PAYLOAD_DATABASE === 'mongoose' ||
|
||||
process.env.PAYLOAD_DATABASE === 'mongodb' ||
|
||||
!process.env.PAYLOAD_DATABASE
|
||||
) {
|
||||
configWithDefaults.db = mongooseAdapter({
|
||||
migrationDir,
|
||||
url:
|
||||
process.env.MONGODB_MEMORY_SERVER_URI ||
|
||||
process.env.DATABASE_URI ||
|
||||
'mongodb://127.0.0.1/payloadtests',
|
||||
// Disable strict mode for Mongoose
|
||||
schemaOptions: {
|
||||
strict: false,
|
||||
},
|
||||
})
|
||||
},
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return configWithDefaults
|
||||
}
|
||||
|
||||
export default createDatabaseTestConfig()
|
||||
|
||||
export const postDoc = {
|
||||
title: 'test post',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { MongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
import type { PostgresAdapter } from '@payloadcms/db-postgres/types'
|
||||
import type { NextRESTClient } from 'helpers/NextRESTClient.js'
|
||||
import type { Payload, PayloadRequest, TypeWithID } from 'payload'
|
||||
@@ -6,6 +7,9 @@ import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { commitTransaction, initTransaction } from 'payload'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
import type { CustomSchema } from './payload-types.js'
|
||||
|
||||
import { devUser } from '../credentials.js'
|
||||
import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
||||
@@ -461,4 +465,109 @@ describe('database', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('existing data', () => {
|
||||
let existingDataDoc: CustomSchema
|
||||
|
||||
beforeAll(async () => {
|
||||
if (payload.db.name === 'mongoose') {
|
||||
const Model = payload.db.collections['custom-schema']
|
||||
|
||||
const [doc] = await Model.create([
|
||||
{
|
||||
array: [
|
||||
{
|
||||
id: uuid(),
|
||||
localizedText: {
|
||||
en: 'goodbye',
|
||||
},
|
||||
noFieldDefined: 'hi',
|
||||
text: 'hello',
|
||||
},
|
||||
],
|
||||
blocks: [
|
||||
{
|
||||
id: uuid(),
|
||||
blockType: 'block',
|
||||
localizedText: {
|
||||
en: 'goodbye',
|
||||
},
|
||||
noFieldDefined: 'hi',
|
||||
text: 'hello',
|
||||
},
|
||||
],
|
||||
localizedText: {
|
||||
en: 'goodbye',
|
||||
},
|
||||
noFieldDefined: 'hi',
|
||||
text: 'hello',
|
||||
},
|
||||
])
|
||||
|
||||
const result = JSON.parse(JSON.stringify(doc))
|
||||
result.id = result._id
|
||||
existingDataDoc = result
|
||||
}
|
||||
})
|
||||
|
||||
it('should allow storage of existing data', async () => {
|
||||
expect(payload.db).toBeDefined()
|
||||
|
||||
if (payload.db.name === 'mongoose') {
|
||||
expect(existingDataDoc.noFieldDefined).toStrictEqual('hi')
|
||||
expect(existingDataDoc.array[0].noFieldDefined).toStrictEqual('hi')
|
||||
expect(existingDataDoc.blocks[0].noFieldDefined).toStrictEqual('hi')
|
||||
|
||||
const docWithExistingData = await payload.findByID({
|
||||
id: existingDataDoc.id,
|
||||
collection: 'custom-schema',
|
||||
})
|
||||
|
||||
expect(docWithExistingData.noFieldDefined).toStrictEqual('hi')
|
||||
expect(docWithExistingData.array[0].noFieldDefined).toStrictEqual('hi')
|
||||
expect(docWithExistingData.blocks[0].noFieldDefined).toStrictEqual('hi')
|
||||
}
|
||||
})
|
||||
|
||||
it('should maintain existing data while updating', async () => {
|
||||
expect(payload.db).toBeDefined()
|
||||
|
||||
if (payload.db.name === 'mongoose') {
|
||||
const result = await payload.update({
|
||||
id: existingDataDoc.id,
|
||||
collection: 'custom-schema',
|
||||
data: {
|
||||
array: [
|
||||
{
|
||||
id: existingDataDoc.array[0].id,
|
||||
localizedText: 'adios',
|
||||
text: 'hola',
|
||||
},
|
||||
],
|
||||
blocks: [
|
||||
{
|
||||
id: existingDataDoc.blocks[0].id,
|
||||
blockType: 'block',
|
||||
localizedText: 'adios',
|
||||
text: 'hola',
|
||||
},
|
||||
],
|
||||
localizedText: 'adios',
|
||||
text: 'hola',
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.text).toStrictEqual('hola')
|
||||
expect(result.array[0].text).toStrictEqual('hola')
|
||||
expect(result.blocks[0].text).toStrictEqual('hola')
|
||||
expect(result.localizedText).toStrictEqual('adios')
|
||||
expect(result.array[0].localizedText).toStrictEqual('adios')
|
||||
expect(result.blocks[0].localizedText).toStrictEqual('adios')
|
||||
|
||||
expect(result.noFieldDefined).toStrictEqual('hi')
|
||||
expect(result.array[0].noFieldDefined).toStrictEqual('hi')
|
||||
expect(result.blocks[0].noFieldDefined).toStrictEqual('hi')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
59
test/field-error-states/collections/PrevValue/index.ts
Normal file
59
test/field-error-states/collections/PrevValue/index.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import * as QueryString from 'qs-esm'
|
||||
|
||||
import { collectionSlugs } from '../../shared.js'
|
||||
|
||||
export const PrevValue: CollectionConfig = {
|
||||
slug: collectionSlugs.prevValue,
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
validate: async (value, options) => {
|
||||
if (options.operation === 'create') return true
|
||||
|
||||
const query = QueryString.stringify(
|
||||
{
|
||||
where: {
|
||||
previousValueRelation: {
|
||||
in: [options.id],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
addQueryPrefix: true,
|
||||
},
|
||||
)
|
||||
|
||||
try {
|
||||
const relatedDocs = await fetch(
|
||||
`http://localhost:3000/api/${collectionSlugs.prevValueRelation}${query}`,
|
||||
{
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
).then((res) => res.json())
|
||||
if (relatedDocs.docs.length > 0 && value !== options.previousValue) {
|
||||
console.log({
|
||||
value,
|
||||
prev: options.previousValue,
|
||||
})
|
||||
return 'Doc is being referenced, cannot change title'
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { collectionSlugs } from '../../shared.js'
|
||||
|
||||
export const PrevValueRelation: CollectionConfig = {
|
||||
slug: collectionSlugs.prevValueRelation,
|
||||
fields: [
|
||||
{
|
||||
relationTo: collectionSlugs.prevValue,
|
||||
name: 'previousValueRelation',
|
||||
type: 'relationship',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { slugs } from '../../shared.js'
|
||||
import { collectionSlugs } from '../../shared.js'
|
||||
import { ValidateDraftsOn } from '../ValidateDraftsOn/index.js'
|
||||
|
||||
export const ValidateDraftsOff: CollectionConfig = {
|
||||
...ValidateDraftsOn,
|
||||
slug: slugs.validateDraftsOff,
|
||||
slug: collectionSlugs.validateDraftsOff,
|
||||
versions: {
|
||||
drafts: true,
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { slugs } from '../../shared.js'
|
||||
import { collectionSlugs } from '../../shared.js'
|
||||
|
||||
export const ValidateDraftsOn: CollectionConfig = {
|
||||
slug: slugs.validateDraftsOn,
|
||||
slug: collectionSlugs.validateDraftsOn,
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { slugs } from '../../shared.js'
|
||||
import { collectionSlugs } from '../../shared.js'
|
||||
import { ValidateDraftsOn } from '../ValidateDraftsOn/index.js'
|
||||
|
||||
export const ValidateDraftsOnAndAutosave: CollectionConfig = {
|
||||
...ValidateDraftsOn,
|
||||
slug: slugs.validateDraftsOnAutosave,
|
||||
slug: collectionSlugs.validateDraftsOnAutosave,
|
||||
versions: {
|
||||
drafts: {
|
||||
autosave: true,
|
||||
|
||||
@@ -5,6 +5,8 @@ const dirname = path.dirname(filename)
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { devUser } from '../credentials.js'
|
||||
import { ErrorFieldsCollection } from './collections/ErrorFields/index.js'
|
||||
import { PrevValue } from './collections/PrevValue/index.js'
|
||||
import { PrevValueRelation } from './collections/PrevValueRelation/index.js'
|
||||
import Uploads from './collections/Upload/index.js'
|
||||
import { ValidateDraftsOff } from './collections/ValidateDraftsOff/index.js'
|
||||
import { ValidateDraftsOn } from './collections/ValidateDraftsOn/index.js'
|
||||
@@ -18,6 +20,8 @@ export default buildConfigWithDefaults({
|
||||
ValidateDraftsOn,
|
||||
ValidateDraftsOff,
|
||||
ValidateDraftsOnAndAutosave,
|
||||
PrevValue,
|
||||
PrevValueRelation,
|
||||
],
|
||||
globals: [GlobalValidateDraftsOn],
|
||||
onInit: async (payload) => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'url'
|
||||
import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js'
|
||||
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
||||
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
||||
import { slugs } from './shared.js'
|
||||
import { collectionSlugs } from './shared.js'
|
||||
|
||||
const { beforeAll, describe } = test
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
@@ -20,13 +20,17 @@ describe('field error states', () => {
|
||||
let validateDraftsOff: AdminUrlUtil
|
||||
let validateDraftsOn: AdminUrlUtil
|
||||
let validateDraftsOnAutosave: AdminUrlUtil
|
||||
let prevValue: AdminUrlUtil
|
||||
let prevValueRelation: AdminUrlUtil
|
||||
|
||||
beforeAll(async ({ browser }, testInfo) => {
|
||||
testInfo.setTimeout(TEST_TIMEOUT_LONG)
|
||||
;({ serverURL } = await initPayloadE2ENoConfig({ dirname }))
|
||||
validateDraftsOff = new AdminUrlUtil(serverURL, slugs.validateDraftsOff)
|
||||
validateDraftsOn = new AdminUrlUtil(serverURL, slugs.validateDraftsOn)
|
||||
validateDraftsOnAutosave = new AdminUrlUtil(serverURL, slugs.validateDraftsOnAutosave)
|
||||
validateDraftsOff = new AdminUrlUtil(serverURL, collectionSlugs.validateDraftsOff)
|
||||
validateDraftsOn = new AdminUrlUtil(serverURL, collectionSlugs.validateDraftsOn)
|
||||
validateDraftsOnAutosave = new AdminUrlUtil(serverURL, collectionSlugs.validateDraftsOnAutosave)
|
||||
prevValue = new AdminUrlUtil(serverURL, collectionSlugs.prevValue)
|
||||
prevValueRelation = new AdminUrlUtil(serverURL, collectionSlugs.prevValueRelation)
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
@@ -87,4 +91,33 @@ describe('field error states', () => {
|
||||
await saveDocAndAssert(page, '#action-save', 'error')
|
||||
})
|
||||
})
|
||||
|
||||
describe('previous values', () => {
|
||||
test('should pass previous value into validate function', async () => {
|
||||
// save original
|
||||
await page.goto(prevValue.create)
|
||||
await page.locator('#field-title').fill('original value')
|
||||
await saveDocAndAssert(page)
|
||||
await page.locator('#field-title').fill('original value 2')
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// create relation to doc
|
||||
await page.goto(prevValueRelation.create)
|
||||
await page.locator('#field-previousValueRelation .react-select').click()
|
||||
await page.locator('#field-previousValueRelation .rs__option').first().click()
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// go back to doc
|
||||
await page.goto(prevValue.list)
|
||||
await page.locator('.row-1 a').click()
|
||||
await page.locator('#field-description').fill('some description')
|
||||
await saveDocAndAssert(page)
|
||||
await page.locator('#field-title').fill('changed')
|
||||
await saveDocAndAssert(page, '#action-save', 'error')
|
||||
|
||||
// ensure value is the value before relationship association
|
||||
await page.reload()
|
||||
await expect(page.locator('#field-title')).toHaveValue('original value 2')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { GlobalConfig } from 'payload'
|
||||
|
||||
import { slugs } from '../../shared.js'
|
||||
import { globalSlugs } from '../../shared.js'
|
||||
|
||||
export const GlobalValidateDraftsOn: GlobalConfig = {
|
||||
slug: slugs.globalValidateDraftsOn,
|
||||
slug: globalSlugs.globalValidateDraftsOn,
|
||||
fields: [
|
||||
{
|
||||
name: 'group',
|
||||
|
||||
@@ -16,10 +16,15 @@ export interface Config {
|
||||
'validate-drafts-on': ValidateDraftsOn;
|
||||
'validate-drafts-off': ValidateDraftsOff;
|
||||
'validate-drafts-on-autosave': ValidateDraftsOnAutosave;
|
||||
'prev-value': PrevValue;
|
||||
'prev-value-relation': PrevValueRelation;
|
||||
users: User;
|
||||
'payload-preferences': PayloadPreference;
|
||||
'payload-migrations': PayloadMigration;
|
||||
};
|
||||
db: {
|
||||
defaultIDType: string;
|
||||
};
|
||||
globals: {
|
||||
'global-validate-drafts-on': GlobalValidateDraftsOn;
|
||||
};
|
||||
@@ -33,13 +38,16 @@ export interface UserAuthOperations {
|
||||
email: string;
|
||||
};
|
||||
login: {
|
||||
password: string;
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
registerFirstUser: {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
unlock: {
|
||||
email: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
@@ -312,6 +320,27 @@ export interface ValidateDraftsOnAutosave {
|
||||
createdAt: string;
|
||||
_status?: ('draft' | 'published') | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "prev-value".
|
||||
*/
|
||||
export interface PrevValue {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "prev-value-relation".
|
||||
*/
|
||||
export interface PrevValueRelation {
|
||||
id: string;
|
||||
previousValueRelation?: (string | null) | PrevValue;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-preferences".
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
export const slugs = {
|
||||
globalValidateDraftsOn: 'global-validate-drafts-on',
|
||||
import type { CollectionSlug, GlobalSlug } from 'payload'
|
||||
|
||||
export const collectionSlugs: {
|
||||
[key: string]: CollectionSlug
|
||||
} = {
|
||||
validateDraftsOff: 'validate-drafts-off',
|
||||
validateDraftsOn: 'validate-drafts-on',
|
||||
validateDraftsOnAutosave: 'validate-drafts-on-autosave',
|
||||
prevValue: 'prev-value',
|
||||
prevValueRelation: 'prev-value-relation',
|
||||
}
|
||||
|
||||
export const globalSlugs: {
|
||||
[key: string]: GlobalSlug
|
||||
} = {
|
||||
globalValidateDraftsOn: 'global-validate-drafts-on',
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { BrowserContext, ChromiumBrowserContext, Locator, Page } from '@playwright/test'
|
||||
import type { Config } from 'payload'
|
||||
|
||||
import { formatAdminURL } from '@payloadcms/ui/shared'
|
||||
import { expect } from '@playwright/test'
|
||||
import { defaults } from 'payload'
|
||||
import { wait } from 'payload/shared'
|
||||
@@ -65,7 +66,7 @@ export async function ensureCompilationIsDone({
|
||||
}): Promise<void> {
|
||||
const {
|
||||
routes: { admin: adminRoute },
|
||||
} = getAdminRoutes({ customAdminRoutes, customRoutes })
|
||||
} = getRoutes({ customAdminRoutes, customRoutes })
|
||||
|
||||
const adminURL = `${serverURL}${adminRoute}`
|
||||
|
||||
@@ -114,7 +115,7 @@ export async function firstRegister(args: FirstRegisterArgs): Promise<void> {
|
||||
|
||||
const {
|
||||
routes: { admin: adminRoute },
|
||||
} = getAdminRoutes({ customAdminRoutes, customRoutes })
|
||||
} = getRoutes({ customAdminRoutes, customRoutes })
|
||||
|
||||
await page.goto(`${serverURL}${adminRoute}`)
|
||||
await page.fill('#field-email', devUser.email)
|
||||
@@ -130,27 +131,37 @@ export async function login(args: LoginArgs): Promise<void> {
|
||||
|
||||
const {
|
||||
admin: {
|
||||
routes: { createFirstUser: createFirstUserRoute, login: loginRoute },
|
||||
routes: { createFirstUser, login: incomingLoginRoute },
|
||||
},
|
||||
routes: { admin: adminRoute },
|
||||
} = getAdminRoutes({ customAdminRoutes, customRoutes })
|
||||
routes: { admin: incomingAdminRoute },
|
||||
} = getRoutes({ customAdminRoutes, customRoutes })
|
||||
|
||||
await page.goto(`${serverURL}${adminRoute}${loginRoute}`)
|
||||
await page.waitForURL(`${serverURL}${adminRoute}${loginRoute}`)
|
||||
const adminRoute = formatAdminURL({ serverURL, adminRoute: incomingAdminRoute, path: '' })
|
||||
const loginRoute = formatAdminURL({
|
||||
serverURL,
|
||||
adminRoute: incomingAdminRoute,
|
||||
path: incomingLoginRoute,
|
||||
})
|
||||
const createFirstUserRoute = formatAdminURL({
|
||||
serverURL,
|
||||
adminRoute: incomingAdminRoute,
|
||||
path: createFirstUser,
|
||||
})
|
||||
|
||||
await page.goto(loginRoute)
|
||||
await page.waitForURL(loginRoute)
|
||||
await wait(500)
|
||||
await page.fill('#field-email', data.email)
|
||||
await page.fill('#field-password', data.password)
|
||||
await wait(500)
|
||||
await page.click('[type=submit]')
|
||||
await page.waitForURL(`${serverURL}${adminRoute}`)
|
||||
await page.waitForURL(adminRoute)
|
||||
|
||||
await expect(() => expect(page.url()).not.toContain(`${adminRoute}${loginRoute}`)).toPass({
|
||||
await expect(() => expect(page.url()).not.toContain(loginRoute)).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
await expect(() =>
|
||||
expect(page.url()).not.toContain(`${adminRoute}${createFirstUserRoute}`),
|
||||
).toPass({
|
||||
await expect(() => expect(page.url()).not.toContain(createFirstUserRoute)).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
}
|
||||
@@ -328,7 +339,7 @@ export function describeIfInCIOrHasLocalstack(): jest.Describe {
|
||||
|
||||
type AdminRoutes = Config['admin']['routes']
|
||||
|
||||
export function getAdminRoutes({
|
||||
export function getRoutes({
|
||||
customAdminRoutes,
|
||||
customRoutes,
|
||||
}: {
|
||||
|
||||
@@ -11,8 +11,8 @@ const Hooks: CollectionConfig = {
|
||||
},
|
||||
hooks: {
|
||||
beforeOperation: [
|
||||
({ req }) => {
|
||||
if (!req.transactionID) {
|
||||
({ req, operation }) => {
|
||||
if (!req.transactionID && ['create', 'delete', 'update'].includes(operation)) {
|
||||
throw new Error('transactionID is missing in beforeOperation hook')
|
||||
}
|
||||
},
|
||||
|
||||
@@ -68,14 +68,14 @@
|
||||
"file-type": "17.1.6",
|
||||
"http-status": "1.6.2",
|
||||
"jwt-decode": "4.0.0",
|
||||
"lexical": "0.15.0",
|
||||
"lexical": "0.16.1",
|
||||
"payload": "workspace:*",
|
||||
"qs-esm": "7.0.2",
|
||||
"server-only": "^0.0.1",
|
||||
"slate": "0.91.4",
|
||||
"tempy": "^1.0.1",
|
||||
"ts-essentials": "7.0.3",
|
||||
"typescript": "5.5.3",
|
||||
"typescript": "5.5.4",
|
||||
"uploadthing": "^6.10.1",
|
||||
"uuid": "10.0.0"
|
||||
},
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
],
|
||||
"paths": {
|
||||
"@payload-config": [
|
||||
"./test/admin/config.ts"
|
||||
"./test/_community/config.ts"
|
||||
],
|
||||
"@payloadcms/live-preview": [
|
||||
"./packages/live-preview/src"
|
||||
|
||||
Reference in New Issue
Block a user