Merge branch '2.0' of github.com:payloadcms/payload into 2.0
This commit is contained in:
@@ -18,14 +18,10 @@
|
||||
"fix": "eslint \"packages/**/*.ts\" --fix",
|
||||
"lint": "eslint \"packages/**/*.ts\"",
|
||||
"lint-staged": "lint-staged",
|
||||
"release:beta": "release-it pre --preReleaseId=beta --npm.tag=beta --config .release-it.pre.json",
|
||||
"release:canary": "release-it pre --preReleaseId=canary --npm.tag=canary --config .release-it.pre.json",
|
||||
"release:major": "release-it major",
|
||||
"release:minor": "release-it minor",
|
||||
"release:patch": "release-it patch",
|
||||
"pretest": "pnpm build",
|
||||
"reinstall": "./scripts/reinstall.sh",
|
||||
"release:list:beta": "./scripts/list_published_packages.sh beta",
|
||||
"script:release:beta": "./scripts/release_beta.sh",
|
||||
"test": "pnpm test:int && pnpm test:components && pnpm test:e2e",
|
||||
"test:components": "cross-env jest --config=jest.components.config.js",
|
||||
"test:e2e": "npx playwright install --with-deps && ts-node -T ./test/runE2E.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/bundler-vite",
|
||||
"version": "0.1.0-beta.4",
|
||||
"version": "0.1.0-beta.6",
|
||||
"description": "The officially supported Vite bundler adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
@@ -44,6 +44,7 @@
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"mock.js"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import getPort from 'get-port'
|
||||
import path from 'path'
|
||||
import virtual from 'vite-plugin-virtual'
|
||||
|
||||
const bundlerPath = path.resolve(__dirname, './')
|
||||
const mockModulePath = path.resolve(__dirname, './mocks/emptyModule.js')
|
||||
const mockDotENVPath = path.resolve(__dirname, './mocks/dotENV.js')
|
||||
|
||||
@@ -26,11 +25,10 @@ export const getViteConfig = async (payloadConfig: SanitizedConfig): Promise<Inl
|
||||
|
||||
const hmrPort = await getPort()
|
||||
|
||||
const absoluteAliases = {
|
||||
[`${bundlerPath}`]: path.resolve(__dirname, './mock.js'),
|
||||
}
|
||||
const absoluteAliases = {}
|
||||
|
||||
const alias = [
|
||||
{ find: '@payloadcms/bundler-vite', replacement: path.resolve(__dirname, '../mock.js') },
|
||||
{ find: 'path', replacement: require.resolve('path-browserify') },
|
||||
{ find: 'payload-config', replacement: payloadConfig.paths.rawConfig },
|
||||
{ find: /payload$/, replacement: mockModulePath },
|
||||
@@ -89,7 +87,9 @@ export const getViteConfig = async (payloadConfig: SanitizedConfig): Promise<Inl
|
||||
exclude: [
|
||||
// Dependencies that need aliases should be excluded
|
||||
// from pre-bundling
|
||||
'@payloadcms/bundler-vite',
|
||||
],
|
||||
include: ['payload/components/root'],
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "1.0.0-beta.3",
|
||||
"version": "1.0.0-beta.4",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
@@ -40,6 +40,7 @@
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"mock.js"
|
||||
]
|
||||
}
|
||||
|
||||
19
packages/db-mongodb/src/extendViteConfig.ts
Normal file
19
packages/db-mongodb/src/extendViteConfig.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
|
||||
export const vite = (config) => {
|
||||
return {
|
||||
...config,
|
||||
optimizeDeps: {
|
||||
...config.optimizeDeps,
|
||||
exclude: [...config.optimizeDeps.exclude, '@payloadcms/db-mongodb'],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const extendViteConfig = (config: SanitizedConfig) => {
|
||||
const existingViteConfig = config.admin.vite ? config.admin.vite : (viteConfig) => viteConfig
|
||||
|
||||
config.admin.vite = (webpackConfig) => {
|
||||
return vite(existingViteConfig(webpackConfig))
|
||||
}
|
||||
}
|
||||
28
packages/db-mongodb/src/extendWebpackConfig.ts
Normal file
28
packages/db-mongodb/src/extendWebpackConfig.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const webpack = (config) => {
|
||||
const aliasPath = path.resolve(__dirname, '../mock.js')
|
||||
|
||||
return {
|
||||
...config,
|
||||
resolve: {
|
||||
...(config.resolve || {}),
|
||||
alias: {
|
||||
...(config.resolve?.alias || {}),
|
||||
'@payloadcms/db-mongodb': aliasPath,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const extendWebpackConfig = (config: SanitizedConfig) => {
|
||||
const existingWebpackConfig = config.admin.webpack
|
||||
? config.admin.webpack
|
||||
: (webpackConfig) => webpackConfig
|
||||
|
||||
config.admin.webpack = (webpackConfig) => {
|
||||
return webpack(existingWebpackConfig(webpackConfig))
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import { deleteMany } from './deleteMany'
|
||||
import { deleteOne } from './deleteOne'
|
||||
import { deleteVersions } from './deleteVersions'
|
||||
import { destroy } from './destroy'
|
||||
import { extendViteConfig } from './extendViteConfig'
|
||||
import { extendWebpackConfig } from './extendWebpackConfig'
|
||||
import { find } from './find'
|
||||
import { findGlobal } from './findGlobal'
|
||||
import { findGlobalVersions } from './findGlobalVersions'
|
||||
@@ -33,7 +35,6 @@ import { updateGlobal } from './updateGlobal'
|
||||
import { updateGlobalVersion } from './updateGlobalVersion'
|
||||
import { updateOne } from './updateOne'
|
||||
import { updateVersion } from './updateVersion'
|
||||
import { webpack } from './webpack'
|
||||
|
||||
export interface Args {
|
||||
/** Set to false to disable auto-pluralization of collection names, Defaults to true */
|
||||
@@ -88,6 +89,9 @@ export function mongooseAdapter({
|
||||
function adapter({ payload }: { payload: Payload }) {
|
||||
mongoose.set('strictQuery', false)
|
||||
|
||||
extendWebpackConfig(payload.config)
|
||||
extendViteConfig(payload.config)
|
||||
|
||||
return createDatabaseAdapter<MongooseAdapter>({
|
||||
autoPluralization,
|
||||
beginTransaction,
|
||||
@@ -126,7 +130,6 @@ export function mongooseAdapter({
|
||||
updateVersion,
|
||||
url,
|
||||
versions: {},
|
||||
webpack,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import type { Webpack } from 'payload/database'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const webpack: Webpack = (config) => {
|
||||
const aliasPath = path.resolve(__dirname, 'mock.js')
|
||||
|
||||
return {
|
||||
...config,
|
||||
resolve: {
|
||||
...(config.resolve || {}),
|
||||
alias: {
|
||||
...(config.resolve?.alias || {}),
|
||||
'@payloadcms/db-mongodb': aliasPath,
|
||||
[path.resolve(__dirname, './index')]: aliasPath,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "0.1.0-beta.8",
|
||||
"version": "0.1.0-beta.10",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
@@ -43,6 +43,7 @@
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"mock.js"
|
||||
]
|
||||
}
|
||||
|
||||
19
packages/db-postgres/src/extendViteConfig.ts
Normal file
19
packages/db-postgres/src/extendViteConfig.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
|
||||
export const vite = (config) => {
|
||||
return {
|
||||
...config,
|
||||
optimizeDeps: {
|
||||
...config.optimizeDeps,
|
||||
exclude: [...config.optimizeDeps.exclude, '@payloadcms/db-postgres'],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const extendViteConfig = (config: SanitizedConfig) => {
|
||||
const existingViteConfig = config.admin.vite ? config.admin.vite : (viteConfig) => viteConfig
|
||||
|
||||
config.admin.vite = (webpackConfig) => {
|
||||
return vite(existingViteConfig(webpackConfig))
|
||||
}
|
||||
}
|
||||
28
packages/db-postgres/src/extendWebpackConfig.ts
Normal file
28
packages/db-postgres/src/extendWebpackConfig.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const webpack = (config) => {
|
||||
const aliasPath = path.resolve(__dirname, '../mock.js')
|
||||
|
||||
return {
|
||||
...config,
|
||||
resolve: {
|
||||
...(config.resolve || {}),
|
||||
alias: {
|
||||
...(config.resolve?.alias || {}),
|
||||
'@payloadcms/db-postgres': aliasPath,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const extendWebpackConfig = (config: SanitizedConfig) => {
|
||||
const existingWebpackConfig = config.admin.webpack
|
||||
? config.admin.webpack
|
||||
: (webpackConfig) => webpackConfig
|
||||
|
||||
config.admin.webpack = (webpackConfig) => {
|
||||
return webpack(existingWebpackConfig(webpackConfig))
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ import { deleteMany } from './deleteMany'
|
||||
import { deleteOne } from './deleteOne'
|
||||
import { deleteVersions } from './deleteVersions'
|
||||
import { destroy } from './destroy'
|
||||
import { extendViteConfig } from './extendViteConfig'
|
||||
import { extendWebpackConfig } from './extendWebpackConfig'
|
||||
import { find } from './find'
|
||||
import { findGlobal } from './findGlobal'
|
||||
import { findGlobalVersions } from './findGlobalVersions'
|
||||
@@ -33,11 +35,14 @@ import { updateOne } from './update'
|
||||
import { updateGlobal } from './updateGlobal'
|
||||
import { updateGlobalVersion } from './updateGlobalVersion'
|
||||
import { updateVersion } from './updateVersion'
|
||||
import { webpack } from './webpack'
|
||||
|
||||
export function postgresAdapter(args: Args): PostgresAdapterResult {
|
||||
function adapter({ payload }: { payload: Payload }) {
|
||||
const migrationDir = args.migrationDir || path.resolve(process.cwd(), 'src/migrations')
|
||||
|
||||
extendWebpackConfig(payload.config)
|
||||
extendViteConfig(payload.config)
|
||||
|
||||
return createDatabaseAdapter<PostgresAdapter>({
|
||||
...args,
|
||||
name: 'postgres',
|
||||
@@ -81,7 +86,6 @@ export function postgresAdapter(args: Args): PostgresAdapterResult {
|
||||
updateGlobalVersion,
|
||||
updateOne,
|
||||
updateVersion,
|
||||
webpack,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,7 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
||||
if (this.payload.config.localization) {
|
||||
this.enums.enum__locales = pgEnum(
|
||||
'_locales',
|
||||
// TODO: types out of sync with core, monorepo please
|
||||
// this.payload.config.localization.localeCodes,
|
||||
(this.payload.config.localization.locales as unknown as { code: string }[]).map(
|
||||
({ code }) => code,
|
||||
) as [string, ...string[]],
|
||||
this.payload.config.localization.locales.map(({ code }) => code) as [string, ...string[]],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,6 +24,7 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
||||
buildTable({
|
||||
adapter: this,
|
||||
buildRelationships: true,
|
||||
collectionIndexes: collection.indexes,
|
||||
disableUnique: false,
|
||||
fields: collection.fields,
|
||||
tableName,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type { IndexBuilder, PgColumnBuilder, UniqueConstraintBuilder } from 'drizzle-orm/pg-core'
|
||||
import type { Field } from 'payload/types'
|
||||
import type { Field, SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
import { relations } from 'drizzle-orm'
|
||||
import {
|
||||
@@ -27,6 +27,7 @@ type Args = {
|
||||
baseColumns?: Record<string, PgColumnBuilder>
|
||||
baseExtraConfig?: Record<string, (cols: GenericColumns) => IndexBuilder | UniqueConstraintBuilder>
|
||||
buildRelationships?: boolean
|
||||
collectionIndexes?: SanitizedCollectionConfig['indexes']
|
||||
disableUnique: boolean
|
||||
fields: Field[]
|
||||
rootRelationsToBuild?: Map<string, string>
|
||||
@@ -45,6 +46,7 @@ export const buildTable = ({
|
||||
baseColumns = {},
|
||||
baseExtraConfig = {},
|
||||
buildRelationships,
|
||||
collectionIndexes = [],
|
||||
disableUnique = false,
|
||||
fields,
|
||||
rootRelationsToBuild,
|
||||
@@ -96,6 +98,7 @@ export const buildTable = ({
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildRelationships,
|
||||
collectionIndexes,
|
||||
columns,
|
||||
disableUnique,
|
||||
fields,
|
||||
|
||||
@@ -5,13 +5,22 @@ import type { GenericColumn } from '../types'
|
||||
|
||||
type CreateIndexArgs = {
|
||||
columnName: string
|
||||
name: string
|
||||
name: string | string[]
|
||||
unique?: boolean
|
||||
}
|
||||
|
||||
export const createIndex = ({ name, columnName, unique }: CreateIndexArgs) => {
|
||||
return (table: { [x: string]: GenericColumn }) => {
|
||||
if (unique) return uniqueIndex(`${columnName}_idx`).on(table[name])
|
||||
return index(`${columnName}_idx`).on(table[name])
|
||||
let columns
|
||||
if (Array.isArray(name)) {
|
||||
columns = name
|
||||
.map((columnName) => table[columnName])
|
||||
// exclude fields were included in compound indexes but do not exist on the table
|
||||
.filter((col) => typeof col !== 'undefined')
|
||||
} else {
|
||||
columns = [table[name]]
|
||||
}
|
||||
if (unique) return uniqueIndex(`${columnName}_idx`).on(columns[0], ...columns.slice(1))
|
||||
return index(`${columnName}_idx`).on(columns[0], ...columns.slice(1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type { IndexBuilder, PgColumnBuilder, UniqueConstraintBuilder } from 'drizzle-orm/pg-core'
|
||||
import type { Field, TabAsField } from 'payload/types'
|
||||
import type { Field, SanitizedCollectionConfig, TabAsField } from 'payload/types'
|
||||
|
||||
import { relations } from 'drizzle-orm'
|
||||
import {
|
||||
@@ -33,6 +33,7 @@ import { validateExistingBlockIsIdentical } from './validateExistingBlockIsIdent
|
||||
type Args = {
|
||||
adapter: PostgresAdapter
|
||||
buildRelationships: boolean
|
||||
collectionIndexes: SanitizedCollectionConfig['indexes']
|
||||
columnPrefix?: string
|
||||
columns: Record<string, PgColumnBuilder>
|
||||
disableUnique?: boolean
|
||||
@@ -61,6 +62,7 @@ type Result = {
|
||||
export const traverseFields = ({
|
||||
adapter,
|
||||
buildRelationships,
|
||||
collectionIndexes,
|
||||
columnPrefix,
|
||||
columns,
|
||||
disableUnique = false,
|
||||
@@ -109,6 +111,24 @@ export const traverseFields = ({
|
||||
targetIndexes = localesIndexes
|
||||
}
|
||||
|
||||
const collectionIndex = collectionIndexes
|
||||
? collectionIndexes.findIndex((index) => {
|
||||
return Object.keys(index.fields).some((indexField) => indexField === fieldName)
|
||||
})
|
||||
: -1
|
||||
|
||||
if (collectionIndex > -1) {
|
||||
const name = toSnakeCase(
|
||||
`${Object.keys(collectionIndexes[collectionIndex].fields).join('_')}`,
|
||||
)
|
||||
targetIndexes[`${name}Idx`] = createIndex({
|
||||
name: Object.keys(collectionIndexes[collectionIndex].fields),
|
||||
columnName: name,
|
||||
unique: collectionIndexes[collectionIndex].options.unique,
|
||||
})
|
||||
collectionIndexes.splice(collectionIndex)
|
||||
}
|
||||
|
||||
if (
|
||||
(field.unique || field.index) &&
|
||||
!['array', 'blocks', 'group', 'point', 'relationship', 'upload'].includes(field.type) &&
|
||||
@@ -415,6 +435,7 @@ export const traverseFields = ({
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildRelationships,
|
||||
collectionIndexes,
|
||||
columnPrefix,
|
||||
columns,
|
||||
disableUnique,
|
||||
@@ -448,6 +469,7 @@ export const traverseFields = ({
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildRelationships,
|
||||
collectionIndexes,
|
||||
columnPrefix: `${columnName}_`,
|
||||
columns,
|
||||
disableUnique,
|
||||
@@ -482,6 +504,7 @@ export const traverseFields = ({
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildRelationships,
|
||||
collectionIndexes,
|
||||
columnPrefix,
|
||||
columns,
|
||||
disableUnique,
|
||||
@@ -518,6 +541,7 @@ export const traverseFields = ({
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildRelationships,
|
||||
collectionIndexes,
|
||||
columnPrefix,
|
||||
columns,
|
||||
disableUnique,
|
||||
|
||||
@@ -69,7 +69,7 @@ export type MigrateDownArgs = { payload: Payload }
|
||||
|
||||
declare module 'payload' {
|
||||
export interface DatabaseAdapter extends Args {
|
||||
db: DrizzleDB
|
||||
drizzle: DrizzleDB
|
||||
enums: Record<string, GenericEnum>
|
||||
pool: Pool
|
||||
relations: Record<string, GenericRelation>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import type { Webpack } from 'payload/database'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const webpack: Webpack = (config) => {
|
||||
const aliasPath = path.resolve(__dirname, 'mock.js')
|
||||
|
||||
return {
|
||||
...config,
|
||||
resolve: {
|
||||
...(config.resolve || {}),
|
||||
alias: {
|
||||
...(config.resolve?.alias || {}),
|
||||
'@payloadcms/db-postgres': aliasPath,
|
||||
[path.resolve(__dirname, './index')]: aliasPath,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
2
packages/payload/database.d.ts
vendored
2
packages/payload/database.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
export { BaseDatabaseAdapter, BeginTransaction, CommitTransaction, Connect, Create, CreateArgs, CreateGlobal, CreateGlobalArgs, CreateGlobalVersion, CreateGlobalVersionArgs, CreateMigration, CreateVersion, CreateVersionArgs, DeleteMany, DeleteManyArgs, DeleteOne, DeleteOneArgs, DeleteVersions, DeleteVersionsArgs, Destroy, Find, FindArgs, FindGlobal, FindGlobalArgs, FindGlobalVersions, FindGlobalVersionsArgs, FindOne, FindOneArgs, FindVersions, FindVersionsArgs, Init, Migration, MigrationData, PaginatedDocs, QueryDrafts, QueryDraftsArgs, RollbackTransaction, Transaction, TypeWithVersion, UpdateGlobal, UpdateGlobalArgs, UpdateGlobalVersion, UpdateGlobalVersionArgs, UpdateOne, UpdateOneArgs, UpdateVersion, UpdateVersionArgs, Webpack, } from './dist/database/types';
|
||||
export { BaseDatabaseAdapter, BeginTransaction, CommitTransaction, Connect, Create, CreateArgs, CreateGlobal, CreateGlobalArgs, CreateGlobalVersion, CreateGlobalVersionArgs, CreateMigration, CreateVersion, CreateVersionArgs, DeleteMany, DeleteManyArgs, DeleteOne, DeleteOneArgs, DeleteVersions, DeleteVersionsArgs, Destroy, Find, FindArgs, FindGlobal, FindGlobalArgs, FindGlobalVersions, FindGlobalVersionsArgs, FindOne, FindOneArgs, FindVersions, FindVersionsArgs, Init, Migration, MigrationData, PaginatedDocs, QueryDrafts, QueryDraftsArgs, RollbackTransaction, Transaction, TypeWithVersion, UpdateGlobal, UpdateGlobalArgs, UpdateGlobalVersion, UpdateGlobalVersionArgs, UpdateOne, UpdateOneArgs, UpdateVersion, UpdateVersionArgs, } from './dist/database/types';
|
||||
export * from './dist/database/queryValidation/types';
|
||||
export { combineQueries } from './dist/database/combineQueries';
|
||||
export { createDatabaseAdapter } from './dist/database/createDatabaseAdapter';
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "2.0.0-beta.7",
|
||||
"version": "2.0.0-beta.11",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -105,6 +105,9 @@ export const Routes: React.FC = () => {
|
||||
if (initialized === true && !isLoadingUser) {
|
||||
return (
|
||||
<Switch>
|
||||
<Route path={`${match.url}/create-first-user`}>
|
||||
<Redirect to={`${match.url}/`} />
|
||||
</Route>
|
||||
{customRoutes({
|
||||
canAccessAdmin,
|
||||
customRoutes: customRoutesConfig,
|
||||
|
||||
@@ -9,7 +9,7 @@ import baseAPIKeyFields from '../../auth/baseFields/apiKey'
|
||||
import baseAuthFields from '../../auth/baseFields/auth'
|
||||
import baseVerificationFields from '../../auth/baseFields/verification'
|
||||
import TimestampsRequired from '../../errors/TimestampsRequired'
|
||||
import sanitizeFields from '../../fields/config/sanitize'
|
||||
import { sanitizeFields } from '../../fields/config/sanitize'
|
||||
import { fieldAffectsData } from '../../fields/config/types'
|
||||
import mergeBaseFields from '../../fields/mergeBaseFields'
|
||||
import { extractTranslations } from '../../translations/extractTranslations'
|
||||
@@ -142,7 +142,7 @@ const sanitizeCollection = (
|
||||
// Sanitize fields
|
||||
// /////////////////////////////////
|
||||
|
||||
const validRelationships = config.collections.map((c) => c.slug)
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
sanitized.fields = sanitizeFields({
|
||||
config,
|
||||
fields: sanitized.fields,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
import type { Configuration } from 'webpack'
|
||||
|
||||
import type {
|
||||
BaseDatabaseAdapter,
|
||||
@@ -35,16 +34,6 @@ export function createDatabaseAdapter<T extends BaseDatabaseAdapter>(
|
||||
| 'transaction'
|
||||
>,
|
||||
): T {
|
||||
// Need to implement DB Webpack config extensions here
|
||||
if (args.webpack) {
|
||||
const existingWebpackConfig = args.payload.config.admin.webpack
|
||||
? args.payload.config.admin.webpack
|
||||
: (webpackConfig) => webpackConfig
|
||||
args.payload.config.admin.webpack = (webpackConfig: Configuration) => {
|
||||
return args.webpack(existingWebpackConfig(webpackConfig))
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// Default 'null' transaction functions
|
||||
beginTransaction,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { Configuration } from 'webpack'
|
||||
|
||||
import type { TypeWithID } from '../collections/config/types'
|
||||
import type { TypeWithID as GlobalsTypeWithID } from '../globals/config/types'
|
||||
import type { Payload } from '../payload'
|
||||
@@ -140,10 +138,6 @@ export interface BaseDatabaseAdapter {
|
||||
* assign the transaction to use when making queries, defaults to the last started transaction
|
||||
*/
|
||||
useTransaction?: (id: number | string) => void
|
||||
/**
|
||||
* Used to alias server only modules or make other changes to webpack configuration
|
||||
*/
|
||||
webpack?: Webpack
|
||||
}
|
||||
|
||||
export type Init = (payload: Payload) => Promise<void>
|
||||
@@ -152,8 +146,6 @@ export type Connect = (payload: Payload) => Promise<void>
|
||||
|
||||
export type Destroy = (payload: Payload) => Promise<void>
|
||||
|
||||
export type Webpack = (config: Configuration) => Configuration
|
||||
|
||||
export type CreateMigration = (payload: Payload, migrationName?: string) => Promise<void>
|
||||
|
||||
export type Transaction = (
|
||||
|
||||
@@ -6,3 +6,4 @@ export { defaults } from '../config/defaults'
|
||||
export { sanitizeConfig } from '../config/sanitize'
|
||||
export { baseBlockFields } from '../fields/baseFields/baseBlockFields'
|
||||
export { baseIDField } from '../fields/baseFields/baseIDField'
|
||||
export { sanitizeFields } from '../fields/config/sanitize'
|
||||
|
||||
@@ -46,7 +46,6 @@ export {
|
||||
UpdateOneArgs,
|
||||
UpdateVersion,
|
||||
UpdateVersionArgs,
|
||||
Webpack,
|
||||
} from '../database/types'
|
||||
|
||||
export * from '../database/queryValidation/types'
|
||||
|
||||
@@ -9,7 +9,7 @@ import type {
|
||||
} from './types'
|
||||
import { Config } from '../../config/types'
|
||||
import { InvalidFieldName, InvalidFieldRelationship, MissingFieldType } from '../../errors'
|
||||
import sanitizeFields from './sanitize'
|
||||
import { sanitizeFields } from './sanitize'
|
||||
import { DatabaseAdapter } from '../..'
|
||||
|
||||
const dummyConfig: Config = {
|
||||
|
||||
@@ -12,10 +12,14 @@ import { fieldAffectsData, tabHasName } from './types'
|
||||
type Args = {
|
||||
config: Config
|
||||
fields: Field[]
|
||||
validRelationships: string[]
|
||||
/**
|
||||
* If not null, will validate that upload and relationship fields do not relate to a collection that is not in this array.
|
||||
* This validation will be skipped if validRelationships is null.
|
||||
*/
|
||||
validRelationships: null | string[]
|
||||
}
|
||||
|
||||
const sanitizeFields = ({ config, fields, validRelationships }: Args): Field[] => {
|
||||
export const sanitizeFields = ({ config, fields, validRelationships }: Args): Field[] => {
|
||||
if (!fields) return []
|
||||
|
||||
return fields.map((unsanitizedField) => {
|
||||
@@ -48,12 +52,16 @@ const sanitizeFields = ({ config, fields, validRelationships }: Args): Field[] =
|
||||
}
|
||||
|
||||
if (field.type === 'relationship' || field.type === 'upload') {
|
||||
const relationships = Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo]
|
||||
if (validRelationships) {
|
||||
const relationships = Array.isArray(field.relationTo)
|
||||
? field.relationTo
|
||||
: [field.relationTo]
|
||||
relationships.forEach((relationship: string) => {
|
||||
if (!validRelationships.includes(relationship)) {
|
||||
throw new InvalidFieldRelationship(field, relationship)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (field.type === 'relationship') {
|
||||
if (field.min && !field.minRows) {
|
||||
@@ -155,5 +163,3 @@ const sanitizeFields = ({ config, fields, validRelationships }: Args): Field[] =
|
||||
return field
|
||||
})
|
||||
}
|
||||
|
||||
export default sanitizeFields
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Config } from '../../config/types'
|
||||
import type { SanitizedGlobalConfig } from './types'
|
||||
|
||||
import defaultAccess from '../../auth/defaultAccess'
|
||||
import sanitizeFields from '../../fields/config/sanitize'
|
||||
import { sanitizeFields } from '../../fields/config/sanitize'
|
||||
import { fieldAffectsData } from '../../fields/config/types'
|
||||
import mergeBaseFields from '../../fields/mergeBaseFields'
|
||||
import translations from '../../translations'
|
||||
@@ -92,7 +92,7 @@ const sanitizeGlobals = (config: Config): SanitizedGlobalConfig[] => {
|
||||
})
|
||||
}
|
||||
|
||||
const validRelationships = collections.map((c) => c.slug)
|
||||
const validRelationships = collections.map((c) => c.slug) || []
|
||||
sanitizedGlobal.fields = sanitizeFields({
|
||||
config,
|
||||
fields: sanitizedGlobal.fields,
|
||||
|
||||
@@ -68,8 +68,6 @@ export const BlockContent: React.FC<Props> = (props) => {
|
||||
})
|
||||
}, [editor, nodeKey, collapsed])
|
||||
|
||||
console.log('BLOCK', block)
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Collapsible
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
--font-body
|
||||
); // Reset font to non-serif, body font, as the lexical editor parent uses a serif font.
|
||||
|
||||
margin: 0 0 1.5em;
|
||||
|
||||
&__header {
|
||||
h3 {
|
||||
margin: 0;
|
||||
|
||||
@@ -7,6 +7,9 @@ const baseClass = 'lexical-block'
|
||||
|
||||
import type { Data } from 'payload/types'
|
||||
|
||||
import { useConfig } from 'payload/components/utilities'
|
||||
import { sanitizeFields } from 'payload/config'
|
||||
|
||||
import type { BlocksFeatureProps } from '..'
|
||||
|
||||
import { useEditorConfigContext } from '../../../lexical/config/EditorConfigProvider'
|
||||
@@ -23,6 +26,7 @@ type Props = {
|
||||
|
||||
export const BlockComponent: React.FC<Props> = (props) => {
|
||||
const { children, className, fields, format, nodeKey } = props
|
||||
const payloadConfig = useConfig()
|
||||
|
||||
const { editorConfig, field } = useEditorConfigContext()
|
||||
|
||||
@@ -30,6 +34,14 @@ export const BlockComponent: React.FC<Props> = (props) => {
|
||||
editorConfig?.resolvedFeatureMap?.get('blocks')?.props as BlocksFeatureProps
|
||||
)?.blocks?.find((block) => block.slug === fields?.data?.blockType)
|
||||
|
||||
// Sanitize block's fields here. This is done here and not in the feature, because the payload config is available here
|
||||
const validRelationships = payloadConfig.collections.map((c) => c.slug) || []
|
||||
block.fields = sanitizeFields({
|
||||
config: payloadConfig,
|
||||
fields: block.fields,
|
||||
validRelationships,
|
||||
})
|
||||
|
||||
const initialDataRef = React.useRef<Data>(buildInitialState(fields.data || {})) // Store initial value in a ref, so it doesn't change on re-render and only gets initialized once
|
||||
|
||||
// Memoized Form JSX
|
||||
|
||||
@@ -30,12 +30,8 @@ export const BlocksFeature = (props?: BlocksFeatureProps): FeatureProvider => {
|
||||
? formatLabels(unsanitizedBlock.slug)
|
||||
: unsanitizedBlock.labels
|
||||
|
||||
// TODO
|
||||
/*unsanitizedBlock.fields = sanitizeFields({
|
||||
config,
|
||||
fields: block.fields,
|
||||
validRelationships,
|
||||
})*/
|
||||
// unsanitizedBlock.fields are sanitized in the React component and not here.
|
||||
// That's because we do not have access to the payload config here.
|
||||
|
||||
return unsanitizedBlock
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
html[data-theme='light'] {
|
||||
.link-editor {
|
||||
box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.2);
|
||||
@include shadow-m;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ html[data-theme='light'] {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
position: relative;
|
||||
font-family: inherit;
|
||||
font-family: var(--font-body);
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
|
||||
@@ -101,6 +101,7 @@ const Component: React.FC<Props> = (props) => {
|
||||
<div className={`${baseClass}__actions`}>
|
||||
<Button
|
||||
buttonStyle="icon-label"
|
||||
className={`${baseClass}__swapButton`}
|
||||
disabled={field?.admin?.readOnly}
|
||||
el="div"
|
||||
icon="swap"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
border: 1px solid var(--theme-elevation-100);
|
||||
max-width: base(15);
|
||||
font-family: var(--font-body);
|
||||
margin: 0 0 1.5em;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid var(--theme-elevation-150);
|
||||
@@ -56,7 +57,14 @@
|
||||
& > * {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__swapButton {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__doc-drawer-toggler,
|
||||
&__swapButton {
|
||||
&:disabled {
|
||||
color: var(--theme-elevation-300);
|
||||
pointer-events: none;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
border: 1px solid var(--theme-elevation-100);
|
||||
position: relative;
|
||||
font-family: var(--font-body);
|
||||
margin: 0 0 1.5em;
|
||||
|
||||
.btn {
|
||||
margin: 0;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
@import 'payload/scss';
|
||||
|
||||
.editor-upload {
|
||||
}
|
||||
@@ -12,8 +12,6 @@ import {
|
||||
} from 'lexical'
|
||||
import * as React from 'react'
|
||||
|
||||
import { UploadFeatureProps } from '..'
|
||||
|
||||
// @ts-expect-error TypeScript being dumb
|
||||
const RawUploadComponent = React.lazy(async () => await import('../component'))
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ html[data-theme='light'] {
|
||||
.floating-select-toolbar-popup__dropdown {
|
||||
&--items {
|
||||
position: absolute;
|
||||
box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.2);
|
||||
@include shadow-m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
html[data-theme='light'] {
|
||||
.floating-select-toolbar-popup {
|
||||
box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.2);
|
||||
@include shadow-m;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -527,11 +527,17 @@ export function useMenuAnchorRef(
|
||||
if (left + menuWidth > rootElementRect.right) {
|
||||
containerDiv.style.left = `${rootElementRect.right - menuWidth + window.scrollX}px`
|
||||
}
|
||||
const margin = 10
|
||||
|
||||
const wouldGoOffTopOfScreen = top < menuHeight
|
||||
const wouldGoOffBottomOfContainer = top + menuHeight > rootElementRect.bottom
|
||||
|
||||
// Position slash menu above the cursor instead of below (default) if it would otherwise go off the bottom of the screen.
|
||||
if (
|
||||
(top + menuHeight > window.innerHeight || top + menuHeight > rootElementRect.bottom) &&
|
||||
(top + menuHeight > window.innerHeight ||
|
||||
(wouldGoOffBottomOfContainer && !wouldGoOffTopOfScreen)) &&
|
||||
top - rootElementRect.top > menuHeight
|
||||
) {
|
||||
const margin = 24
|
||||
containerDiv.style.top = `${
|
||||
top + VERTICAL_OFFSET - menuHeight + window.scrollY - (height + margin)
|
||||
}px`
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import type { LexicalCommand, LexicalEditor, RangeSelection, TextNode } from 'lexical'
|
||||
import type {
|
||||
LexicalCommand,
|
||||
LexicalEditor,
|
||||
ParagraphNode,
|
||||
RangeSelection,
|
||||
TextNode,
|
||||
} from 'lexical'
|
||||
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { mergeRegister } from '@lexical/utils'
|
||||
@@ -53,7 +59,8 @@ function tryToPositionRange(leadOffset: number, range: Range, editorWindow: Wind
|
||||
|
||||
try {
|
||||
range.setStart(anchorNode, startOffset)
|
||||
range.setEnd(anchorNode, endOffset)
|
||||
// if endOffset is 0, positioning the range for when you click the plus button to open the slash menu will fial
|
||||
range.setEnd(anchorNode, endOffset > 1 ? endOffset : 1)
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
@@ -176,7 +183,7 @@ export type TypeaheadMenuPluginProps = {
|
||||
}
|
||||
|
||||
export const ENABLE_SLASH_MENU_COMMAND: LexicalCommand<{
|
||||
rect: DOMRect
|
||||
node: ParagraphNode
|
||||
}> = createCommand('ENABLE_SLASH_MENU_COMMAND')
|
||||
|
||||
export function LexicalTypeaheadMenuPlugin({
|
||||
@@ -215,7 +222,7 @@ export function LexicalTypeaheadMenuPlugin({
|
||||
return mergeRegister(
|
||||
editor.registerCommand(
|
||||
ENABLE_SLASH_MENU_COMMAND,
|
||||
({ rect }) => {
|
||||
({ node }) => {
|
||||
editor.getEditorState().read(() => {
|
||||
const match: MenuTextMatch = {
|
||||
leadOffset: 0,
|
||||
@@ -223,15 +230,22 @@ export function LexicalTypeaheadMenuPlugin({
|
||||
replaceableString: '',
|
||||
}
|
||||
if (match !== null && !isSelectionOnEntityBoundary(editor, match.leadOffset)) {
|
||||
if (rect !== null) {
|
||||
if (node !== null) {
|
||||
const editorWindow = editor._window ?? window
|
||||
const range = editorWindow.document.createRange()
|
||||
|
||||
const isRangePositioned = tryToPositionRange(match.leadOffset, range, editorWindow)
|
||||
if (isRangePositioned !== null) {
|
||||
startTransition(() =>
|
||||
openTypeahead({
|
||||
getRect: () => {
|
||||
return rect
|
||||
return range.getBoundingClientRect()
|
||||
},
|
||||
match,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -270,7 +284,9 @@ export function LexicalTypeaheadMenuPlugin({
|
||||
if (isRangePositioned !== null) {
|
||||
startTransition(() =>
|
||||
openTypeahead({
|
||||
getRect: () => range.getBoundingClientRect(),
|
||||
getRect: () => {
|
||||
return range.getBoundingClientRect()
|
||||
},
|
||||
match,
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
html[data-theme='light'] {
|
||||
.slash-menu {
|
||||
box-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.2);
|
||||
@include shadow-m;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ html[data-theme='light'] {
|
||||
color: var(--color-base-800);
|
||||
border-radius: 4px;
|
||||
list-style: none;
|
||||
font-family: var(--font-body);
|
||||
max-height: 300px;
|
||||
overflow-y: scroll;
|
||||
|
||||
.group {
|
||||
padding-bottom: 8px;
|
||||
@@ -24,7 +27,10 @@ html[data-theme='light'] {
|
||||
}
|
||||
|
||||
.item {
|
||||
padding-left: 8px;
|
||||
all: unset;
|
||||
padding-left: 12px;
|
||||
font-size: 13px;
|
||||
box-sizing: border-box;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-base-900);
|
||||
|
||||
@@ -239,9 +239,9 @@ function useAddBlockHandle(
|
||||
if (!emptyBlockElem) {
|
||||
return
|
||||
}
|
||||
|
||||
let node: ParagraphNode
|
||||
editor.update(() => {
|
||||
const node: ParagraphNode = $getNearestNodeFromDOMNode(emptyBlockElem) as ParagraphNode
|
||||
node = $getNearestNodeFromDOMNode(emptyBlockElem) as ParagraphNode
|
||||
if (!node || node.getType() !== 'paragraph') {
|
||||
return
|
||||
}
|
||||
@@ -257,7 +257,7 @@ function useAddBlockHandle(
|
||||
// Otherwise, this won't work
|
||||
setTimeout(() => {
|
||||
editor.dispatchCommand(ENABLE_SLASH_MENU_COMMAND, {
|
||||
rect: emptyBlockElem.getBoundingClientRect(),
|
||||
node: node,
|
||||
})
|
||||
}, 0)
|
||||
|
||||
|
||||
26
scripts/release_beta.sh
Executable file
26
scripts/release_beta.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
# Build packages/payload
|
||||
|
||||
package_name=$1
|
||||
package_dir="packages/$package_name"
|
||||
|
||||
if [ -z "$package_name" ]; then
|
||||
echo "Please specify a package to publish"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if packages/$package_name exists
|
||||
|
||||
if [ ! -d "$package_dir" ]; then
|
||||
echo "Package $package_name does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
npm --prefix "$package_dir" version pre --preid beta
|
||||
git add "$package_dir"/package.json
|
||||
new_version=$(node -p "require('./$package_dir/package.json').version")
|
||||
git commit -m "chore(release): $package_name@$new_version"
|
||||
pnpm publish -C "$package_dir" --tag beta --no-git-checks
|
||||
@@ -76,11 +76,11 @@ export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<S
|
||||
...existingConfig.resolve?.alias,
|
||||
[path.resolve(__dirname, '../packages/db-postgres/src/index')]: path.resolve(
|
||||
__dirname,
|
||||
'../packages/db-postgres/src/mock.js',
|
||||
'../packages/db-postgres/mock.js',
|
||||
),
|
||||
[path.resolve(__dirname, '../packages/db-mongodb/src/index')]: path.resolve(
|
||||
__dirname,
|
||||
'../packages/db-mongodb/src/mock.js',
|
||||
'../packages/db-mongodb/mock.js',
|
||||
),
|
||||
[path.resolve(__dirname, '../packages/bundler-webpack/src/index')]: path.resolve(
|
||||
__dirname,
|
||||
@@ -88,7 +88,7 @@ export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<S
|
||||
),
|
||||
[path.resolve(__dirname, '../packages/bundler-vite/src/index')]: path.resolve(
|
||||
__dirname,
|
||||
'../packages/bundler-vite/src/mock.js',
|
||||
'../packages/bundler-vite/mock.js',
|
||||
),
|
||||
react: path.resolve(__dirname, '../packages/payload/node_modules/react'),
|
||||
},
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('Fields', () => {
|
||||
;({ serverURL } = await initPayloadTest({ __dirname, init: { local: false } }))
|
||||
config = await configPromise
|
||||
|
||||
client = new RESTClient(config, { serverURL, defaultSlug: 'point-fields' })
|
||||
client = new RESTClient(config, { defaultSlug: 'point-fields', serverURL })
|
||||
const graphQLURL = `${serverURL}${config.routes.api}${config.routes.graphQL}`
|
||||
graphQLClient = new GraphQLClient(graphQLURL)
|
||||
token = await client.login()
|
||||
@@ -64,7 +64,7 @@ describe('Fields', () => {
|
||||
})
|
||||
|
||||
it('should populate default values in beforeValidate hook', async () => {
|
||||
const { fieldWithDefaultValue, dependentOnFieldWithDefaultValue } = await payload.create({
|
||||
const { dependentOnFieldWithDefaultValue, fieldWithDefaultValue } = await payload.create({
|
||||
collection: 'text-fields',
|
||||
data: { text },
|
||||
})
|
||||
@@ -89,10 +89,6 @@ describe('Fields', () => {
|
||||
depth: 0,
|
||||
where: {
|
||||
updatedAt: {
|
||||
// TODO:
|
||||
// drizzle is not adjusting for timezones
|
||||
// tenMinutesAgo: "2023-08-29T15:49:39.897Z" UTC
|
||||
// doc.updatedAt: "2023-08-29T11:59:43.738Z" GMT -4
|
||||
greater_than_equal: tenMinutesAgo,
|
||||
},
|
||||
},
|
||||
@@ -121,15 +117,15 @@ describe('Fields', () => {
|
||||
beforeAll(async () => {
|
||||
const { id } = await payload.create({
|
||||
collection: 'select-fields',
|
||||
locale: 'en',
|
||||
data: {
|
||||
selectHasManyLocalized: ['one', 'two'],
|
||||
},
|
||||
locale: 'en',
|
||||
})
|
||||
doc = await payload.findByID({
|
||||
id,
|
||||
collection: 'select-fields',
|
||||
locale: 'all',
|
||||
id,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -146,8 +142,8 @@ describe('Fields', () => {
|
||||
})
|
||||
|
||||
const updatedDoc = await payload.update({
|
||||
collection: 'select-fields',
|
||||
id,
|
||||
collection: 'select-fields',
|
||||
data: {
|
||||
select: 'one',
|
||||
},
|
||||
@@ -245,15 +241,15 @@ describe('Fields', () => {
|
||||
const localizedHasMany = [5, 10]
|
||||
const { id } = await payload.create({
|
||||
collection: 'number-fields',
|
||||
locale: 'en',
|
||||
data: {
|
||||
localizedHasMany,
|
||||
},
|
||||
locale: 'en',
|
||||
})
|
||||
const localizedDoc = await payload.findByID({
|
||||
id,
|
||||
collection: 'number-fields',
|
||||
locale: 'all',
|
||||
id,
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
@@ -284,81 +280,44 @@ describe('Fields', () => {
|
||||
it('should have indexes', () => {
|
||||
expect(definitions.text).toEqual(1)
|
||||
})
|
||||
|
||||
it('should have unique indexes', () => {
|
||||
expect(definitions.uniqueText).toEqual(1)
|
||||
expect(options.uniqueText).toMatchObject({ unique: true })
|
||||
})
|
||||
it('should have 2dsphere indexes on point fields', () => {
|
||||
expect(definitions.point).toEqual('2dsphere')
|
||||
})
|
||||
it('should have 2dsphere indexes on point fields in groups', () => {
|
||||
expect(definitions['group.point']).toEqual('2dsphere')
|
||||
})
|
||||
it('should have a sparse index on a unique localized field in a group', () => {
|
||||
expect(definitions['group.localizedUnique.en']).toEqual(1)
|
||||
expect(options['group.localizedUnique.en']).toMatchObject({ unique: true, sparse: true })
|
||||
expect(definitions['group.localizedUnique.es']).toEqual(1)
|
||||
expect(options['group.localizedUnique.es']).toMatchObject({ unique: true, sparse: true })
|
||||
})
|
||||
it('should have unique indexes in a collapsible', () => {
|
||||
expect(definitions['collapsibleLocalizedUnique.en']).toEqual(1)
|
||||
expect(options['collapsibleLocalizedUnique.en']).toMatchObject({
|
||||
unique: true,
|
||||
sparse: true,
|
||||
})
|
||||
expect(definitions.collapsibleTextUnique).toEqual(1)
|
||||
expect(options.collapsibleTextUnique).toMatchObject({ unique: true })
|
||||
})
|
||||
|
||||
it('should have unique compound indexes', () => {
|
||||
expect(definitions.partOne).toEqual(1)
|
||||
expect(options.partOne).toMatchObject({
|
||||
unique: true,
|
||||
name: 'compound-index',
|
||||
sparse: true,
|
||||
unique: true,
|
||||
})
|
||||
})
|
||||
it('should throw validation error saving on unique fields', async () => {
|
||||
const data = {
|
||||
text: 'a',
|
||||
uniqueText: 'a',
|
||||
}
|
||||
await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data,
|
||||
|
||||
it('should have 2dsphere indexes on point fields', () => {
|
||||
expect(definitions.point).toEqual('2dsphere')
|
||||
})
|
||||
expect(async () => {
|
||||
const result = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data,
|
||||
|
||||
it('should have 2dsphere indexes on point fields in groups', () => {
|
||||
expect(definitions['group.point']).toEqual('2dsphere')
|
||||
})
|
||||
return result.error
|
||||
}).toBeDefined()
|
||||
|
||||
it('should have a sparse index on a unique localized field in a group', () => {
|
||||
expect(definitions['group.localizedUnique.en']).toEqual(1)
|
||||
expect(options['group.localizedUnique.en']).toMatchObject({ sparse: true, unique: true })
|
||||
expect(definitions['group.localizedUnique.es']).toEqual(1)
|
||||
expect(options['group.localizedUnique.es']).toMatchObject({ sparse: true, unique: true })
|
||||
})
|
||||
it('should throw validation error saving on unique combined fields', async () => {
|
||||
await payload.delete({ collection: 'indexed-fields', where: {} })
|
||||
const data1 = {
|
||||
text: 'a',
|
||||
uniqueText: 'a',
|
||||
partOne: 'u',
|
||||
partTwo: 'u',
|
||||
}
|
||||
const data2 = {
|
||||
text: 'b',
|
||||
uniqueText: 'b',
|
||||
partOne: 'u',
|
||||
partTwo: 'u',
|
||||
}
|
||||
await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data: data1,
|
||||
|
||||
it('should have unique indexes in a collapsible', () => {
|
||||
expect(definitions['collapsibleLocalizedUnique.en']).toEqual(1)
|
||||
expect(options['collapsibleLocalizedUnique.en']).toMatchObject({
|
||||
sparse: true,
|
||||
unique: true,
|
||||
})
|
||||
expect(async () => {
|
||||
const result = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data: data2,
|
||||
})
|
||||
return result.error
|
||||
}).toBeDefined()
|
||||
expect(definitions.collapsibleTextUnique).toEqual(1)
|
||||
expect(options.collapsibleTextUnique).toMatchObject({ unique: true })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -386,9 +345,9 @@ describe('Fields', () => {
|
||||
it('should have version indexes from collection indexes', () => {
|
||||
expect(definitions['version.partOne']).toEqual(1)
|
||||
expect(options['version.partOne']).toMatchObject({
|
||||
unique: true,
|
||||
name: 'compound-index',
|
||||
sparse: true,
|
||||
unique: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -424,9 +383,9 @@ describe('Fields', () => {
|
||||
doc = await payload.create({
|
||||
collection: 'point-fields',
|
||||
data: {
|
||||
point,
|
||||
localized,
|
||||
group,
|
||||
localized,
|
||||
point,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -440,9 +399,9 @@ describe('Fields', () => {
|
||||
payload.create({
|
||||
collection: 'point-fields',
|
||||
data: {
|
||||
point,
|
||||
localized,
|
||||
group,
|
||||
localized,
|
||||
point,
|
||||
},
|
||||
}),
|
||||
).rejects.toThrow(Error)
|
||||
@@ -463,6 +422,52 @@ describe('Fields', () => {
|
||||
})
|
||||
}
|
||||
|
||||
describe('unique indexes', () => {
|
||||
it('should throw validation error saving on unique fields', async () => {
|
||||
const data = {
|
||||
text: 'a',
|
||||
uniqueText: 'a',
|
||||
}
|
||||
await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data,
|
||||
})
|
||||
expect(async () => {
|
||||
const result = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data,
|
||||
})
|
||||
return result.error
|
||||
}).toBeDefined()
|
||||
})
|
||||
it('should throw validation error saving on unique combined fields', async () => {
|
||||
await payload.delete({ collection: 'indexed-fields', where: {} })
|
||||
const data1 = {
|
||||
partOne: 'u',
|
||||
partTwo: 'u',
|
||||
text: 'a',
|
||||
uniqueText: 'a',
|
||||
}
|
||||
const data2 = {
|
||||
partOne: 'u',
|
||||
partTwo: 'u',
|
||||
text: 'b',
|
||||
uniqueText: 'b',
|
||||
}
|
||||
await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data: data1,
|
||||
})
|
||||
expect(async () => {
|
||||
const result = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data: data2,
|
||||
})
|
||||
return result.error
|
||||
}).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('array', () => {
|
||||
let doc
|
||||
const collection = arrayFieldsSlug
|
||||
@@ -499,26 +504,26 @@ describe('Fields', () => {
|
||||
})
|
||||
|
||||
const enDoc = await payload.update({
|
||||
collection,
|
||||
id,
|
||||
locale: 'en',
|
||||
collection,
|
||||
data: {
|
||||
localized: [{ text: enText }],
|
||||
},
|
||||
locale: 'en',
|
||||
})
|
||||
|
||||
const esDoc = await payload.update({
|
||||
collection,
|
||||
id,
|
||||
locale: 'es',
|
||||
collection,
|
||||
data: {
|
||||
localized: [{ text: esText }],
|
||||
},
|
||||
locale: 'es',
|
||||
})
|
||||
|
||||
const allLocales = (await payload.findByID({
|
||||
collection,
|
||||
id,
|
||||
collection,
|
||||
locale: 'all',
|
||||
})) as unknown as { localized: { en: unknown; es: unknown } }
|
||||
|
||||
@@ -569,8 +574,8 @@ describe('Fields', () => {
|
||||
|
||||
it('should create with localized text inside a named tab', async () => {
|
||||
document = await payload.findByID({
|
||||
collection: tabsSlug,
|
||||
id: document.id,
|
||||
collection: tabsSlug,
|
||||
locale: 'all',
|
||||
})
|
||||
expect(document.localizedTab.en.text).toStrictEqual(localizedTextValue)
|
||||
@@ -578,8 +583,8 @@ describe('Fields', () => {
|
||||
|
||||
it('should allow access control on a named tab', async () => {
|
||||
document = await payload.findByID({
|
||||
collection: tabsSlug,
|
||||
id: document.id,
|
||||
collection: tabsSlug,
|
||||
overrideAccess: false,
|
||||
})
|
||||
expect(document.accessControlTab).toBeUndefined()
|
||||
@@ -735,8 +740,8 @@ describe('Fields', () => {
|
||||
expect(jsonFieldsDoc.json.state).toEqual({})
|
||||
|
||||
const updatedJsonFieldsDoc = await payload.update({
|
||||
collection: 'json-fields',
|
||||
id: jsonFieldsDoc.id,
|
||||
collection: 'json-fields',
|
||||
data: {
|
||||
json: {
|
||||
state: {},
|
||||
@@ -800,8 +805,8 @@ describe('Fields', () => {
|
||||
expect(nodes).toBeDefined()
|
||||
const child = nodes.flatMap((n) => n.children).find((c) => c.doc)
|
||||
expect(child).toMatchObject({
|
||||
type: 'link',
|
||||
linkType: 'internal',
|
||||
type: 'link',
|
||||
})
|
||||
expect(child.doc.relationTo).toEqual('array-fields')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user