Compare commits

..

21 Commits

Author SHA1 Message Date
Dan Ribbens
ba2702cfca chore(release): v3.0.0-alpha.45 [skip ci] 2024-03-11 14:53:31 -04:00
James
eba1f6327d Merge branch 'alpha' of github.com:payloadcms/payload into alpha 2024-03-11 14:41:37 -04:00
James Mikrut
1ba0b4037c Merge pull request #5293 from payloadcms/fix/auth-schema-and-client-side
fix (alpha): `auth.strategies` schema and removal of auth functions from client config
2024-03-11 14:40:43 -04:00
James
49daa75bc4 chore: fixes race condition in payload hmr 2024-03-11 14:39:41 -04:00
PatrikKozak
fea1eb1149 fix: removes auth strategies & forgotPassword & verify functions from client side 2024-03-11 13:56:50 -04:00
PatrikKozak
9a58f6c454 fix: updates auth schema to match updated auth types 2024-03-11 13:54:54 -04:00
James
66cefe6bb5 chore: removes auth cache, sets overrideAccess false 2024-03-11 12:21:13 -04:00
Jarrod Flesch
23510acf40 chore: sets bg on templates (#5289) 2024-03-10 23:10:37 -04:00
Jarrod Flesch
faa49f36e7 fix(alpha): correctly set redirect route when logout is triggered (#5288) 2024-03-10 22:35:06 -04:00
James
a5fb8b20a1 Merge branch 'alpha' of github.com:payloadcms/payload into alpha 2024-03-10 22:18:56 -04:00
James
e14b303609 chore: int tests 2024-03-10 22:18:48 -04:00
Dan Ribbens
2ec3df6680 chore(release): v3.0.0-alpha.44 [skip ci] 2024-03-10 22:07:16 -04:00
Elliot DeNolf
1f4b6001ef chore: run eslint on pre-commit hook 2024-03-10 22:01:15 -04:00
James
6e7c9cc6a3 Merge branch 'alpha' of github.com:payloadcms/payload into alpha 2024-03-10 21:56:06 -04:00
James
2db385c6a5 chore: requires drizzle-kit within func 2024-03-10 21:54:31 -04:00
Elliot DeNolf
bd27f48eae test: remove component test suite 2024-03-10 21:19:04 -04:00
Dan Ribbens
98a33250f6 chore(release): v3.0.0-alpha.43 [skip ci] 2024-03-10 21:11:46 -04:00
Elliot DeNolf
8f9729a928 ci: remove component tests 2024-03-10 21:10:19 -04:00
James
1a8564bc35 chore: safely import drizzle-kit 2024-03-10 19:03:15 -04:00
James
76c9632417 Merge branch 'alpha' of github.com:payloadcms/payload into alpha 2024-03-10 18:18:32 -04:00
James
2370361b43 chore: stops excluding pino and pino-pretty in webpack config 2024-03-10 18:17:57 -04:00
37 changed files with 108 additions and 261 deletions

View File

@@ -196,9 +196,6 @@ jobs:
echo "POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres" >> $GITHUB_ENV
if: matrix.database == 'supabase'
- name: Component Tests
run: pnpm test:components
- name: Integration Tests
run: pnpm test:int
env:

View File

@@ -1,16 +0,0 @@
module.exports = {
moduleNameMapper: {
'\\.(css|scss)$': '<rootDir>/packages/payload/src/bundlers/mocks/emptyModule.js',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/packages/payload/src/bundlers/mocks/fileMock.js',
},
setupFilesAfterEnv: ['./test/componentsSetup.js'],
testEnvironment: 'jsdom',
testPathIgnorePatterns: ['node_modules', 'dist'],
testRegex: '(/src/admin/.*\\.(test|spec))\\.[jt]sx?$',
testTimeout: 15000,
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest'],
},
verbose: true,
}

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"private": true,
"type": "module",
"workspaces:": [
@@ -157,7 +157,8 @@
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write"
"prettier --write",
"eslint --cache --fix"
]
},
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"description": "The officially supported MongoDB database adapter for Payload - Update 2",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"description": "The officially supported Postgres database adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -3,10 +3,13 @@ import type { DrizzleSnapshotJSON } from 'drizzle-kit/payload'
import type { CreateMigration } from 'payload/database'
import fs from 'fs'
import { createRequire } from 'module'
import prompts from 'prompts'
import type { PostgresAdapter } from './types.js'
const require = createRequire(import.meta.url)
const migrationTemplate = (
upSQL?: string,
downSQL?: string,
@@ -60,7 +63,7 @@ export const createMigration: CreateMigration = async function createMigration(
fs.mkdirSync(dir)
}
const { generateDrizzleJson, generateMigration } = await import('drizzle-kit/payload')
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/payload')
const [yyymmdd, hhmmss] = new Date().toISOString().split('T')
const formattedDate = yyymmdd.replace(/\D/g, '')

View File

@@ -3,6 +3,7 @@ import type { Payload } from 'payload'
import type { Migration } from 'payload/database'
import type { PayloadRequest } from 'payload/types'
import { createRequire } from 'module'
import {
commitTransaction,
initTransaction,
@@ -17,6 +18,8 @@ import { createMigrationTable } from './utilities/createMigrationTable.js'
import { migrationTableExists } from './utilities/migrationTableExists.js'
import { parseError } from './utilities/parseError.js'
const require = createRequire(import.meta.url)
export async function migrate(this: PostgresAdapter): Promise<void> {
const { payload } = this
const migrationFiles = await readMigrationFiles({ payload })
@@ -82,7 +85,7 @@ export async function migrate(this: PostgresAdapter): Promise<void> {
}
async function runMigrationFile(payload: Payload, migration: Migration, batch: number) {
const { generateDrizzleJson } = await import('drizzle-kit/payload')
const { generateDrizzleJson } = require('drizzle-kit/payload')
const start = Date.now()
const req = { payload } as PayloadRequest

View File

@@ -1,10 +1,11 @@
import { eq } from 'drizzle-orm'
import { numeric, timestamp, varchar } from 'drizzle-orm/pg-core'
import { createRequire } from 'module'
import prompts from 'prompts'
import type { PostgresAdapter } from '../types.js'
const { pushSchema } = await import('drizzle-kit/payload')
const require = createRequire(import.meta.url)
/**
* Pushes the development schema to the database using Drizzle.
@@ -13,6 +14,8 @@ const { pushSchema } = await import('drizzle-kit/payload')
* @returns {Promise<void>} - A promise that resolves once the schema push is complete.
*/
export const pushDevSchema = async (db: PostgresAdapter) => {
const { pushSchema } = require('drizzle-kit/payload')
// This will prompt if clarifications are needed for Drizzle to push new schema
const { apply, hasDataLoss, statementsToExecute, warnings } = await pushSchema(
db.schema,

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/graphql",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"main": "./src/index.ts",
"types": "./src/index.d.ts",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/next",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"main": "./src/index.ts",
"types": "./src/index.d.ts",
"type": "module",

View File

@@ -38,7 +38,7 @@ export const RootLayout = async ({
const payload = await getPayload({ config: configPromise })
const { cookies, permissions, user } = await auth({
const { cookies, permissions } = await auth({
headers,
payload,
})

View File

@@ -1,34 +1,36 @@
import type { Payload, PayloadRequest } from 'payload/types'
import { getAccessResults, getAuthenticatedUser, parseCookies } from 'payload/auth'
import { cache } from 'react'
export const auth = cache(
async ({ headers, payload }: { headers: Request['headers']; payload: Payload }) => {
const cookies = parseCookies(headers)
type Args = {
headers: Request['headers']
payload: Payload
}
const user = await getAuthenticatedUser({
cookies,
export const auth = async ({ headers, payload }: Args) => {
const cookies = parseCookies(headers)
const user = await getAuthenticatedUser({
cookies,
headers,
payload,
})
const permissions = await getAccessResults({
req: {
context: {},
headers,
i18n: undefined,
payload,
})
const permissions = await getAccessResults({
req: {
context: {},
headers,
i18n: undefined,
payload,
payloadAPI: 'REST',
t: undefined,
user,
} as PayloadRequest,
})
return {
cookies,
permissions,
payloadAPI: 'REST',
t: undefined,
user,
}
},
)
} as PayloadRequest,
})
return {
cookies,
permissions,
user,
}
}

View File

@@ -8,7 +8,7 @@ let cached = global._payload
if (!cached) {
// eslint-disable-next-line no-multi-assign
cached = global._payload = { payload: null, promise: null }
cached = global._payload = { payload: null, promise: null, reload: false }
}
export const getPayload = async (options: InitOptions): Promise<Payload> => {
@@ -19,8 +19,11 @@ export const getPayload = async (options: InitOptions): Promise<Payload> => {
if (cached.payload) {
const config = await options.config
if (cached.reload) {
cached.reload = false
if (cached.reload === true) {
let resolve
cached.reload = new Promise((res) => (resolve = res))
if (typeof cached.payload.db.destroy === 'function') {
await cached.payload.db.destroy()
}
@@ -37,6 +40,11 @@ export const getPayload = async (options: InitOptions): Promise<Payload> => {
await cached.payload.db.init()
await cached.payload.db.connect({ hotReload: true })
resolve()
}
if (cached.reload instanceof Promise) {
await cached.reload
}
return cached.payload

View File

@@ -22,8 +22,8 @@ export { generateAccountMetadata } from './meta.js'
export const Account: React.FC<AdminViewProps> = async ({ initPageResult, searchParams }) => {
const {
permissions,
locale,
permissions,
req: {
i18n,
payload,
@@ -53,6 +53,7 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
id: user.id,
collection: userSlug,
depth: 0,
overrideAccess: false,
user,
})
} catch (error) {

View File

@@ -106,6 +106,7 @@ export const Document: React.FC<AdminViewProps> = async ({
collection: collectionSlug,
depth: 0,
locale: locale.code,
overrideAccess: false,
user,
})
} catch (error) {} // eslint-disable-line no-empty
@@ -148,6 +149,7 @@ export const Document: React.FC<AdminViewProps> = async ({
slug: globalSlug,
depth: 0,
locale: locale.code,
overrideAccess: false,
user,
})
} catch (error) {} // eslint-disable-line no-empty

View File

@@ -1,172 +0,0 @@
import { render } from '@testing-library/react'
import React from 'react'
import type { BlockField, DateField, SelectField } from 'payload/types'
import { BlocksCell } from './fields/Blocks'
import { Checkbox } from './fields/Checkbox'
import { DateCell } from './fields/Date'
import { Select } from './fields/Select'
import { Textarea } from './fields/Textarea'
jest.mock('../../../../utilities/Config', () => ({
useConfig: () => ({ admin: { dateFormat: 'MMMM do yyyy, h:mm a' } }),
}))
jest.mock('../../../../providers/Translation', () => ({
useTranslation: () => ({ t: (string) => string }),
}))
describe('Cell Types', () => {
describe('Blocks', () => {
const field: BlockField = {
blocks: [
{
fields: [],
labels: {
plural: 'Numbers',
singular: 'Number',
},
slug: 'number',
},
],
label: 'Blocks Content',
labels: {
plural: 'Blocks Content',
singular: 'Block',
},
name: 'blocks',
type: 'blocks',
}
it('renders multiple', () => {
const data = [{ blockType: 'number' }, { blockType: 'number' }]
const { container } = render(<BlocksCell data={data} field={field} />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('2 Blocks Content - Number, Number')
})
it('renders zero', () => {
const data = []
const { container } = render(<BlocksCell data={data} field={field} />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('0 Blocks Content')
})
it('renders "and X more" if over maximum of 5', () => {
const data = [
{ blockType: 'number' },
{ blockType: 'number' },
{ blockType: 'number' },
{ blockType: 'number' },
{ blockType: 'number' },
{ blockType: 'number' },
]
const { container } = render(<BlocksCell data={data} field={field} />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('fields:itemsAndMore')
})
})
describe('Date', () => {
const field: DateField = {
admin: {
date: {
pickerAppearance: 'dayOnly',
},
},
name: 'dayOnly',
type: 'date',
}
it('renders date', () => {
const timeStamp = '2020-10-06T14:07:39.033Z'
const { container } = render(<DateCell data={timeStamp} field={field} />)
const dateMatch = /October\s6th\s2020,\s\d{1,2}:07\s[A|P]M/ // Had to account for timezones in CI
const el = container.querySelector('span')
expect(el.textContent).toMatch(dateMatch)
})
it('handles undefined', () => {
const timeStamp = undefined
const { container } = render(<DateCell data={timeStamp} field={field} />)
const el = container.querySelector('span')
expect(el.textContent).toBe('')
})
})
describe('Checkbox', () => {
it('renders true', () => {
const { container } = render(<Checkbox data />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('true')
})
it('renders false', () => {
const { container } = render(<Checkbox data={false} />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('false')
})
})
describe('Textarea', () => {
it('renders data', () => {
const { container } = render(<Textarea data="data" />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('data')
})
it('handle undefined - bug/13', () => {
const { container } = render(<Textarea data={undefined} />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('')
})
})
describe('Select', () => {
const fieldWithOptionsObject: SelectField = {
name: 'selectObject',
options: [
{
label: 'One',
value: 'one',
},
{
label: 'Two',
value: 'two',
},
],
type: 'select',
}
const fieldWithStringsOptions: SelectField = {
name: 'selectString',
options: ['blue', 'green', 'yellow'],
type: 'select',
}
it('renders options objects', () => {
const { container } = render(<Select data="one" field={fieldWithOptionsObject} />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('One')
})
it('renders option strings', () => {
const { container } = render(<Select data="blue" field={fieldWithStringsOptions} />)
const el = container.querySelector('span')
expect(el).toHaveTextContent('blue')
})
describe('HasMany', () => {
it('renders options objects', () => {
const { container } = render(
<Select data={['one', 'two']} field={fieldWithOptionsObject} />,
)
const el = container.querySelector('span')
expect(el).toHaveTextContent('One, Two')
})
it('renders option strings', () => {
const { container } = render(
<Select data={['blue', 'green']} field={fieldWithStringsOptions} />,
)
const el = container.querySelector('span')
expect(el).toHaveTextContent('blue, green')
})
})
})
})

View File

@@ -72,6 +72,7 @@ export const ListView: React.FC<AdminViewProps> = async ({ initPageResult, searc
collection: collectionSlug,
depth: 0,
limit,
overrideAccess: false,
user,
})

View File

@@ -15,7 +15,7 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
docID: id,
globalConfig,
permissions,
req: { payload, payload: { config } = {} } = {},
req: { payload, payload: { config } = {}, user } = {},
} = initPageResult
// /entityType/:entitySlug/:id/versions/:versionID
@@ -43,6 +43,8 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
collection: slug,
depth: 1,
locale: '*',
overrideAccess: false,
user,
})
publishedDoc = await payload.findByID({
@@ -51,6 +53,8 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
depth: 1,
draft: false,
locale: '*',
overrideAccess: false,
user,
})
mostRecentDoc = await payload.findByID({
@@ -59,6 +63,8 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
depth: 1,
draft: true,
locale: '*',
overrideAccess: false,
user,
})
} catch (error) {
return notFound()
@@ -75,6 +81,8 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
slug,
depth: 1,
locale: '*',
overrideAccess: false,
user,
})
publishedDoc = payload.findGlobal({
@@ -82,6 +90,8 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
depth: 1,
draft: false,
locale: '*',
overrideAccess: false,
user,
})
mostRecentDoc = payload.findGlobal({
@@ -89,6 +99,8 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
depth: 1,
draft: true,
locale: '*',
overrideAccess: false,
user,
})
} catch (error) {
return notFound()

View File

@@ -43,6 +43,7 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
collection: collectionSlug,
depth: 0,
limit: limit ? parseInt(limit?.toString(), 10) : undefined,
overrideAccess: false,
page: page ? parseInt(page.toString(), 10) : undefined,
sort: sort as string,
user,
@@ -62,6 +63,7 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
versionsData = await payload.findGlobalVersions({
slug: globalSlug,
depth: 0,
overrideAccess: false,
page: page ? parseInt(page as string, 10) : undefined,
sort: sort as string,
user,

View File

@@ -33,8 +33,6 @@ const withPayload = (nextConfig = {}) => {
...(incomingWebpackConfig?.externals || []),
'drizzle-kit',
'drizzle-kit/payload',
'pino',
'pino-pretty',
'sharp',
'libsql',
],

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"description": "Node, React and MongoDB Headless CMS and Application Framework",
"license": "MIT",
"main": "./src/index.js",

View File

@@ -94,16 +94,10 @@ const collectionSchema = joi.object().keys({
maxLoginAttempts: joi.number(),
removeTokenFromResponses: joi.boolean().valid(true),
strategies: joi.array().items(
joi.alternatives().try(
strategyBaseSchema.keys({
name: joi.string().required(),
strategy: joi.func().maxArity(1).required(),
}),
strategyBaseSchema.keys({
name: joi.string(),
strategy: joi.object().required(),
}),
),
joi.object().keys({
name: joi.string().required(),
authenticate: joi.func().required(),
}),
),
tokenExpiration: joi.number(),
useAPIKey: joi.boolean(),

View File

@@ -85,6 +85,13 @@ const sanitizeCollections = (
delete sanitized.upload.handlers
}
if ('auth' in sanitized && typeof sanitized.auth === 'object') {
sanitized.auth = { ...sanitized.auth }
delete sanitized.auth.strategies
delete sanitized.auth.forgotPassword
delete sanitized.auth.verify
}
if ('admin' in sanitized) {
sanitized.admin = { ...sanitized.admin }

View File

@@ -1,7 +1,7 @@
{
"name": "@payloadcms/plugin-cloud-storage",
"description": "The official cloud storage plugin for Payload CMS",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",

View File

@@ -1,7 +1,7 @@
{
"name": "@payloadcms/plugin-cloud",
"description": "The official Payload Cloud plugin",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"description": "The official Nested Docs plugin for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-redirects",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"homepage:": "https://payloadcms.com",
"repository": "git@github.com:payloadcms/plugin-redirects.git",
"description": "Redirects plugin for Payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-search",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"homepage:": "https://payloadcms.com",
"repository": "git@github.com:payloadcms/plugin-search.git",
"description": "Search plugin for Payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-seo",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"homepage:": "https://payloadcms.com",
"repository": "git@github.com:payloadcms/plugin-seo.git",
"description": "SEO plugin for Payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"description": "The officially supported Lexical richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-slate",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"description": "The officially supported Slate richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/translations",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"main": "./dist/exports/index.ts",
"types": "./dist/types.d.ts",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/ui",
"version": "3.0.0-alpha.42",
"version": "3.0.0-alpha.45",
"main": "./src/index.ts",
"types": "./dist/index.d.ts",
"type": "module",

View File

@@ -51,9 +51,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const redirectToInactivityRoute = useCallback(() => {
if (window.location.pathname.startsWith(admin)) {
const redirectParam = `?redirect=${encodeURIComponent(
window.location.pathname.replace(admin, ''),
)}`
const redirectParam = `?redirect=${encodeURIComponent(window.location.pathname)}`
router.replace(`${admin}${logoutInactivityRoute}${redirectParam}`)
} else {
router.replace(`${admin}${logoutInactivityRoute}`)

View File

@@ -1,8 +1,10 @@
@import '../../scss/styles.scss';
.template-default {
[dir='rtl']
&__nav-toggler-wrapper {
background-color: var(--theme-bg);
color: var(--theme-text);
[dir='rtl'] &__nav-toggler-wrapper {
left: unset;
right: 0;
}

View File

@@ -9,6 +9,8 @@
margin-left: auto;
margin-right: auto;
min-height: 100%;
background-color: var(--theme-bg-color);
color: var(--theme-text);
&--width-normal {
.template-minimal__wrap {

View File

@@ -1 +0,0 @@
import '@testing-library/jest-dom'