Compare commits
1 Commits
v3.0.0-alp
...
v3.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67e9306f7a |
@@ -1,7 +1,7 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import config from '@payload-config'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views/Root/index'
|
||||
import { RootPage } from '@payloadcms/next/views/Root/index'
|
||||
|
||||
type Args = {
|
||||
params: {
|
||||
@@ -12,9 +12,6 @@ type Args = {
|
||||
}
|
||||
}
|
||||
|
||||
export const generateMetadata = ({ params, searchParams }: Args) =>
|
||||
generatePageMetadata({ config, params, searchParams })
|
||||
|
||||
const Page = ({ params, searchParams }: Args) => RootPage({ config, params, searchParams })
|
||||
|
||||
export default Page
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
|
||||
import { REST_GET, REST_DELETE, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export const GET = REST_GET(config)
|
||||
export const POST = REST_POST(config)
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
export const GET = () => {
|
||||
export const GET = async () => {
|
||||
console.log('1')
|
||||
console.log('1')
|
||||
console.log('1')
|
||||
console.log('1')
|
||||
console.log('1')
|
||||
return Response.json({
|
||||
hello: 'elliot',
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const withPayload = require('./packages/next/src/withPayload')
|
||||
const { withPayload } = require('./packages/next/src/withPayload')
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
})
|
||||
@@ -6,14 +6,5 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
module.exports = withBundleAnalyzer(
|
||||
withPayload({
|
||||
reactStrictMode: false,
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
destination: '/admin',
|
||||
permanent: true,
|
||||
source: '/',
|
||||
},
|
||||
]
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
27
package.json
27
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.0.0-alpha.19",
|
||||
"version": "3.0.0-alpha.10",
|
||||
"private": true,
|
||||
"workspaces:": [
|
||||
"packages/*"
|
||||
@@ -9,7 +9,7 @@
|
||||
"build": "pnpm run build:core",
|
||||
"build:all": "turbo build",
|
||||
"build:core": "turbo build --filter \"!@payloadcms/plugin-*\"",
|
||||
"build:plugins": "turbo build --filter \"@payloadcms/plugin-*\" --filter \"!@payloadcms/plugin-search\"",
|
||||
"build:plugins": "turbo build --filter \"@payloadcms/plugin-*\"",
|
||||
"build:app": "next build",
|
||||
"build:create-payload-app": "turbo build --filter create-payload-app",
|
||||
"build:db-mongodb": "turbo build --filter db-mongodb",
|
||||
@@ -36,9 +36,9 @@
|
||||
"clean": "turbo clean",
|
||||
"clean:cache": "rimraf node_modules/.cache && rimraf packages/payload/node_modules/.cache && rimraf .next",
|
||||
"clean:all": "find . \\( -type d \\( -name node_modules -o -name dist -o -name .cache \\) -o -type f -name tsconfig.tsbuildinfo \\) -exec rm -rf {} +",
|
||||
"dev": "cross-env node --no-deprecation ./test/dev.js",
|
||||
"dev:generate-graphql-schema": "NODE_OPTIONS=--no-deprecation ts-node -T ./test/generateGraphQLSchema.ts",
|
||||
"dev:generate-types": "NODE_OPTIONS=--no-deprecation ts-node -T ./test/generateTypes.ts",
|
||||
"dev": "cross-env node ./test/dev.js",
|
||||
"dev:generate-graphql-schema": "ts-node -T ./test/generateGraphQLSchema.ts",
|
||||
"dev:generate-types": "ts-node -T ./test/generateTypes.ts",
|
||||
"dev:postgres": "pnpm --filter payload run dev:postgres",
|
||||
"docker:restart": "pnpm docker:stop --remove-orphans && pnpm docker:start",
|
||||
"docker:start": "docker-compose -f packages/plugin-cloud-storage/docker-compose.yml up -d",
|
||||
@@ -53,12 +53,12 @@
|
||||
"release:alpha": "tsx ./scripts/release.ts --bump prerelease --tag alpha",
|
||||
"release:beta": "tsx ./scripts/release.ts --bump prerelease --tag beta",
|
||||
"test": "pnpm test:int && pnpm test:components && pnpm test:e2e",
|
||||
"test:components": "cross-env NODE_OPTIONS=--no-deprecation jest --config=jest.components.config.js",
|
||||
"test:e2e": "NODE_OPTIONS=--no-deprecation npx playwright install --with-deps chromium && NODE_OPTIONS=--no-deprecation ts-node -T ./test/runE2E.ts",
|
||||
"test:e2e:debug": "cross-env NODE_OPTIONS=--no-deprecation PWDEBUG=1 DISABLE_LOGGING=true playwright test",
|
||||
"test:e2e:headed": "cross-env NODE_OPTIONS=--no-deprecation DISABLE_LOGGING=true playwright test --headed",
|
||||
"test:int:postgres": "cross-env NODE_OPTIONS=--no-deprecation PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
||||
"test:int": "cross-env NODE_OPTIONS=--no-deprecation DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
||||
"test:components": "cross-env jest --config=jest.components.config.js",
|
||||
"test:e2e": "npx playwright install --with-deps chromium && ts-node -T ./test/runE2E.ts",
|
||||
"test:e2e:debug": "cross-env PWDEBUG=1 DISABLE_LOGGING=true playwright test",
|
||||
"test:e2e:headed": "cross-env DISABLE_LOGGING=true playwright test --headed",
|
||||
"test:int:postgres": "cross-env PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
||||
"test:int": "cross-env DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
||||
"translateNewKeys": "pnpm --filter payload run translateNewKeys"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -89,7 +89,6 @@
|
||||
"@types/testing-library__jest-dom": "5.14.8",
|
||||
"add-stream": "^1.0.0",
|
||||
"chalk": "^4.1.2",
|
||||
"comment-json": "^4.2.3",
|
||||
"concat-stream": "^2.0.0",
|
||||
"conventional-changelog": "^5.1.0",
|
||||
"conventional-changelog-conventionalcommits": "^7.0.2",
|
||||
@@ -116,7 +115,7 @@
|
||||
"lint-staged": "^14.0.1",
|
||||
"minimist": "1.2.8",
|
||||
"mongodb-memory-server": "^9",
|
||||
"next": "14.1.2",
|
||||
"next": "14.1.1-canary.26",
|
||||
"node-mocks-http": "^1.14.1",
|
||||
"nodemon": "3.0.3",
|
||||
"pino": "8.15.0",
|
||||
@@ -129,7 +128,7 @@
|
||||
"read-stream": "^2.1.1",
|
||||
"rimraf": "3.0.2",
|
||||
"semver": "^7.5.4",
|
||||
"sharp": "0.32.6",
|
||||
"sharp": "0.33.2",
|
||||
"shelljs": "0.8.5",
|
||||
"simple-git": "^3.20.0",
|
||||
"slash": "3.0.0",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm copyfiles && pnpm build:swc",
|
||||
"copyfiles": "copyfiles -u 2 \"../../app/(payload)/**\" \"dist\"",
|
||||
"copyfiles": "copyfiles -u 4 \"../next/src/app/(payload)/**\" \"dist/app\"",
|
||||
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
|
||||
"clean": "rimraf {dist,*.tsbuildinfo}",
|
||||
"test": "jest",
|
||||
@@ -23,9 +23,7 @@
|
||||
"arg": "^5.0.0",
|
||||
"chalk": "^4.1.0",
|
||||
"command-exists": "^1.2.9",
|
||||
"comment-json": "^4.2.3",
|
||||
"degit": "^2.8.4",
|
||||
"detect-package-manager": "^3.0.1",
|
||||
"execa": "^5.0.0",
|
||||
"figures": "^3.2.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
|
||||
@@ -1,88 +1,16 @@
|
||||
import type { CompilerOptions } from 'typescript'
|
||||
|
||||
import chalk from 'chalk'
|
||||
import * as CommentJson from 'comment-json'
|
||||
import { detect } from 'detect-package-manager'
|
||||
import execa from 'execa'
|
||||
import fs from 'fs'
|
||||
import fse from 'fs-extra'
|
||||
import globby from 'globby'
|
||||
import path from 'path'
|
||||
|
||||
import type { CliArgs } from '../types'
|
||||
|
||||
import { copyRecursiveSync } from '../utils/copy-recursive-sync'
|
||||
import { error, info, debug as origDebug, success, warning } from '../utils/log'
|
||||
import { error, info, debug as origDebug, success } from '../utils/log'
|
||||
|
||||
type InitNextArgs = Pick<CliArgs, '--debug'> & {
|
||||
projectDir?: string
|
||||
useDistFiles?: boolean
|
||||
}
|
||||
type InitNextResult = { reason?: string; success: boolean; userAppDir?: string }
|
||||
|
||||
export async function initNext(args: InitNextArgs): Promise<InitNextResult> {
|
||||
args.projectDir = args.projectDir || process.cwd()
|
||||
const { projectDir } = args
|
||||
const templateResult = await applyPayloadTemplateFiles(args)
|
||||
if (!templateResult.success) return templateResult
|
||||
|
||||
const { success: installSuccess } = await installDeps(projectDir)
|
||||
if (!installSuccess) {
|
||||
return { ...templateResult, reason: 'Failed to install dependencies', success: false }
|
||||
}
|
||||
|
||||
// Create or find payload.config.ts
|
||||
const createConfigResult = findOrCreatePayloadConfig(projectDir)
|
||||
if (!createConfigResult.success) {
|
||||
return { ...templateResult, ...createConfigResult }
|
||||
}
|
||||
|
||||
// Add `@payload-config` to tsconfig.json `paths`
|
||||
await addPayloadConfigToTsConfig(projectDir)
|
||||
|
||||
// Output directions for user to update next.config.js
|
||||
const withPayloadMessage = `
|
||||
|
||||
${chalk.bold(`Wrap your existing next.config.js with the withPayload function. Here is an example:`)}
|
||||
|
||||
const { withPayload } = require("@payloadcms/next");
|
||||
|
||||
const nextConfig = {
|
||||
// Your Next.js config
|
||||
};
|
||||
|
||||
module.exports = withPayload(nextConfig);
|
||||
|
||||
`
|
||||
|
||||
console.log(withPayloadMessage)
|
||||
|
||||
return templateResult
|
||||
}
|
||||
|
||||
async function addPayloadConfigToTsConfig(projectDir: string) {
|
||||
const tsConfigPath = path.resolve(projectDir, 'tsconfig.json')
|
||||
const userTsConfigContent = await fse.readFile(tsConfigPath, {
|
||||
encoding: 'utf8',
|
||||
})
|
||||
const userTsConfig = CommentJson.parse(userTsConfigContent) as {
|
||||
compilerOptions?: CompilerOptions
|
||||
}
|
||||
if (!userTsConfig.compilerOptions && !('extends' in userTsConfig)) {
|
||||
userTsConfig.compilerOptions = {}
|
||||
}
|
||||
|
||||
if (!userTsConfig.compilerOptions.paths?.['@payload-config']) {
|
||||
userTsConfig.compilerOptions.paths = {
|
||||
...(userTsConfig.compilerOptions.paths || {}),
|
||||
'@payload-config': ['./payload.config.ts'],
|
||||
}
|
||||
await fse.writeFile(tsConfigPath, CommentJson.stringify(userTsConfig, null, 2))
|
||||
}
|
||||
}
|
||||
|
||||
async function applyPayloadTemplateFiles(args: InitNextArgs): Promise<InitNextResult> {
|
||||
const { '--debug': debug, projectDir, useDistFiles } = args
|
||||
export async function initNext(
|
||||
args: Pick<CliArgs, '--debug'> & { nextDir?: string; useDistFiles?: boolean },
|
||||
): Promise<{ success: boolean }> {
|
||||
const { '--debug': debug, nextDir, useDistFiles } = args
|
||||
|
||||
info('Initializing Payload app in Next.js project', 1)
|
||||
|
||||
@@ -90,18 +18,24 @@ async function applyPayloadTemplateFiles(args: InitNextArgs): Promise<InitNextRe
|
||||
if (debug) origDebug(message)
|
||||
}
|
||||
|
||||
if (!fs.existsSync(projectDir)) {
|
||||
return { reason: `Could not find specified project directory at ${projectDir}`, success: false }
|
||||
let projectDir = process.cwd()
|
||||
if (nextDir) {
|
||||
projectDir = path.resolve(projectDir, nextDir)
|
||||
if (debug) logDebug(`Overriding project directory to ${projectDir}`)
|
||||
}
|
||||
|
||||
if (!fs.existsSync(projectDir)) {
|
||||
error(`Could not find specified project directory at ${projectDir}`)
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
// Next.js configs can be next.config.js, next.config.mjs, etc.
|
||||
const foundConfig = (await globby('next.config.*js', { cwd: projectDir }))?.[0]
|
||||
const nextConfigPath = path.resolve(projectDir, foundConfig)
|
||||
if (!fs.existsSync(nextConfigPath)) {
|
||||
return {
|
||||
reason: `No next.config.js found at ${nextConfigPath}. Ensure you are in a Next.js project directory.`,
|
||||
success: false,
|
||||
}
|
||||
error(
|
||||
`No next.config.js found at ${nextConfigPath}. Ensure you are in a Next.js project directory.`,
|
||||
)
|
||||
return { success: false }
|
||||
} else {
|
||||
if (debug) logDebug(`Found Next config at ${nextConfigPath}`)
|
||||
}
|
||||
@@ -109,27 +43,21 @@ async function applyPayloadTemplateFiles(args: InitNextArgs): Promise<InitNextRe
|
||||
const templateFilesPath =
|
||||
__dirname.endsWith('dist') || useDistFiles
|
||||
? path.resolve(__dirname, '../..', 'dist/app')
|
||||
: path.resolve(__dirname, '../../../../app')
|
||||
: path.resolve(__dirname, '../../../next/src/app')
|
||||
|
||||
if (debug) logDebug(`Using template files from: ${templateFilesPath}`)
|
||||
|
||||
if (!fs.existsSync(templateFilesPath)) {
|
||||
return {
|
||||
reason: `Could not find template source files from ${templateFilesPath}`,
|
||||
success: false,
|
||||
}
|
||||
error(`Could not find template source files from ${templateFilesPath}`)
|
||||
return { success: false }
|
||||
} else {
|
||||
if (debug) logDebug('Found template source files')
|
||||
}
|
||||
|
||||
// src/app or app
|
||||
const userAppDirGlob = await globby(['**/app'], {
|
||||
cwd: projectDir,
|
||||
onlyDirectories: true,
|
||||
})
|
||||
const userAppDir = path.resolve(projectDir, userAppDirGlob?.[0])
|
||||
const userAppDir = path.resolve(projectDir, 'src/app')
|
||||
if (!fs.existsSync(userAppDir)) {
|
||||
return { reason: `Could not find user app directory inside ${projectDir}`, success: false }
|
||||
error(`Could not find user app directory at ${userAppDir}`)
|
||||
return { success: false }
|
||||
} else {
|
||||
logDebug(`Found user app directory: ${userAppDir}`)
|
||||
}
|
||||
@@ -137,83 +65,5 @@ async function applyPayloadTemplateFiles(args: InitNextArgs): Promise<InitNextRe
|
||||
logDebug(`Copying template files from ${templateFilesPath} to ${userAppDir}`)
|
||||
copyRecursiveSync(templateFilesPath, userAppDir, debug)
|
||||
success('Successfully initialized.')
|
||||
return { success: true, userAppDir }
|
||||
}
|
||||
|
||||
async function installDeps(projectDir: string) {
|
||||
const packageManager = await detect({ cwd: projectDir })
|
||||
if (!packageManager) {
|
||||
throw new Error('Could not detect package manager')
|
||||
}
|
||||
|
||||
info(`Installing dependencies with ${packageManager}`, 1)
|
||||
const packagesToInstall = [
|
||||
'payload',
|
||||
'@payloadcms/db-mongodb',
|
||||
'@payloadcms/next',
|
||||
'@payloadcms/richtext-slate',
|
||||
'@payloadcms/ui',
|
||||
].map((pkg) => `${pkg}@alpha`)
|
||||
|
||||
let exitCode = 0
|
||||
switch (packageManager) {
|
||||
case 'npm': {
|
||||
;({ exitCode } = await execa('npm', ['install', '--save', ...packagesToInstall], {
|
||||
cwd: projectDir,
|
||||
}))
|
||||
break
|
||||
}
|
||||
case 'yarn':
|
||||
case 'pnpm': {
|
||||
;({ exitCode } = await execa(packageManager, ['add', ...packagesToInstall], {
|
||||
cwd: projectDir,
|
||||
}))
|
||||
break
|
||||
}
|
||||
case 'bun': {
|
||||
warning('Bun support is untested.')
|
||||
;({ exitCode } = await execa('bun', ['add', ...packagesToInstall], { cwd: projectDir }))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (exitCode !== 0) {
|
||||
error(`Failed to install dependencies with ${packageManager}`)
|
||||
} else {
|
||||
success(`Successfully installed dependencies`)
|
||||
}
|
||||
return { success: exitCode === 0 }
|
||||
}
|
||||
function findOrCreatePayloadConfig(projectDir: string) {
|
||||
const configPath = path.resolve(projectDir, 'payload.config.ts')
|
||||
if (fs.existsSync(configPath)) {
|
||||
return { message: 'Found existing payload.config.ts', success: true }
|
||||
} else {
|
||||
// Create default config
|
||||
// TODO: Pull this from templates
|
||||
const defaultConfig = `import path from "path";
|
||||
|
||||
import { mongooseAdapter } from "@payloadcms/db-mongodb"; // database-adapter-import
|
||||
import { slateEditor } from "@payloadcms/richtext-slate"; // editor-import
|
||||
import { buildConfig } from "payload/config";
|
||||
|
||||
export default buildConfig({
|
||||
editor: slateEditor({}), // editor-config
|
||||
collections: [],
|
||||
secret: "asdfasdf",
|
||||
typescript: {
|
||||
outputFile: path.resolve(__dirname, "payload-types.ts"),
|
||||
},
|
||||
graphQL: {
|
||||
schemaOutputFile: path.resolve(__dirname, "generated-schema.graphql"),
|
||||
},
|
||||
db: mongooseAdapter({
|
||||
url: "mongodb://localhost:27017/next-payload-3",
|
||||
}),
|
||||
});
|
||||
`
|
||||
|
||||
fse.writeFileSync(configPath, defaultConfig)
|
||||
return { message: 'Created default payload.config.ts', success: true }
|
||||
}
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { parseTemplate } from './lib/parse-template'
|
||||
import { selectDb } from './lib/select-db'
|
||||
import { getValidTemplates, validateTemplate } from './lib/templates'
|
||||
import { writeEnvFile } from './lib/write-env-file'
|
||||
import { error, success } from './utils/log'
|
||||
import { success } from './utils/log'
|
||||
import { helpMessage, successMessage, welcomeMessage } from './utils/messages'
|
||||
|
||||
export class Main {
|
||||
@@ -61,11 +61,6 @@ export class Main {
|
||||
|
||||
if (this.args['--init-next']) {
|
||||
const result = await initNext(this.args)
|
||||
if (!result.success) {
|
||||
error(result.reason || 'Failed to initialize Payload app in Next.js project')
|
||||
} else {
|
||||
success('Payload app successfully initialized in Next.js project')
|
||||
}
|
||||
process.exit(result.success ? 0 : 1)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.0.0-alpha.19",
|
||||
"version": "3.0.0-alpha.10",
|
||||
"description": "The officially supported MongoDB database adapter for Payload - Update 2",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -6,14 +6,7 @@ import mongoose from 'mongoose'
|
||||
|
||||
import type { MongooseAdapter } from '.'
|
||||
|
||||
export const connect: Connect = async function connect(
|
||||
this: MongooseAdapter,
|
||||
options = {
|
||||
hotReload: false,
|
||||
},
|
||||
) {
|
||||
const { hotReload } = options
|
||||
|
||||
export const connect: Connect = async function connect(this: MongooseAdapter) {
|
||||
if (this.url === false) {
|
||||
return
|
||||
}
|
||||
@@ -31,8 +24,6 @@ export const connect: Connect = async function connect(
|
||||
useFacet: undefined,
|
||||
}
|
||||
|
||||
if (hotReload) connectionOptions.autoIndex = false
|
||||
|
||||
try {
|
||||
this.connection = (await mongoose.connect(urlToConnect, connectionOptions)).connection
|
||||
|
||||
@@ -43,15 +34,12 @@ export const connect: Connect = async function connect(
|
||||
this.beginTransaction = undefined
|
||||
}
|
||||
|
||||
if (!hotReload) {
|
||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||
this.payload.logger.info('---- DROPPING DATABASE ----')
|
||||
await mongoose.connection.dropDatabase()
|
||||
this.payload.logger.info('---- DROPPED DATABASE ----')
|
||||
}
|
||||
|
||||
this.payload.logger.info(successfulConnectionMessage)
|
||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||
this.payload.logger.info('---- DROPPING DATABASE ----')
|
||||
await mongoose.connection.dropDatabase()
|
||||
this.payload.logger.info('---- DROPPED DATABASE ----')
|
||||
}
|
||||
this.payload.logger.info(successfulConnectionMessage)
|
||||
} catch (err) {
|
||||
this.payload.logger.error(`Error: cannot connect to MongoDB. Details: ${err.message}`, err)
|
||||
process.exit(1)
|
||||
|
||||
@@ -10,7 +10,6 @@ export const destroy: Destroy = async function destroy(this: MongooseAdapter) {
|
||||
await mongoose.connection.close()
|
||||
await this.mongoMemoryServer.stop()
|
||||
} else {
|
||||
await mongoose.disconnect()
|
||||
await mongoose.connection.close()
|
||||
}
|
||||
Object.keys(mongoose.models).map((model) => mongoose.deleteModel(model))
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { buildGlobalModel } from './models/buildGlobalModel'
|
||||
import buildSchema from './models/buildSchema'
|
||||
import getBuildQueryPlugin from './queries/buildQuery'
|
||||
|
||||
export const init: Init = function init(this: MongooseAdapter) {
|
||||
export const init: Init = async function init(this: MongooseAdapter) {
|
||||
this.payload.config.collections.forEach((collection: SanitizedCollectionConfig) => {
|
||||
const schema = buildCollectionSchema(collection, this.payload.config)
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable class-methods-use-this */
|
||||
/* eslint-disable @typescript-eslint/no-use-before-define */
|
||||
import type { IndexOptions, Schema, SchemaOptions, SchemaTypeOptions } from 'mongoose'
|
||||
/* eslint-disable no-use-before-define */
|
||||
import type { IndexOptions, SchemaOptions, SchemaTypeOptions } from 'mongoose'
|
||||
import type { SanitizedConfig, SanitizedLocalizationConfig } from 'payload/config'
|
||||
import type {
|
||||
ArrayField,
|
||||
@@ -31,7 +32,7 @@ import type {
|
||||
UploadField,
|
||||
} from 'payload/types'
|
||||
|
||||
import mongoose from 'mongoose'
|
||||
import { Schema } from 'mongoose'
|
||||
import {
|
||||
fieldAffectsData,
|
||||
fieldIsLocalized,
|
||||
@@ -125,7 +126,7 @@ const buildSchema = (
|
||||
}
|
||||
}
|
||||
|
||||
const schema = new mongoose.Schema(fields, options)
|
||||
const schema = new Schema(fields, options)
|
||||
|
||||
schemaFields.forEach((field) => {
|
||||
if (!fieldIsPresentationalOnly(field)) {
|
||||
@@ -175,7 +176,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const fieldSchema = {
|
||||
type: [new mongoose.Schema({}, { _id: false, discriminatorKey: 'blockType' })],
|
||||
type: [new Schema({}, { _id: false, discriminatorKey: 'blockType' })],
|
||||
default: undefined,
|
||||
}
|
||||
|
||||
@@ -184,7 +185,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
})
|
||||
|
||||
field.blocks.forEach((blockItem: Block) => {
|
||||
const blockSchema = new mongoose.Schema({}, { _id: false, id: false })
|
||||
const blockSchema = new Schema({}, { _id: false, id: false })
|
||||
|
||||
blockItem.fields.forEach((blockField) => {
|
||||
const addFieldSchema: FieldSchemaGenerator = fieldToSchemaMap[blockField.type]
|
||||
@@ -306,10 +307,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
config: SanitizedConfig,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
}
|
||||
const baseSchema = { ...formatBaseSchema(field, buildSchemaOptions), type: Schema.Types.Mixed }
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
@@ -407,17 +405,17 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
localeSchema = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
_id: false,
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
type: Schema.Types.Mixed,
|
||||
relationTo: { type: String, enum: field.relationTo },
|
||||
value: {
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
type: Schema.Types.Mixed,
|
||||
refPath: `${field.name}.${locale}.relationTo`,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
localeSchema = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
type: Schema.Types.Mixed,
|
||||
ref: field.relationTo,
|
||||
}
|
||||
}
|
||||
@@ -433,10 +431,10 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
schemaToReturn = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
_id: false,
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
type: Schema.Types.Mixed,
|
||||
relationTo: { type: String, enum: field.relationTo },
|
||||
value: {
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
type: Schema.Types.Mixed,
|
||||
refPath: `${field.name}.relationTo`,
|
||||
},
|
||||
}
|
||||
@@ -450,7 +448,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
} else {
|
||||
schemaToReturn = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
type: Schema.Types.Mixed,
|
||||
ref: field.relationTo,
|
||||
}
|
||||
|
||||
@@ -472,10 +470,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
config: SanitizedConfig,
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
}
|
||||
const baseSchema = { ...formatBaseSchema(field, buildSchemaOptions), type: Schema.Types.Mixed }
|
||||
|
||||
schema.add({
|
||||
[field.name]: localizeSchema(field, baseSchema, config.localization),
|
||||
@@ -591,7 +586,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
): void => {
|
||||
const baseSchema = {
|
||||
...formatBaseSchema(field, buildSchemaOptions),
|
||||
type: mongoose.Schema.Types.Mixed,
|
||||
type: Schema.Types.Mixed,
|
||||
ref: field.relationTo,
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.0.0-alpha.19",
|
||||
"version": "0.7.0",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -46,14 +46,7 @@ const connectWithReconnect = async function ({
|
||||
})
|
||||
}
|
||||
|
||||
export const connect: Connect = async function connect(
|
||||
this: PostgresAdapter,
|
||||
options = {
|
||||
hotReload: false,
|
||||
},
|
||||
) {
|
||||
const { hotReload } = options
|
||||
|
||||
export const connect: Connect = async function connect(this: PostgresAdapter, payload) {
|
||||
this.schema = {
|
||||
...this.tables,
|
||||
...this.relations,
|
||||
@@ -62,26 +55,23 @@ export const connect: Connect = async function connect(
|
||||
|
||||
try {
|
||||
this.pool = new Pool(this.poolOptions)
|
||||
await connectWithReconnect({ adapter: this, payload: this.payload })
|
||||
await connectWithReconnect({ adapter: this, payload })
|
||||
|
||||
const logger = this.logger || false
|
||||
|
||||
this.drizzle = drizzle(this.pool, { logger, schema: this.schema })
|
||||
|
||||
if (!hotReload) {
|
||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||
this.payload.logger.info(`---- DROPPING TABLES SCHEMA(${this.schemaName || 'public'}) ----`)
|
||||
await this.drizzle.execute(
|
||||
sql.raw(`
|
||||
drop schema if exists ${this.schemaName || 'public'} cascade;
|
||||
create schema ${this.schemaName || 'public'};
|
||||
`),
|
||||
)
|
||||
this.payload.logger.info('---- DROPPED TABLES ----')
|
||||
}
|
||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||
this.payload.logger.info(`---- DROPPING TABLES SCHEMA(${this.schemaName || 'public'}) ----`)
|
||||
await this.drizzle.execute(
|
||||
sql.raw(`
|
||||
drop schema if exists ${this.schemaName || 'public'} cascade;
|
||||
create schema ${this.schemaName || 'public'};
|
||||
`),
|
||||
)
|
||||
this.payload.logger.info('---- DROPPED TABLES ----')
|
||||
}
|
||||
} catch (err) {
|
||||
this.payload.logger.error(`Error: cannot connect to Postgres. Details: ${err.message}`, err)
|
||||
payload.logger.error(`Error: cannot connect to Postgres. Details: ${err.message}`, err)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-alpha.19",
|
||||
"version": "3.0.0-alpha.10",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.d.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.0.0-alpha.19",
|
||||
"version": "3.0.0-alpha.10",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.d.ts",
|
||||
"bin": {
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build:webpack": "webpack --config webpack.config.js",
|
||||
"build": "pnpm copyfiles && pnpm build:swc && pnpm build:types",
|
||||
"build": "pnpm copyfiles && pnpm build:swc && pnpm build:webpack && pnpm build:types",
|
||||
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
|
||||
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
||||
"clean": "rimraf {dist,*.tsbuildinfo}",
|
||||
@@ -49,7 +49,6 @@
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@types/react": "18.2.15",
|
||||
"@types/react-dom": "18.2.7",
|
||||
"@types/ws": "^8.5.10",
|
||||
"css-loader": "^6.10.0",
|
||||
"css-minimizer-webpack-plugin": "^6.0.0",
|
||||
"file-loader": "6.2.0",
|
||||
@@ -78,9 +77,7 @@
|
||||
"graphql-playground-html": "1.6.30",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"react-diff-viewer-continued": "3.2.6",
|
||||
"react-toastify": "8.2.0",
|
||||
"sass": "^1.71.1",
|
||||
"ws": "^8.16.0"
|
||||
"react-toastify": "8.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"http-status": "1.6.2",
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default as withPayload } from '../withPayload'
|
||||
export { withPayload } from '../withPayload'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export { AdminLayout } from './layouts/Admin'
|
||||
export { DocumentLayout } from './layouts/Document'
|
||||
export { RootLayout } from './layouts/Root'
|
||||
export { Dashboard as DashboardPage } from './views/Dashboard'
|
||||
export { Login } from './views/Login'
|
||||
export { Dashboard as DashboardPage, generateMetadata as dashboardMeta } from './views/Dashboard'
|
||||
export { Login, generateMetadata as loginMeta } from './views/Login'
|
||||
export { RootPage } from './views/Root'
|
||||
|
||||
42
packages/next/src/layouts/Document/index.tsx
Normal file
42
packages/next/src/layouts/Document/index.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { DocumentHeader } from '@payloadcms/ui'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
|
||||
export const metadata = {
|
||||
description: 'Generated by Next.js',
|
||||
title: 'Next.js',
|
||||
}
|
||||
|
||||
export const DocumentLayout = async ({
|
||||
children,
|
||||
collectionSlug,
|
||||
config: configPromise,
|
||||
globalSlug,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
collectionSlug?: string
|
||||
config: Promise<SanitizedConfig>
|
||||
globalSlug?: string
|
||||
}) => {
|
||||
const { collectionConfig, globalConfig, req } = await initPage({
|
||||
collectionSlug,
|
||||
config: configPromise,
|
||||
globalSlug,
|
||||
})
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<DocumentHeader
|
||||
collectionConfig={collectionConfig}
|
||||
config={req.payload.config}
|
||||
globalConfig={globalConfig}
|
||||
i18n={req.i18n}
|
||||
/>
|
||||
{children}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -5,17 +5,15 @@ import { translations } from '@payloadcms/translations/client'
|
||||
import { RootProvider, buildComponentMap } from '@payloadcms/ui'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import { headers as getHeaders } from 'next/headers'
|
||||
import { parseCookies } from 'payload/auth'
|
||||
import { createClientConfig } from 'payload/config'
|
||||
import { deepMerge } from 'payload/utilities'
|
||||
import React from 'react'
|
||||
import 'react-toastify/dist/ReactToastify.css'
|
||||
|
||||
import { getRequestLanguage } from '../../utilities/getRequestLanguage'
|
||||
import { DefaultEditView } from '../../views/Edit/Default'
|
||||
import { DefaultListView } from '../../views/List/Default'
|
||||
import { DefaultCell } from '../../views/List/Default/Cell'
|
||||
import { getPayload } from '../../utilities/getPayload'
|
||||
import { getRequestLanguage } from '../../utilities/getRequestLanguage'
|
||||
|
||||
export const metadata = {
|
||||
description: 'Generated by Next.js',
|
||||
@@ -36,13 +34,10 @@ export const RootLayout = async ({
|
||||
|
||||
const headers = getHeaders()
|
||||
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
|
||||
const { cookies, user, permissions } = await auth({
|
||||
payload,
|
||||
const { cookies, user } = await auth({
|
||||
config: configPromise,
|
||||
headers,
|
||||
})
|
||||
|
||||
const lang =
|
||||
getRequestLanguage({
|
||||
cookies,
|
||||
@@ -63,7 +58,6 @@ export const RootLayout = async ({
|
||||
DefaultEditView,
|
||||
DefaultListView,
|
||||
config,
|
||||
permissions: permissions,
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -158,9 +158,7 @@ export const processMultipart: ProcessMultipart = async ({ options, request }) =
|
||||
parsingRequest = false
|
||||
}
|
||||
|
||||
if (value) {
|
||||
busboy.write(value)
|
||||
}
|
||||
busboy.write(value)
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from 'fs'
|
||||
|
||||
export function iteratorToStream(iterator) {
|
||||
function iteratorToStream(iterator) {
|
||||
return new ReadableStream({
|
||||
async pull(controller) {
|
||||
const { done, value } = await iterator.next()
|
||||
@@ -13,7 +13,7 @@ export function iteratorToStream(iterator) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function* nodeStreamToIterator(stream: fs.ReadStream) {
|
||||
async function* nodeStreamToIterator(stream: fs.ReadStream) {
|
||||
for await (const chunk of stream) {
|
||||
yield new Uint8Array(chunk)
|
||||
}
|
||||
|
||||
@@ -51,10 +51,6 @@ if (!cached) {
|
||||
}
|
||||
|
||||
export const getGraphql = async (config: Promise<SanitizedConfig> | SanitizedConfig) => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
cached = global._payload_graphql = { graphql: null, promise: null }
|
||||
}
|
||||
|
||||
if (cached.graphql) {
|
||||
return cached.graphql
|
||||
}
|
||||
@@ -114,7 +110,7 @@ export const POST =
|
||||
}
|
||||
return response
|
||||
},
|
||||
schema,
|
||||
schema: schema,
|
||||
validationRules: (request, args, defaultRules) => defaultRules.concat(validationRules(args)),
|
||||
})(originalRequest)
|
||||
|
||||
|
||||
@@ -77,7 +77,6 @@ export const GET =
|
||||
params: { collection: collectionSlug },
|
||||
request,
|
||||
})
|
||||
|
||||
collection = req.payload.collections?.[collectionSlug]
|
||||
|
||||
if (!collection) {
|
||||
@@ -91,7 +90,7 @@ export const GET =
|
||||
)
|
||||
}
|
||||
|
||||
if (collection.config.upload.disableLocalStorage && !collection.config.upload.handlers) {
|
||||
if (collection.config.upload.disableLocalStorage) {
|
||||
throw new APIError(
|
||||
`This collection has local storage disabled: ${collectionSlug}`,
|
||||
httpStatus.BAD_REQUEST,
|
||||
@@ -104,21 +103,10 @@ export const GET =
|
||||
req,
|
||||
})
|
||||
|
||||
let response: Response = null
|
||||
if (collection.config.upload.handlers?.length) {
|
||||
for (const handler of collection.config.upload.handlers) {
|
||||
response = await handler(req, { params })
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
const fileDir = collection.config.upload?.staticDir || collection.config.slug
|
||||
const filePath = path.resolve(`${fileDir}/${filename}`)
|
||||
|
||||
const stats = await fsPromises.stat(filePath)
|
||||
const data = streamFile(filePath)
|
||||
|
||||
return new Response(data, {
|
||||
headers: new Headers({
|
||||
'content-length': stats.size + '',
|
||||
|
||||
@@ -12,7 +12,7 @@ if (!cached) {
|
||||
}
|
||||
|
||||
export const getFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
|
||||
if (cached && process.env.NODE_ENV !== 'development') {
|
||||
if (cached) {
|
||||
return cached
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const find: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const { searchParams } = req
|
||||
|
||||
// parse using `qs` to handle `where` queries
|
||||
const { depth, draft, limit, page, sort, where } = qs.parse(searchParams.toString()) as {
|
||||
depth?: string
|
||||
|
||||
@@ -208,7 +208,6 @@ export const GET =
|
||||
if (`doc-${slug2}-by-id` in endpoints.collection.GET) {
|
||||
// /:collection/access/:id
|
||||
// /:collection/versions/:id
|
||||
|
||||
res = await (
|
||||
endpoints.collection.GET[`doc-${slug2}-by-id`] as CollectionRouteHandlerWithID
|
||||
)({ id: slug3, collection, req })
|
||||
@@ -335,7 +334,6 @@ export const POST =
|
||||
// /:collection/forgot-password
|
||||
// /:collection/reset-password
|
||||
// /:collection/refresh-token
|
||||
|
||||
res = await (endpoints.collection.POST?.[slug2] as CollectionRouteHandler)({
|
||||
collection,
|
||||
req,
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import type { Payload, PayloadRequest } from 'payload/types'
|
||||
import type { PayloadRequest, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { getPayload } from 'payload'
|
||||
import { getAccessResults, getAuthenticatedUser, parseCookies } from 'payload/auth'
|
||||
import { cache } from 'react'
|
||||
|
||||
export const auth = cache(
|
||||
async ({ headers, payload }: { headers: Request['headers']; payload: Payload }) => {
|
||||
async ({
|
||||
config,
|
||||
headers,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig> | SanitizedConfig
|
||||
headers: Request['headers']
|
||||
}) => {
|
||||
const cookies = parseCookies(headers)
|
||||
|
||||
const payload = await getPayload({ config })
|
||||
const user = await getAuthenticatedUser({
|
||||
cookies,
|
||||
headers,
|
||||
|
||||
117
packages/next/src/utilities/createClientConfig.ts
Normal file
117
packages/next/src/utilities/createClientConfig.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { ClientConfig, Field, SanitizedConfig } from 'payload/types'
|
||||
|
||||
export const sanitizeField = (f) => {
|
||||
const field = { ...f }
|
||||
|
||||
if ('access' in field) delete field.access
|
||||
if ('hooks' in field) delete field.hooks
|
||||
if ('validate' in field) delete field.validate
|
||||
if ('defaultValue' in field) delete field.defaultValue
|
||||
if ('label' in field) delete field.label
|
||||
|
||||
if ('fields' in field) {
|
||||
field.fields = sanitizeFields(field.fields)
|
||||
}
|
||||
|
||||
if ('editor' in field) {
|
||||
delete field.editor
|
||||
}
|
||||
|
||||
if ('blocks' in field) {
|
||||
field.blocks = field.blocks.map((block) => {
|
||||
const sanitized = { ...block }
|
||||
sanitized.fields = sanitizeFields(sanitized.fields)
|
||||
return sanitized
|
||||
})
|
||||
}
|
||||
|
||||
if ('tabs' in field) {
|
||||
field.tabs = field.tabs.map((tab) => sanitizeField(tab))
|
||||
}
|
||||
|
||||
if ('admin' in field) {
|
||||
field.admin = { ...field.admin }
|
||||
|
||||
if ('components' in field.admin) {
|
||||
delete field.admin.components
|
||||
}
|
||||
|
||||
if ('condition' in field.admin) {
|
||||
delete field.admin.condition
|
||||
}
|
||||
|
||||
if ('description' in field.admin) {
|
||||
delete field.admin.description
|
||||
}
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
const sanitizeCollections = (
|
||||
collections: SanitizedConfig['collections'],
|
||||
): ClientConfig['collections'] =>
|
||||
collections.map((collection) => {
|
||||
const sanitized = { ...collection }
|
||||
sanitized.fields = sanitizeFields(sanitized.fields)
|
||||
delete sanitized.hooks
|
||||
delete sanitized.access
|
||||
delete sanitized.endpoints
|
||||
|
||||
if ('editor' in sanitized) delete sanitized.editor
|
||||
|
||||
if ('admin' in sanitized) {
|
||||
sanitized.admin = { ...sanitized.admin }
|
||||
|
||||
if ('components' in sanitized.admin) {
|
||||
delete sanitized.admin.components
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized
|
||||
})
|
||||
|
||||
const sanitizeGlobals = (globals: SanitizedConfig['globals']): ClientConfig['globals'] =>
|
||||
globals.map((global) => {
|
||||
const sanitized = { ...global }
|
||||
sanitized.fields = sanitizeFields(sanitized.fields)
|
||||
delete sanitized.hooks
|
||||
delete sanitized.access
|
||||
delete sanitized.endpoints
|
||||
|
||||
if ('admin' in sanitized) {
|
||||
sanitized.admin = { ...sanitized.admin }
|
||||
|
||||
if ('components' in sanitized.admin) {
|
||||
delete sanitized.admin.components
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized
|
||||
})
|
||||
|
||||
export const sanitizeFields = (fields: Field[]): Field[] => fields.map(sanitizeField)
|
||||
|
||||
export const createClientConfig = async (
|
||||
configPromise: Promise<SanitizedConfig> | SanitizedConfig,
|
||||
): Promise<ClientConfig> => {
|
||||
const config = await configPromise
|
||||
const clientConfig = { ...config }
|
||||
|
||||
delete clientConfig.endpoints
|
||||
delete clientConfig.db
|
||||
delete clientConfig.editor
|
||||
|
||||
'localization' in clientConfig &&
|
||||
clientConfig.localization &&
|
||||
clientConfig.localization.locales.forEach((locale) => {
|
||||
delete locale.toString
|
||||
})
|
||||
|
||||
clientConfig.onInit = undefined
|
||||
|
||||
clientConfig.collections = sanitizeCollections(clientConfig.collections)
|
||||
clientConfig.globals = sanitizeGlobals(clientConfig.globals)
|
||||
|
||||
return clientConfig
|
||||
}
|
||||
@@ -7,13 +7,13 @@ import type {
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { getPayload } from 'payload'
|
||||
import { getAuthenticatedUser } from 'payload/auth'
|
||||
import { parseCookies } from 'payload/auth'
|
||||
import { getDataLoader } from 'payload/utilities'
|
||||
import { URL } from 'url'
|
||||
|
||||
import { getDataAndFile } from './getDataAndFile'
|
||||
import { getPayload } from './getPayload'
|
||||
import { getRequestLanguage } from './getRequestLanguage'
|
||||
import { getRequestLocales } from './getRequestLocales'
|
||||
|
||||
@@ -32,7 +32,6 @@ export const createPayloadRequest = async ({
|
||||
}: Args): Promise<PayloadRequest> => {
|
||||
const cookies = parseCookies(request.headers)
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
|
||||
const { collections, config } = payload
|
||||
|
||||
let collection: Collection = undefined
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import type { GeneratedTypes, Payload } from 'payload'
|
||||
import type { InitOptions } from 'payload/config'
|
||||
|
||||
import { BasePayload } from 'payload'
|
||||
import WebSocket from 'ws'
|
||||
|
||||
let cached = global._payload
|
||||
|
||||
if (!cached) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
cached = global._payload = { payload: null, promise: null }
|
||||
}
|
||||
|
||||
export const getPayload = async (options: InitOptions): Promise<Payload> => {
|
||||
if (cached.payload) {
|
||||
const config = await options.config
|
||||
|
||||
if (cached.reload) {
|
||||
cached.reload = false
|
||||
if (typeof cached.payload.db.destroy === 'function') {
|
||||
await cached.payload.db.destroy()
|
||||
}
|
||||
|
||||
cached.payload.config = config
|
||||
|
||||
cached.payload.collections = config.collections.reduce((collections, collection) => {
|
||||
collections[collection.slug] = { config: collection }
|
||||
return collections
|
||||
}, {})
|
||||
|
||||
// TODO: re-build payload.globals as well as any other properties
|
||||
// that may change on Payload singleton
|
||||
|
||||
await cached.payload.db.init()
|
||||
await cached.payload.db.connect({ hotReload: true })
|
||||
}
|
||||
|
||||
return cached.payload
|
||||
}
|
||||
|
||||
if (!cached.promise) {
|
||||
cached.promise = new BasePayload<GeneratedTypes>().init(options)
|
||||
}
|
||||
|
||||
try {
|
||||
cached.payload = await cached.promise
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
try {
|
||||
const ws = new WebSocket('ws://localhost:3000/_next/webpack-hmr')
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
if (typeof event.data === 'string') {
|
||||
const data = JSON.parse(event.data)
|
||||
|
||||
if ('action' in data && data.action === 'serverComponentChanges') {
|
||||
cached.reload = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// swallow e
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
cached.promise = null
|
||||
throw e
|
||||
}
|
||||
|
||||
return cached.payload
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Permissions } from 'payload/auth'
|
||||
import type { Locale } from 'payload/config'
|
||||
import type {
|
||||
InitPageResult,
|
||||
PayloadRequest,
|
||||
SanitizedCollectionConfig,
|
||||
SanitizedConfig,
|
||||
@@ -11,61 +12,69 @@ import { translations } from '@payloadcms/translations/client'
|
||||
import { findLocaleFromCode } from '@payloadcms/ui'
|
||||
import { headers as getHeaders } from 'next/headers'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { getPayload } from 'payload'
|
||||
import { createLocalReq } from 'payload/utilities'
|
||||
import qs from 'qs'
|
||||
|
||||
import { getPayload } from '../utilities/getPayload'
|
||||
import { auth } from './auth'
|
||||
import { getRequestLanguage } from './getRequestLanguage'
|
||||
|
||||
type Args = {
|
||||
collectionSlug?: string
|
||||
config: Promise<SanitizedConfig> | SanitizedConfig
|
||||
globalSlug?: string
|
||||
localeParam?: string
|
||||
redirectUnauthenticatedUser?: boolean
|
||||
route?: string
|
||||
searchParams?: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
|
||||
export type InitPageResult = {
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
locale: Locale
|
||||
permissions: Permissions
|
||||
req: PayloadRequest
|
||||
}
|
||||
|
||||
export const initPage = async ({
|
||||
config: configPromise,
|
||||
localeParam,
|
||||
redirectUnauthenticatedUser = false,
|
||||
route,
|
||||
searchParams,
|
||||
}: Args): Promise<InitPageResult> => {
|
||||
const headers = getHeaders()
|
||||
const localeParam = searchParams?.locale as string
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
|
||||
const { cookies, permissions, user } = await auth({
|
||||
config: configPromise,
|
||||
headers,
|
||||
payload,
|
||||
})
|
||||
|
||||
const routeSegments = route.replace(payload.config.routes.admin, '').split('/').filter(Boolean)
|
||||
const [entityType, entitySlug, createOrID] = routeSegments
|
||||
const collectionSlug = entityType === 'collections' ? entitySlug : undefined
|
||||
const globalSlug = entityType === 'globals' ? entitySlug : undefined
|
||||
const docID = collectionSlug && createOrID !== 'create' ? createOrID : undefined
|
||||
const config = await configPromise
|
||||
const routeSegments = route.replace(config.routes.admin, '').split('/').filter(Boolean)
|
||||
const collectionSlug = routeSegments[0] === 'collections' ? routeSegments[1] : undefined
|
||||
const globalSlug = routeSegments[0] === 'globals' ? routeSegments[1] : undefined
|
||||
|
||||
const { collections, globals, localization, routes } = payload.config
|
||||
const { collections, globals, localization, routes } = config
|
||||
|
||||
if (redirectUnauthenticatedUser && !user && route !== '/login') {
|
||||
if ('redirect' in searchParams) delete searchParams.redirect
|
||||
|
||||
const stringifiedSearchParams = Object.keys(searchParams ?? {}).length
|
||||
? `?${qs.stringify(searchParams)}`
|
||||
: ''
|
||||
|
||||
redirect(`${routes.admin}/login?redirect=${route + stringifiedSearchParams}`)
|
||||
redirect(`${routes.admin}/login?redirect=${routes.admin + route + stringifiedSearchParams}`)
|
||||
}
|
||||
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
const defaultLocale =
|
||||
localization && localization.defaultLocale ? localization.defaultLocale : 'en'
|
||||
const localeCode = localeParam || defaultLocale
|
||||
const locale = localization && findLocaleFromCode(localization, localeCode)
|
||||
const language = getRequestLanguage({ cookies, headers })
|
||||
|
||||
const i18n = initI18n({
|
||||
config: payload.config.i18n,
|
||||
config: config.i18n,
|
||||
context: 'client',
|
||||
language,
|
||||
translations,
|
||||
@@ -96,12 +105,9 @@ export const initPage = async ({
|
||||
|
||||
return {
|
||||
collectionConfig,
|
||||
cookies,
|
||||
docID,
|
||||
globalConfig,
|
||||
locale,
|
||||
permissions,
|
||||
req,
|
||||
translations: i18n.translations,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export const timestamp = (label: string) => {
|
||||
if (!process.env.PAYLOAD_TIME) process.env.PAYLOAD_TIME = String(new Date().getTime())
|
||||
const now = new Date()
|
||||
console.log(`[${now.getTime() - Number(process.env.PAYLOAD_TIME)}ms] ${label}`)
|
||||
}
|
||||
@@ -14,9 +14,9 @@ const chars = {
|
||||
const baseClass = 'query-inspector'
|
||||
|
||||
const Bracket = ({
|
||||
type,
|
||||
comma = false,
|
||||
position,
|
||||
type,
|
||||
}: {
|
||||
comma?: boolean
|
||||
position: 'end' | 'start'
|
||||
@@ -49,7 +49,7 @@ export const RenderJSON = ({
|
||||
parentType = 'object',
|
||||
trailingComma = false,
|
||||
}: Args) => {
|
||||
const objectKeys = object ? Object.keys(object) : []
|
||||
const objectKeys = Object.keys(object)
|
||||
const objectLength = objectKeys.length
|
||||
const [isOpen, setIsOpen] = React.useState<boolean>(true)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
import {
|
||||
Checkbox,
|
||||
@@ -26,8 +27,10 @@ import './index.scss'
|
||||
|
||||
const baseClass = 'query-inspector'
|
||||
|
||||
export const APIViewClient: React.FC = () => {
|
||||
const { id, collectionSlug, globalSlug, initialData } = useDocumentInfo()
|
||||
export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
const { collectionSlug, globalSlug } = props
|
||||
|
||||
const { id, initialData } = useDocumentInfo()
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import type { ServerSideEditViewProps } from 'payload/types'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import type { ServerSideEditViewProps } from '../Edit/types'
|
||||
|
||||
import { sanitizeEditViewProps } from '../Edit/sanitizeEditViewProps'
|
||||
import { APIViewClient } from './index.client'
|
||||
|
||||
export const APIView: React.FC<ServerSideEditViewProps> = () => {
|
||||
return <APIViewClient />
|
||||
export const APIView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
// Perform server-side logic here, but no need to fetch data, etc.
|
||||
// The `Document` component is a wrapper around all edit views, including this one
|
||||
// It sets up the document info context for the client to subscribe to
|
||||
const clientSideProps = sanitizeEditViewProps(props)
|
||||
return <APIViewClient {...clientSideProps} />
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Data, DocumentPreferences, ServerSideEditViewProps } from 'payload/types'
|
||||
import type { Metadata } from 'next'
|
||||
import type { Data, DocumentPreferences, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import {
|
||||
HydrateClientUser,
|
||||
@@ -10,24 +11,47 @@ import {
|
||||
import { notFound } from 'next/navigation'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
import type { ServerSideEditViewProps } from '../Edit/types'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { EditView } from '../Edit'
|
||||
import { Settings } from './Settings'
|
||||
|
||||
export { generateAccountMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('authentication:accountOfCurrentUser')}`,
|
||||
keywords: `${t('authentication:account')}`,
|
||||
title: t('authentication:account'),
|
||||
})
|
||||
}
|
||||
|
||||
export const Account = async ({
|
||||
page,
|
||||
searchParams,
|
||||
}: {
|
||||
page: InitPageResult
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}) => {
|
||||
const { locale, permissions, req } = page
|
||||
|
||||
export const Account: React.FC<AdminViewProps> = async ({ initPageResult, searchParams }) => {
|
||||
const {
|
||||
locale,
|
||||
permissions,
|
||||
req: {
|
||||
payload,
|
||||
payload: { config },
|
||||
user,
|
||||
},
|
||||
req,
|
||||
} = initPageResult
|
||||
payload,
|
||||
payload: { config },
|
||||
user,
|
||||
} = req
|
||||
|
||||
const {
|
||||
admin: { components: { views: { Account: CustomAccountComponent } = {} } = {}, user: userSlug },
|
||||
@@ -83,10 +107,24 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
|
||||
req,
|
||||
})
|
||||
|
||||
const serverSideProps: ServerSideEditViewProps = {
|
||||
initPageResult,
|
||||
routeSegments: [],
|
||||
const componentProps: ServerSideEditViewProps = {
|
||||
id: user?.id,
|
||||
action: `${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale.code}`,
|
||||
apiURL: `${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale.code}`,
|
||||
collectionSlug: userSlug,
|
||||
config,
|
||||
data,
|
||||
docPermissions: collectionPermissions,
|
||||
docPreferences,
|
||||
hasSavePermission: collectionPermissions?.update?.permission,
|
||||
i18n: req.i18n,
|
||||
initialState,
|
||||
locale,
|
||||
payload,
|
||||
permissions,
|
||||
searchParams,
|
||||
updatedAt: '', // TODO
|
||||
user,
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -109,7 +147,7 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
|
||||
typeof CustomAccountComponent === 'function' ? CustomAccountComponent : undefined
|
||||
}
|
||||
DefaultComponent={EditView}
|
||||
componentProps={serverSideProps}
|
||||
componentProps={componentProps}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateAccountMetadata: GenerateViewMetadata = async ({ config, i18n: { t } }) => {
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('authentication:accountOfCurrentUser')}`,
|
||||
keywords: `${t('authentication:account')}`,
|
||||
title: t('authentication:account'),
|
||||
})
|
||||
}
|
||||
@@ -1,19 +1,13 @@
|
||||
'use client'
|
||||
import { FieldMap, RenderFields, useComponentMap } from '@payloadcms/ui'
|
||||
import { RenderFields, useComponentMap } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
export const CreateFirstUserFields: React.FC<{
|
||||
userSlug: string
|
||||
createFirstUserFieldMap: FieldMap
|
||||
}> = ({ userSlug, createFirstUserFieldMap }) => {
|
||||
}> = ({ userSlug }) => {
|
||||
const { getFieldMap } = useComponentMap()
|
||||
|
||||
const fieldMap = getFieldMap({ collectionSlug: userSlug })
|
||||
|
||||
return (
|
||||
<RenderFields
|
||||
fieldMap={[...(fieldMap || []), ...(createFirstUserFieldMap || [])]}
|
||||
operation="create"
|
||||
/>
|
||||
)
|
||||
return <RenderFields fieldMap={fieldMap} />
|
||||
}
|
||||
|
||||
@@ -1,31 +1,66 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { Field } from 'payload/types'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Form, FormSubmit, buildStateFromSchema, mapFields } from '@payloadcms/ui'
|
||||
import { Form, FormSubmit, buildStateFromSchema } from '@payloadcms/ui'
|
||||
import { redirect } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { CreateFirstUserFields } from './index.client'
|
||||
import './index.scss'
|
||||
|
||||
export { generateCreateFirstUserMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
export const CreateFirstUser: React.FC<AdminViewProps> = async ({ initPageResult }) => {
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:createFirstUser'),
|
||||
keywords: t('general:create'),
|
||||
title: t('authentication:createFirstUser'),
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
page: InitPageResult
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
}
|
||||
export const CreateFirstUser: React.FC<Props> = async ({ page }) => {
|
||||
const { req } = page
|
||||
const { config } = req.payload
|
||||
const {
|
||||
req,
|
||||
req: {
|
||||
payload: {
|
||||
config,
|
||||
config: {
|
||||
admin: { user: userSlug },
|
||||
routes: { admin: adminRoute, api: apiRoute },
|
||||
serverURL,
|
||||
},
|
||||
},
|
||||
},
|
||||
} = initPageResult
|
||||
admin: { user: userSlug },
|
||||
routes: { admin: adminRoute, api: apiRoute },
|
||||
serverURL,
|
||||
} = config
|
||||
|
||||
const fields: Field[] = [
|
||||
if (req.user) {
|
||||
redirect(adminRoute)
|
||||
}
|
||||
|
||||
const { docs } = await req.payload.find({
|
||||
collection: userSlug,
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
})
|
||||
|
||||
if (docs.length > 0) {
|
||||
redirect(adminRoute)
|
||||
}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
@@ -34,23 +69,17 @@ export const CreateFirstUser: React.FC<AdminViewProps> = async ({ initPageResult
|
||||
},
|
||||
{
|
||||
name: 'password',
|
||||
type: 'text',
|
||||
type: 'password',
|
||||
label: req.t('general:password'),
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'confirm-password',
|
||||
type: 'text',
|
||||
type: 'confirmPassword',
|
||||
label: req.t('authentication:confirmPassword'),
|
||||
required: true,
|
||||
},
|
||||
]
|
||||
|
||||
const createFirstUserFieldMap = mapFields({
|
||||
fieldSchema: fields,
|
||||
config,
|
||||
parentPath: userSlug,
|
||||
})
|
||||
] as Field[]
|
||||
|
||||
const formState = await buildStateFromSchema({
|
||||
fieldSchema: fields,
|
||||
@@ -70,10 +99,7 @@ export const CreateFirstUser: React.FC<AdminViewProps> = async ({ initPageResult
|
||||
redirect={adminRoute}
|
||||
validationOperation="create"
|
||||
>
|
||||
<CreateFirstUserFields
|
||||
userSlug={userSlug}
|
||||
createFirstUserFieldMap={createFirstUserFieldMap}
|
||||
/>
|
||||
<CreateFirstUserFields userSlug={userSlug} />
|
||||
<FormSubmit>{req.t('general:create')}</FormSubmit>
|
||||
</Form>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateCreateFirstUserMetadata: GenerateViewMetadata = async ({
|
||||
config,
|
||||
i18n: { t },
|
||||
}) => {
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:createFirstUser'),
|
||||
keywords: t('general:create'),
|
||||
title: t('authentication:createFirstUser'),
|
||||
})
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
import React, { Fragment, useEffect, useState } from 'react'
|
||||
|
||||
import './index.scss'
|
||||
import { Permissions } from 'payload/auth'
|
||||
|
||||
const baseClass = 'dashboard'
|
||||
|
||||
@@ -23,8 +22,7 @@ export const DefaultDashboardClient: React.FC<{
|
||||
Link: React.ComponentType
|
||||
visibleCollections: string[]
|
||||
visibleGlobals: string[]
|
||||
permissions: Permissions
|
||||
}> = ({ Link, visibleCollections, visibleGlobals, permissions }) => {
|
||||
}> = ({ Link, visibleCollections, visibleGlobals }) => {
|
||||
const config = useConfig()
|
||||
|
||||
const {
|
||||
@@ -33,7 +31,7 @@ export const DefaultDashboardClient: React.FC<{
|
||||
routes: { admin },
|
||||
} = config
|
||||
|
||||
const { user } = useAuth()
|
||||
const { permissions, user } = useAuth()
|
||||
|
||||
const { i18n, t } = useTranslation()
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import React from 'react'
|
||||
|
||||
import { DefaultDashboardClient } from './index.client'
|
||||
import './index.scss'
|
||||
import { Permissions } from 'payload/auth'
|
||||
|
||||
const baseClass = 'dashboard'
|
||||
|
||||
@@ -14,7 +13,6 @@ export type DashboardProps = {
|
||||
config: SanitizedConfig
|
||||
visibleCollections: string[]
|
||||
visibleGlobals: string[]
|
||||
permissions: Permissions
|
||||
}
|
||||
|
||||
export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
||||
@@ -27,7 +25,6 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
||||
},
|
||||
visibleCollections,
|
||||
visibleGlobals,
|
||||
permissions,
|
||||
} = props
|
||||
|
||||
return (
|
||||
@@ -41,7 +38,6 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
||||
Link={Link}
|
||||
visibleCollections={visibleCollections}
|
||||
visibleGlobals={visibleGlobals}
|
||||
permissions={permissions}
|
||||
/>
|
||||
{Array.isArray(afterDashboard) &&
|
||||
afterDashboard.map((Component, i) => <Component key={i} />)}
|
||||
|
||||
@@ -1,26 +1,49 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { HydrateClientUser, RenderCustomComponent } from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import { isEntityHidden } from 'payload/utilities'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
import type { DashboardProps } from './Default'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { DefaultDashboard } from './Default'
|
||||
|
||||
export { generateDashboardMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('general:dashboard')} Payload`,
|
||||
keywords: `${t('general:dashboard')}, Payload`,
|
||||
title: t('general:dashboard'),
|
||||
})
|
||||
}
|
||||
|
||||
type Args = {
|
||||
page: InitPageResult
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
|
||||
export const Dashboard = async ({ page, searchParams }: Args) => {
|
||||
const { permissions, req } = page
|
||||
|
||||
export const Dashboard: React.FC<AdminViewProps> = ({
|
||||
initPageResult,
|
||||
// searchParams,
|
||||
}) => {
|
||||
const {
|
||||
permissions,
|
||||
req: {
|
||||
payload: { config },
|
||||
user,
|
||||
},
|
||||
} = initPageResult
|
||||
payload: { config },
|
||||
user,
|
||||
} = req
|
||||
|
||||
const CustomDashboardComponent = config.admin.components?.views?.Dashboard
|
||||
|
||||
@@ -43,7 +66,6 @@ export const Dashboard: React.FC<AdminViewProps> = ({
|
||||
config,
|
||||
visibleCollections,
|
||||
visibleGlobals,
|
||||
permissions,
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateDashboardMetadata: GenerateViewMetadata = async ({ config, i18n: { t } }) => {
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('general:dashboard')} Payload`,
|
||||
keywords: `${t('general:dashboard')}, Payload`,
|
||||
title: t('general:dashboard'),
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { EditViewComponent } from 'payload/config'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
|
||||
export const getCustomViewByKey = (
|
||||
@@ -6,7 +6,7 @@ export const getCustomViewByKey = (
|
||||
| SanitizedCollectionConfig['admin']['components']['views']
|
||||
| SanitizedGlobalConfig['admin']['components']['views'],
|
||||
customViewKey: string,
|
||||
): EditViewComponent => {
|
||||
): AdminViewComponent => {
|
||||
return typeof views?.Edit === 'function'
|
||||
? views?.Edit
|
||||
: typeof views?.Edit === 'object' &&
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { EditViewComponent } from 'payload/config'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
|
||||
export const getCustomViewByPath = (
|
||||
@@ -6,7 +6,7 @@ export const getCustomViewByPath = (
|
||||
| SanitizedCollectionConfig['admin']['components']['views']
|
||||
| SanitizedGlobalConfig['admin']['components']['views'],
|
||||
path: string,
|
||||
): EditViewComponent => {
|
||||
): AdminViewComponent => {
|
||||
if (typeof views?.Edit === 'object' && typeof views?.Edit !== 'function') {
|
||||
const foundViewConfig = Object.entries(views.Edit).find(([, view]) => {
|
||||
if (typeof view === 'object' && typeof view !== 'function' && 'path' in view) {
|
||||
|
||||
@@ -1,90 +1,92 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
import type {
|
||||
SanitizedCollectionConfig,
|
||||
SanitizedConfig,
|
||||
SanitizedGlobalConfig,
|
||||
} from 'payload/types'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { generateMetadata as apiMeta } from '../API/meta'
|
||||
import { generateMetadata as editMeta } from '../Edit/meta'
|
||||
import { generateMetadata as livePreviewMeta } from '../LivePreview/meta'
|
||||
import { generateMetadata as versionMeta } from '../Version/meta'
|
||||
import { generateMetadata as versionsMeta } from '../Versions/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
import { getNextI18n } from '../../utilities/getNextI18n.ts'
|
||||
import { meta } from '../../utilities/meta.ts'
|
||||
|
||||
export type GenerateEditViewMetadata = (
|
||||
args: Parameters<GenerateViewMetadata>[0] & {
|
||||
collectionConfig?: SanitizedCollectionConfig | null
|
||||
globalConfig?: SanitizedGlobalConfig | null
|
||||
isEditing: boolean
|
||||
},
|
||||
) => Promise<Metadata>
|
||||
export type GenerateEditViewMetadata = (args: {
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
config: SanitizedConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
i18n: I18n
|
||||
isEditing: boolean
|
||||
}) => Promise<Metadata>
|
||||
|
||||
export const getMetaBySegment: GenerateEditViewMetadata = async ({
|
||||
config,
|
||||
export const getMetaBySegment = async ({
|
||||
config: configPromise,
|
||||
params,
|
||||
collectionConfig,
|
||||
globalConfig,
|
||||
}) => {
|
||||
const { segments } = params
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
params: {
|
||||
collection?: string
|
||||
global?: string
|
||||
segments: string[]
|
||||
}
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
let fn: GenerateEditViewMetadata | null = null
|
||||
|
||||
const [segmentOne] = segments
|
||||
const isCollection = segmentOne === 'collections'
|
||||
const isGlobal = segmentOne === 'globals'
|
||||
const isEditing = Boolean(
|
||||
params.collection && params.segments?.length > 0 && params.segments[0] !== 'create',
|
||||
)
|
||||
|
||||
const isEditing = Boolean(isCollection && segments?.length > 2 && segments[2] !== 'create')
|
||||
|
||||
if (isCollection) {
|
||||
if (params.collection && params?.segments?.length) {
|
||||
// `/:id`
|
||||
if (params.segments.length === 3) {
|
||||
fn = editMeta
|
||||
if (params.segments.length === 1) {
|
||||
fn = await import('../Edit/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:id/api`
|
||||
if (params.segments.length === 4 && params.segments[3] === 'api') {
|
||||
fn = apiMeta
|
||||
if (params.segments.length === 2 && params.segments[1] === 'api') {
|
||||
fn = await import('../API/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:id/preview`
|
||||
if (params.segments.length === 4 && params.segments[3] === 'preview') {
|
||||
fn = livePreviewMeta
|
||||
if (params.segments.length === 2 && params.segments[1] === 'preview') {
|
||||
fn = await import('../LivePreview/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:id/versions`
|
||||
if (params.segments.length === 4 && params.segments[3] === 'versions') {
|
||||
fn = versionsMeta
|
||||
if (params.segments.length === 2 && params.segments[1] === 'versions') {
|
||||
fn = await import('../Versions/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:id/versions/:version`
|
||||
if (params.segments.length === 5 && params.segments[3] === 'versions') {
|
||||
fn = versionMeta
|
||||
if (params.segments.length === 3 && params.segments[1] === 'versions') {
|
||||
fn = await import('../Version/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
if (isGlobal) {
|
||||
if (params.global) {
|
||||
// `/:slug`
|
||||
if (params.segments?.length === 2) {
|
||||
fn = editMeta
|
||||
if (!params.segments?.length) {
|
||||
fn = await import('../Edit/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:slug/api`
|
||||
if (params.segments?.length === 3 && params.segments[2] === 'api') {
|
||||
fn = apiMeta
|
||||
if (params.segments?.length === 1 && params.segments[0] === 'api') {
|
||||
fn = await import('../API/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:slug/preview`
|
||||
if (params.segments?.length === 3 && params.segments[2] === 'preview') {
|
||||
fn = livePreviewMeta
|
||||
if (params.segments?.length === 1 && params.segments[0] === 'preview') {
|
||||
fn = await import('../LivePreview/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:slug/versions`
|
||||
if (params.segments?.length === 3 && params.segments[2] === 'versions') {
|
||||
fn = versionsMeta
|
||||
if (params.segments?.length === 1 && params.segments[0] === 'versions') {
|
||||
fn = await import('../Versions/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
|
||||
// `/:slug/versions/:version`
|
||||
if (params.segments?.length === 4 && params.segments[2] === 'versions') {
|
||||
fn = versionMeta
|
||||
if (params.segments?.length === 2 && params.segments[0] === 'versions') {
|
||||
fn = await import('../Version/meta.ts').then((mod) => mod.generateMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +94,14 @@ export const getMetaBySegment: GenerateEditViewMetadata = async ({
|
||||
config,
|
||||
})
|
||||
|
||||
const collectionConfig = params.collection
|
||||
? config?.collections?.find((collection) => collection.slug === params.collection)
|
||||
: null
|
||||
|
||||
const globalConfig = params.global
|
||||
? config?.globals?.find((global) => global.slug === params.global)
|
||||
: null
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
return fn({
|
||||
collectionConfig,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CollectionPermission, GlobalPermission, User } from 'payload/auth'
|
||||
import type { EditViewComponent } from 'payload/config'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type {
|
||||
SanitizedCollectionConfig,
|
||||
SanitizedConfig,
|
||||
@@ -31,13 +31,13 @@ export const getViewsFromConfig = async ({
|
||||
routeSegments: string[]
|
||||
user: User
|
||||
}): Promise<{
|
||||
CustomView: EditViewComponent
|
||||
DefaultView: EditViewComponent
|
||||
CustomView: AdminViewComponent
|
||||
DefaultView: AdminViewComponent
|
||||
} | null> => {
|
||||
// Conditionally import and lazy load the default view
|
||||
let DefaultView: EditViewComponent = null
|
||||
let CustomView: EditViewComponent = null
|
||||
|
||||
let DefaultView: AdminViewComponent = null
|
||||
let CustomView: AdminViewComponent = null
|
||||
const [entityType, entitySlug, createOrID, tabViewName, segmentFive] = routeSegments
|
||||
const views =
|
||||
(collectionConfig && collectionConfig?.admin?.components?.views) ||
|
||||
(globalConfig && globalConfig?.admin?.components?.views)
|
||||
@@ -49,9 +49,6 @@ export const getViewsFromConfig = async ({
|
||||
config?.admin?.livePreview?.globals?.includes(globalConfig?.slug)
|
||||
|
||||
if (collectionConfig) {
|
||||
const [collectionEntity, collectionSlug, createOrID, nestedViewSlug, segmentFive] =
|
||||
routeSegments
|
||||
|
||||
const {
|
||||
admin: { hidden },
|
||||
} = collectionConfig
|
||||
@@ -61,7 +58,7 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
|
||||
// `../:id`, or `../create`
|
||||
if (!nestedViewSlug) {
|
||||
if (!tabViewName) {
|
||||
switch (createOrID) {
|
||||
case 'create': {
|
||||
if ('create' in docPermissions && docPermissions?.create?.permission) {
|
||||
@@ -80,10 +77,10 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
}
|
||||
|
||||
if (nestedViewSlug) {
|
||||
if (tabViewName) {
|
||||
// `../:id/versions/:version`, etc
|
||||
if (segmentFive) {
|
||||
if (nestedViewSlug === 'versions') {
|
||||
if (tabViewName === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = getCustomViewByKey(views, 'Version')
|
||||
DefaultView = DefaultVersionView
|
||||
@@ -93,7 +90,7 @@ export const getViewsFromConfig = async ({
|
||||
|
||||
// `../:id/api`, `../:id/preview`, `../:id/versions`, etc
|
||||
if (routeSegments?.length === 4) {
|
||||
switch (nestedViewSlug) {
|
||||
switch (tabViewName) {
|
||||
case 'api': {
|
||||
if (collectionConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = getCustomViewByKey(views, 'API')
|
||||
@@ -118,7 +115,7 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
|
||||
default: {
|
||||
const path = `/${nestedViewSlug}`
|
||||
const path = `/${tabViewName}`
|
||||
CustomView = getCustomViewByPath(views, path)
|
||||
break
|
||||
}
|
||||
@@ -128,8 +125,6 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
|
||||
if (globalConfig) {
|
||||
const [globalEntity, globalSlug, nestedViewSlug] = routeSegments
|
||||
|
||||
const {
|
||||
admin: { hidden },
|
||||
} = globalConfig
|
||||
@@ -138,14 +133,14 @@ export const getViewsFromConfig = async ({
|
||||
return null
|
||||
}
|
||||
|
||||
if (routeSegments?.length === 2) {
|
||||
if (!routeSegments?.length) {
|
||||
if (docPermissions?.read?.permission) {
|
||||
CustomView = getCustomViewByKey(views, 'Default')
|
||||
DefaultView = DefaultEditView
|
||||
}
|
||||
} else if (routeSegments?.length === 3) {
|
||||
} else if (routeSegments?.length === 1) {
|
||||
// `../:slug/api`, `../:slug/preview`, `../:slug/versions`, etc
|
||||
switch (nestedViewSlug) {
|
||||
switch (tabViewName) {
|
||||
case 'api': {
|
||||
if (globalConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = getCustomViewByKey(views, 'API')
|
||||
@@ -179,7 +174,7 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
} else if (routeSegments?.length === 2) {
|
||||
// `../:slug/versions/:version`, etc
|
||||
if (nestedViewSlug === 'versions') {
|
||||
if (tabViewName === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = getCustomViewByKey(views, 'Version')
|
||||
DefaultView = DefaultVersionView
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { QueryParamTypes } from '@payloadcms/ui'
|
||||
import type { EditViewComponent } from 'payload/config'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type {
|
||||
DocumentPreferences,
|
||||
Document as DocumentType,
|
||||
Field,
|
||||
ServerSideEditViewProps,
|
||||
SanitizedConfig,
|
||||
} from 'payload/types'
|
||||
import type { DocumentPermissions } from 'payload/types'
|
||||
|
||||
@@ -22,48 +22,51 @@ import { notFound } from 'next/navigation'
|
||||
import queryString from 'qs'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { GenerateEditViewMetadata } from './getMetaBySegment'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
import type { ServerSideEditViewProps } from '../Edit/types'
|
||||
|
||||
import { getMetaBySegment } from './getMetaBySegment'
|
||||
import { getViewsFromConfig } from './getViewsFromConfig'
|
||||
|
||||
export const generateMetadata: GenerateEditViewMetadata = async (args) => getMetaBySegment(args)
|
||||
|
||||
export const Document: React.FC<AdminViewProps> = async ({
|
||||
initPageResult,
|
||||
params,
|
||||
searchParams,
|
||||
}) => {
|
||||
const {
|
||||
collectionConfig,
|
||||
docID: id,
|
||||
globalConfig,
|
||||
locale,
|
||||
permissions,
|
||||
req,
|
||||
req: {
|
||||
i18n,
|
||||
payload,
|
||||
payload: {
|
||||
config,
|
||||
config: {
|
||||
routes: { api: apiRoute },
|
||||
serverURL,
|
||||
},
|
||||
},
|
||||
user,
|
||||
},
|
||||
} = initPageResult
|
||||
export const generateMetadata = async (args: {
|
||||
config: Promise<SanitizedConfig>
|
||||
params: {
|
||||
collection?: string
|
||||
global?: string
|
||||
segments: string[]
|
||||
}
|
||||
}) => getMetaBySegment(args)
|
||||
|
||||
type Props = {
|
||||
page: InitPageResult
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
export const Document = async ({ page, params, searchParams }: Props) => {
|
||||
const segments = Array.isArray(params?.segments) ? params.segments : []
|
||||
const collectionSlug = collectionConfig?.slug || undefined
|
||||
const globalSlug = globalConfig?.slug || undefined
|
||||
const [entityType, entitySlug, createOrID] = segments
|
||||
const collectionSlug = entityType === 'collections' ? entitySlug : undefined
|
||||
const globalSlug = entitySlug === 'globals' ? entitySlug : undefined
|
||||
const isCreating = createOrID === 'create'
|
||||
const id = (collectionSlug && !isCreating && createOrID) || undefined
|
||||
|
||||
const isEditing = Boolean(globalSlug || (collectionSlug && !!id))
|
||||
|
||||
let CustomView: EditViewComponent
|
||||
let DefaultView: EditViewComponent
|
||||
const {
|
||||
i18n,
|
||||
payload,
|
||||
payload: { config },
|
||||
user,
|
||||
} = page.req
|
||||
|
||||
const {
|
||||
routes: { api },
|
||||
serverURL,
|
||||
} = config
|
||||
const { collectionConfig, globalConfig, locale, permissions, req } = page
|
||||
|
||||
let CustomView: SanitizedConfig['admin']['components']['views'][0]
|
||||
let DefaultView: AdminViewComponent
|
||||
let data: DocumentType
|
||||
let docPermissions: DocumentPermissions
|
||||
let preferencesKey: string
|
||||
@@ -75,13 +78,13 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
if (collectionConfig) {
|
||||
docPermissions = permissions?.collections?.[collectionSlug]
|
||||
fields = collectionConfig.fields
|
||||
action = `${serverURL}${apiRoute}/${collectionSlug}${isEditing ? `/${id}` : ''}`
|
||||
action = `${serverURL}${api}/${collectionSlug}${isEditing ? `/${id}` : ''}`
|
||||
|
||||
hasSavePermission =
|
||||
(isEditing && permissions?.collections?.[collectionSlug]?.update?.permission) ||
|
||||
(!isEditing && permissions?.collections?.[collectionSlug]?.create?.permission)
|
||||
|
||||
apiURL = `${serverURL}${apiRoute}/${collectionSlug}/${id}?locale=${locale.code}${
|
||||
apiURL = `${serverURL}${api}/${collectionSlug}/${id}?locale=${locale.code}${
|
||||
collectionConfig.versions?.drafts ? '&draft=true' : ''
|
||||
}`
|
||||
|
||||
@@ -108,7 +111,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
locale: locale.code,
|
||||
user,
|
||||
})
|
||||
} catch (error) {} // eslint-disable-line no-empty
|
||||
} catch (error) {}
|
||||
|
||||
if (id) {
|
||||
preferencesKey = `collection-${collectionSlug}-${id}`
|
||||
@@ -119,9 +122,9 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
docPermissions = permissions?.globals?.[globalSlug]
|
||||
fields = globalConfig.fields
|
||||
hasSavePermission = isEditing && docPermissions?.update?.permission
|
||||
action = `${serverURL}${apiRoute}/${globalSlug}`
|
||||
action = `${serverURL}${api}/${globalSlug}`
|
||||
|
||||
apiURL = `${serverURL}${apiRoute}/${globalSlug}?locale=${locale.code}${
|
||||
apiURL = `${serverURL}${api}/${globalSlug}?locale=${locale.code}${
|
||||
globalConfig.versions?.drafts ? '&draft=true' : ''
|
||||
}`
|
||||
|
||||
@@ -159,7 +162,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
equals: preferencesKey,
|
||||
},
|
||||
},
|
||||
})) as any as { docs: { value: DocumentPreferences }[] } // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
})) as any as { docs: { value: DocumentPreferences }[] }
|
||||
|
||||
const initialState = await buildStateFromSchema({
|
||||
id,
|
||||
@@ -177,23 +180,42 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
uploadEdits: undefined,
|
||||
}
|
||||
|
||||
const serverSideProps: ServerSideEditViewProps = {
|
||||
initPageResult,
|
||||
routeSegments: segments,
|
||||
const componentProps: ServerSideEditViewProps = {
|
||||
id,
|
||||
action: `${action}?${queryString.stringify(formQueryParams)}`,
|
||||
apiURL,
|
||||
canAccessAdmin: permissions?.canAccessAdmin,
|
||||
collectionConfig,
|
||||
collectionSlug,
|
||||
config,
|
||||
data,
|
||||
docPermissions,
|
||||
docPreferences,
|
||||
globalConfig,
|
||||
globalSlug,
|
||||
hasSavePermission,
|
||||
i18n,
|
||||
initialState,
|
||||
isEditing,
|
||||
locale,
|
||||
payload,
|
||||
permissions,
|
||||
searchParams,
|
||||
updatedAt: data?.updatedAt?.toString(),
|
||||
user,
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<DocumentHeader
|
||||
collectionConfig={collectionConfig}
|
||||
config={payload.config}
|
||||
config={req.payload.config}
|
||||
globalConfig={globalConfig}
|
||||
i18n={i18n}
|
||||
i18n={req.i18n}
|
||||
/>
|
||||
<HydrateClientUser permissions={permissions} user={user} />
|
||||
<SetDocumentInfo
|
||||
action={`${action}?${queryString.stringify(formQueryParams)}`}
|
||||
action={action}
|
||||
apiURL={apiURL}
|
||||
collectionSlug={collectionConfig?.slug}
|
||||
disableActions={false}
|
||||
@@ -210,7 +232,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
<RenderCustomComponent
|
||||
CustomComponent={typeof CustomView === 'function' ? CustomView : undefined}
|
||||
DefaultComponent={DefaultView}
|
||||
componentProps={serverSideProps}
|
||||
componentProps={componentProps}
|
||||
/>
|
||||
</FormQueryParamsProvider>
|
||||
</EditDepthProvider>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { GenerateEditViewMetadata, getMetaBySegment } from './getMetaBySegment'
|
||||
|
||||
export const generateDocumentMetadata: GenerateEditViewMetadata = async (args) =>
|
||||
getMetaBySegment(args)
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
getFormState,
|
||||
useComponentMap,
|
||||
useConfig,
|
||||
useDocumentEvents,
|
||||
useDocumentInfo,
|
||||
} from '@payloadcms/ui'
|
||||
import { Upload } from '@payloadcms/ui/elements'
|
||||
@@ -67,15 +66,13 @@ export const DefaultEditView: React.FC = () => {
|
||||
|
||||
const globalConfig = globalSlug && globals.find((global) => global.slug === globalSlug)
|
||||
|
||||
const schemaPath = collectionConfig?.slug || globalConfig?.slug
|
||||
const [schemaPath] = React.useState(collectionConfig?.slug || globalConfig?.slug)
|
||||
|
||||
const fieldMap = getFieldMap({
|
||||
collectionSlug: collectionConfig?.slug,
|
||||
globalSlug: globalConfig?.slug,
|
||||
})
|
||||
|
||||
const { reportUpdate } = useDocumentEvents()
|
||||
|
||||
const operation = id ? 'update' : 'create'
|
||||
|
||||
const auth = collectionConfig ? collectionConfig.auth : undefined
|
||||
@@ -90,11 +87,11 @@ export const DefaultEditView: React.FC = () => {
|
||||
|
||||
const onSave = useCallback(
|
||||
async (json) => {
|
||||
reportUpdate({
|
||||
id,
|
||||
entitySlug: collectionConfig.slug,
|
||||
updatedAt: json?.result?.updatedAt || new Date().toISOString(),
|
||||
})
|
||||
// reportUpdate({
|
||||
// id,
|
||||
// entitySlug: collectionConfig.slug,
|
||||
// updatedAt: json?.result?.updatedAt || new Date().toISOString(),
|
||||
// })
|
||||
|
||||
// if (auth && id === user.id) {
|
||||
// await refreshCookieAsync()
|
||||
@@ -111,7 +108,7 @@ export const DefaultEditView: React.FC = () => {
|
||||
id,
|
||||
onSaveFromContext,
|
||||
// refreshCookieAsync,
|
||||
reportUpdate,
|
||||
// reportUpdate
|
||||
],
|
||||
)
|
||||
|
||||
@@ -158,6 +155,17 @@ export const DefaultEditView: React.FC = () => {
|
||||
}`}
|
||||
type="withoutNav"
|
||||
/>
|
||||
{/* <Meta
|
||||
description={`${isEditing ? t('general:editing') : t('general:creating')} - ${getTranslation(
|
||||
collection.labels.singular,
|
||||
i18n,
|
||||
)}`}
|
||||
keywords={`${getTranslation(collection.labels.singular, i18n)}, Payload, CMS`}
|
||||
title={`${isEditing ? t('general:editing') : t('general:creating')} - ${getTranslation(
|
||||
collection.labels.singular,
|
||||
i18n,
|
||||
)}`}
|
||||
/> */}
|
||||
{BeforeDocument}
|
||||
{preventLeaveWithoutSaving && <LeaveWithoutSaving />}
|
||||
<SetStepNav
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
import {
|
||||
LoadingOverlay,
|
||||
@@ -11,14 +12,12 @@ import { useRouter } from 'next/navigation'
|
||||
import React, { Fragment, useEffect } from 'react'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
export const EditViewClient: React.FC = () => {
|
||||
export const EditViewClient: React.FC<EditViewProps> = () => {
|
||||
const { id, collectionSlug, getDocPermissions, getVersions, globalSlug, setDocumentInfo } =
|
||||
useDocumentInfo()
|
||||
|
||||
const {
|
||||
routes: { admin: adminRoute },
|
||||
} = useConfig()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const { getComponentMap } = useComponentMap()
|
||||
@@ -32,8 +31,8 @@ export const EditViewClient: React.FC = () => {
|
||||
|
||||
const onSave = useCallback(
|
||||
async (json: { doc }) => {
|
||||
void getVersions()
|
||||
void getDocPermissions()
|
||||
getVersions()
|
||||
getDocPermissions()
|
||||
|
||||
if (!isEditing) {
|
||||
router.push(`${adminRoute}/collections/${collectionSlug}/${json?.doc?.id}`)
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import type { ServerSideEditViewProps } from 'payload/types'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import { EditViewClient } from './index.client'
|
||||
import type { ServerSideEditViewProps } from './types'
|
||||
|
||||
export const EditView: React.FC<ServerSideEditViewProps> = () => {
|
||||
return <EditViewClient />
|
||||
import { EditViewClient } from './index.client'
|
||||
import { sanitizeEditViewProps } from './sanitizeEditViewProps'
|
||||
|
||||
export const EditView: React.FC<ServerSideEditViewProps> = (props) => {
|
||||
// Perform server-side logic here, but no need to fetch data, etc.
|
||||
// The `Document` component is a wrapper around all edit views, including this one
|
||||
// It sets up the document info context for the client to subscribe to
|
||||
const clientSideProps = sanitizeEditViewProps(props)
|
||||
return <EditViewClient {...clientSideProps} />
|
||||
}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import type { EditViewProps, ServerSideEditViewProps } from 'payload/types'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
import type { ServerSideEditViewProps } from './types'
|
||||
|
||||
export const sanitizeEditViewProps = (props: ServerSideEditViewProps) => {
|
||||
const clientSideProps = { ...props }
|
||||
delete clientSideProps.initPageResult.req
|
||||
delete clientSideProps.initPageResult.collectionConfig
|
||||
delete clientSideProps.initPageResult.globalConfig
|
||||
delete clientSideProps.payload
|
||||
delete clientSideProps.config
|
||||
delete clientSideProps.searchParams
|
||||
delete clientSideProps.i18n
|
||||
delete clientSideProps.collectionConfig
|
||||
delete clientSideProps.globalConfig
|
||||
|
||||
return clientSideProps as EditViewProps
|
||||
}
|
||||
|
||||
43
packages/next/src/views/Edit/types.d.ts
vendored
Normal file
43
packages/next/src/views/Edit/types.d.ts
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { FormState } from '@payloadcms/ui'
|
||||
import type { Permissions, User } from 'payload/auth'
|
||||
import type { EditViewProps, Locale } from 'payload/config'
|
||||
import type {
|
||||
Data,
|
||||
DocumentPermissions,
|
||||
DocumentPreferences,
|
||||
Payload,
|
||||
SanitizedConfig,
|
||||
} from 'payload/types'
|
||||
export type ServerSideEditViewProps = EditViewProps & {
|
||||
action?: string
|
||||
apiURL: string
|
||||
canAccessAdmin?: boolean
|
||||
collectionConfig?: SanitizedConfig['collections'][0]
|
||||
config: SanitizedConfig
|
||||
data: Data
|
||||
disableActions?: boolean
|
||||
disableLeaveWithoutSaving?: boolean
|
||||
docPermissions: DocumentPermissions
|
||||
docPreferences: DocumentPreferences
|
||||
globalConfig?: SanitizedConfig['globals'][0]
|
||||
hasSavePermission?: boolean
|
||||
i18n: I18n
|
||||
id?: string
|
||||
initialState?: FormState
|
||||
isEditing?: boolean
|
||||
locale: Locale
|
||||
params?: {
|
||||
collection?: string
|
||||
global?: string
|
||||
segments: string[]
|
||||
}
|
||||
payload: Payload
|
||||
permissions: Permissions
|
||||
searchParams: {
|
||||
[key: string]: string | string[] | undefined
|
||||
}
|
||||
updatedAt: string
|
||||
user: User
|
||||
}
|
||||
//# sourceMappingURL=types.d.ts.map
|
||||
1
packages/next/src/views/Edit/types.d.ts.map
Normal file
1
packages/next/src/views/Edit/types.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC3D,OAAO,KAAK,EACV,IAAI,EACJ,mBAAmB,EACnB,mBAAmB,EACnB,OAAO,EACP,eAAe,EAChB,MAAM,eAAe,CAAA;AAEtB,MAAM,MAAM,uBAAuB,GAAG,aAAa,GAAG;IACpD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,gBAAgB,CAAC,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,MAAM,EAAE,eAAe,CAAA;IACvB,IAAI,EAAE,IAAI,CAAA;IACV,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC,cAAc,EAAE,mBAAmB,CAAA;IACnC,cAAc,EAAE,mBAAmB,CAAA;IACnC,YAAY,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;IAC5C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,IAAI,EAAE,IAAI,CAAA;IACV,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,EAAE,CAAA;KACnB,CAAA;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,WAAW,CAAA;IACxB,YAAY,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAA;KAAE,CAAA;IAE9D,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,IAAI,CAAA;CACX,CAAA"}
|
||||
37
packages/next/src/views/Edit/types.ts
Normal file
37
packages/next/src/views/Edit/types.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { FormState } from '@payloadcms/ui'
|
||||
import type { Permissions, User } from 'payload/auth'
|
||||
import type { EditViewProps, Locale } from 'payload/config'
|
||||
import type {
|
||||
Data,
|
||||
DocumentPermissions,
|
||||
DocumentPreferences,
|
||||
Payload,
|
||||
SanitizedConfig,
|
||||
} from 'payload/types'
|
||||
|
||||
export type ServerSideEditViewProps = EditViewProps & {
|
||||
action?: string
|
||||
apiURL: string
|
||||
canAccessAdmin?: boolean
|
||||
collectionConfig?: SanitizedConfig['collections'][0]
|
||||
config: SanitizedConfig
|
||||
data: Data
|
||||
disableActions?: boolean
|
||||
disableLeaveWithoutSaving?: boolean
|
||||
docPermissions: DocumentPermissions
|
||||
docPreferences: DocumentPreferences
|
||||
globalConfig?: SanitizedConfig['globals'][0]
|
||||
hasSavePermission?: boolean
|
||||
i18n: I18n
|
||||
id?: string
|
||||
initialState?: FormState
|
||||
isEditing?: boolean
|
||||
locale: Locale
|
||||
payload: Payload
|
||||
permissions: Permissions
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
// isLoading: boolean
|
||||
updatedAt: string
|
||||
user: User
|
||||
}
|
||||
@@ -1,21 +1,46 @@
|
||||
import { Button, Email, Form, FormSubmit, Translation } from '@payloadcms/ui'
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Button, Email, Form, FormSubmit, MinimalTemplate, Translation } from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
export { generateForgotPasswordMetadata } from './meta'
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
|
||||
export const forgotPasswordBaseClass = 'forgot-password'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:forgotPassword'),
|
||||
keywords: t('authentication:forgotPassword'),
|
||||
title: t('authentication:forgotPassword'),
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
baseClass: string
|
||||
page: InitPageResult
|
||||
}
|
||||
export const ForgotPassword: React.FC<Props> = async ({ page }) => {
|
||||
const { req } = page
|
||||
|
||||
export const ForgotPassword: React.FC<AdminViewProps> = ({ initPageResult }) => {
|
||||
const {
|
||||
req: {
|
||||
i18n,
|
||||
payload: { config },
|
||||
user,
|
||||
},
|
||||
} = initPageResult
|
||||
i18n,
|
||||
payload: { config },
|
||||
user,
|
||||
} = req
|
||||
|
||||
const {
|
||||
admin: { user: userSlug },
|
||||
@@ -48,7 +73,7 @@ export const ForgotPassword: React.FC<AdminViewProps> = ({ initPageResult }) =>
|
||||
/>
|
||||
</p>
|
||||
<br />
|
||||
<Button Link={Link} buttonStyle="secondary" el="link" to={admin}>
|
||||
<Button buttonStyle="secondary" el="link" to={admin}>
|
||||
{i18n.t('general:backToDashboard')}
|
||||
</Button>
|
||||
</Fragment>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
|
||||
export const generateForgotPasswordMetadata = async ({ config, i18n: { t } }) => {
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:forgotPassword'),
|
||||
keywords: t('authentication:forgotPassword'),
|
||||
title: t('authentication:forgotPassword'),
|
||||
})
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
SetViewActions,
|
||||
UnpublishMany,
|
||||
} from '@payloadcms/ui/elements'
|
||||
import Link from 'next/link'
|
||||
import { formatFilesize } from 'payload/utilities'
|
||||
import React, { Fragment, useEffect } from 'react'
|
||||
|
||||
@@ -157,7 +156,7 @@ export const DefaultListView: React.FC = () => {
|
||||
<div className={`${baseClass}__no-results`}>
|
||||
<p>{i18n.t('general:noResults', { label: getTranslation(labels?.plural, i18n) })}</p>
|
||||
{hasCreatePermission && newDocumentURL && (
|
||||
<Button Link={Link} el="link" to={newDocumentURL}>
|
||||
<Button el="link" to={newDocumentURL}>
|
||||
{i18n.t('general:createNewLabel', {
|
||||
label: getTranslation(labels?.singular, i18n),
|
||||
})}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import {
|
||||
HydrateClientUser,
|
||||
ListInfoProvider,
|
||||
@@ -8,24 +12,62 @@ import { notFound } from 'next/navigation'
|
||||
import { isEntityHidden } from 'payload/utilities'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
import type { DefaultListViewProps, ListPreferences } from './Default/types'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { DefaultListView } from './Default'
|
||||
|
||||
export { generateListMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
params,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
params: {
|
||||
collection: string
|
||||
}
|
||||
}): Promise<Metadata> => {
|
||||
let title: string = ''
|
||||
const description: string = ''
|
||||
const keywords: string = ''
|
||||
|
||||
export const ListView: React.FC<AdminViewProps> = async ({ initPageResult, searchParams }) => {
|
||||
const collectionSlug = params.collection
|
||||
|
||||
const config = await configPromise
|
||||
|
||||
const i18n = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
const collectionConfig = collectionSlug
|
||||
? config?.collections?.find((collection) => collection.slug === collectionSlug)
|
||||
: null
|
||||
|
||||
if (collectionConfig) {
|
||||
title = getTranslation(collectionConfig.labels.plural, i18n)
|
||||
}
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description,
|
||||
keywords,
|
||||
title,
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
page: InitPageResult
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
export const ListView = async ({ page, searchParams }: Props) => {
|
||||
const { collectionConfig, permissions } = page
|
||||
const {
|
||||
collectionConfig,
|
||||
permissions,
|
||||
req: {
|
||||
payload,
|
||||
payload: { config },
|
||||
user,
|
||||
},
|
||||
} = initPageResult
|
||||
|
||||
payload,
|
||||
payload: { config },
|
||||
user,
|
||||
} = page.req
|
||||
const collectionSlug = collectionConfig?.slug
|
||||
|
||||
let listPreferences: ListPreferences
|
||||
@@ -43,7 +85,7 @@ export const ListView: React.FC<AdminViewProps> = async ({ initPageResult, searc
|
||||
},
|
||||
})
|
||||
?.then((res) => res?.docs?.[0]?.value)) as ListPreferences
|
||||
} catch (error) {} // eslint-disable-line no-empty
|
||||
} catch (error) {}
|
||||
|
||||
const {
|
||||
routes: { admin },
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
import { Metadata } from 'next'
|
||||
import { SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
export const generateListMetadata = async (
|
||||
args: Parameters<GenerateViewMetadata>[0] & {
|
||||
collectionConfig: SanitizedCollectionConfig
|
||||
},
|
||||
): Promise<Metadata> => {
|
||||
const { collectionConfig, config, i18n } = args
|
||||
|
||||
let title: string = ''
|
||||
const description: string = ''
|
||||
const keywords: string = ''
|
||||
|
||||
if (collectionConfig) {
|
||||
title = getTranslation(collectionConfig.labels.plural, i18n)
|
||||
}
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description,
|
||||
keywords,
|
||||
title,
|
||||
})
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import type { LivePreviewConfig } from 'payload/config'
|
||||
import type { EditViewProps, LivePreviewConfig } from 'payload/config'
|
||||
|
||||
import { DndContext } from '@dnd-kit/core'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
@@ -10,7 +10,7 @@ import { customCollisionDetection } from './collisionDetection'
|
||||
import { LivePreviewContext } from './context'
|
||||
import { sizeReducer } from './sizeReducer'
|
||||
|
||||
export type LivePreviewProviderProps = {
|
||||
export type LivePreviewProviderProps = EditViewProps & {
|
||||
appIsReady?: boolean
|
||||
breakpoints?: LivePreviewConfig['breakpoints']
|
||||
children: React.ReactNode
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import type { EditViewProps } from 'payload/types'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
import {
|
||||
ShimmerEffect,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import type { EditViewProps } from 'payload/types'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
import { Chevron, LinkIcon, Popup, PopupList, X } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import type { EditViewProps } from 'payload/types'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
import { useDraggable } from '@dnd-kit/core'
|
||||
import { DragHandle } from '@payloadcms/ui'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import type { FormProps } from '@payloadcms/ui'
|
||||
import type { LivePreviewConfig } from 'payload/config'
|
||||
import type { EditViewProps, LivePreviewConfig } from 'payload/config'
|
||||
import type { Data } from 'payload/types'
|
||||
|
||||
import {
|
||||
@@ -198,14 +198,15 @@ const PreviewView: React.FC = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
export const LivePreviewClient: React.FC<{
|
||||
breakpoints: LivePreviewConfig['breakpoints']
|
||||
initialData: Data
|
||||
livePreviewConfig: LivePreviewConfig
|
||||
url: string
|
||||
}> = (props) => {
|
||||
const { breakpoints, url } = props
|
||||
const { collectionSlug, globalSlug } = useDocumentInfo()
|
||||
export const LivePreviewClient: React.FC<
|
||||
EditViewProps & {
|
||||
breakpoints: LivePreviewConfig['breakpoints']
|
||||
initialData: Data
|
||||
livePreviewConfig: LivePreviewConfig
|
||||
url: string
|
||||
}
|
||||
> = (props) => {
|
||||
const { breakpoints, collectionSlug, globalSlug, url } = props
|
||||
|
||||
const { isPopupOpen, openPopupWindow, popupRef } = usePopupWindow({
|
||||
eventType: 'payload-live-preview',
|
||||
@@ -220,6 +221,7 @@ export const LivePreviewClient: React.FC<{
|
||||
<Fragment>
|
||||
<SetViewActions actions={componentMap?.actionsMap?.Edit?.LivePreview} />
|
||||
<LivePreviewProvider
|
||||
{...props}
|
||||
breakpoints={breakpoints}
|
||||
isPopupOpen={isPopupOpen}
|
||||
openPopupWindow={openPopupWindow}
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import type { LivePreviewConfig } from 'payload/config'
|
||||
import type { ServerSideEditViewProps } from 'payload/types'
|
||||
import type { Data } from 'payload/types'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { LivePreviewClient } from './index.client'
|
||||
import './index.scss'
|
||||
|
||||
export const LivePreviewView: React.FC = async (props: ServerSideEditViewProps) => {
|
||||
const { initPageResult } = props
|
||||
|
||||
type Props = {
|
||||
data: Data
|
||||
page: InitPageResult
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
export const LivePreviewView: React.FC = async (props: Props) => {
|
||||
const { page } = props
|
||||
const {
|
||||
collectionConfig,
|
||||
globalConfig,
|
||||
@@ -20,10 +27,10 @@ export const LivePreviewView: React.FC = async (props: ServerSideEditViewProps)
|
||||
},
|
||||
} = {},
|
||||
} = {},
|
||||
} = initPageResult
|
||||
} = page
|
||||
|
||||
// TODO(JAKE): not sure what `data` is or what it should be
|
||||
const data = 'data' in props ? props.data : {}
|
||||
const { data = {} } = props
|
||||
|
||||
let livePreviewConfig: LivePreviewConfig = topLevelLivePreviewConfig
|
||||
|
||||
@@ -56,17 +63,20 @@ export const LivePreviewView: React.FC = async (props: ServerSideEditViewProps)
|
||||
? await livePreviewConfig.url({
|
||||
data,
|
||||
documentInfo: {}, // TODO: recreate this object server-side, see `useDocumentInfo`
|
||||
// @ts-expect-error
|
||||
locale,
|
||||
})
|
||||
: livePreviewConfig?.url
|
||||
|
||||
return (
|
||||
<LivePreviewClient
|
||||
breakpoints={breakpoints}
|
||||
initialData={data}
|
||||
livePreviewConfig={livePreviewConfig}
|
||||
url={url}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<LivePreviewClient
|
||||
breakpoints={breakpoints}
|
||||
collectionSlug={collectionConfig?.slug}
|
||||
globalSlug={globalConfig?.slug}
|
||||
initialData={data}
|
||||
livePreviewConfig={livePreviewConfig}
|
||||
url={url}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
import type { FormState } from '@payloadcms/ui'
|
||||
|
||||
import {
|
||||
Email,
|
||||
@@ -14,8 +15,6 @@ import React from 'react'
|
||||
|
||||
const baseClass = 'login__form'
|
||||
|
||||
import type { FormState } from 'payload/types'
|
||||
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
@@ -1,18 +1,43 @@
|
||||
import { Logo } from '@payloadcms/ui'
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Logo, MinimalTemplate } from '@payloadcms/ui'
|
||||
import { redirect } from 'next/navigation'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { LoginForm } from './LoginForm'
|
||||
import './index.scss'
|
||||
|
||||
export { generateLoginMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
export const loginBaseClass = 'login'
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
export const Login: React.FC<AdminViewProps> = ({ initPageResult, searchParams }) => {
|
||||
const { req } = initPageResult
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('authentication:login')}`,
|
||||
keywords: `${t('authentication:login')}`,
|
||||
title: t('authentication:login'),
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
baseClass: string
|
||||
page: InitPageResult
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
export const Login: React.FC<Props> = ({ baseClass, page, searchParams }) => {
|
||||
const { req } = page
|
||||
|
||||
const {
|
||||
payload: { config },
|
||||
@@ -33,7 +58,7 @@ export const Login: React.FC<AdminViewProps> = ({ initPageResult, searchParams }
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={`${loginBaseClass}__brand`}>
|
||||
<div className={`${baseClass}__brand`}>
|
||||
<Logo config={config} />
|
||||
</div>
|
||||
{Array.isArray(beforeLogin) && beforeLogin.map((Component, i) => <Component key={i} />)}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateLoginMetadata: GenerateViewMetadata = async ({ config, i18n: { t } }) => {
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('authentication:login')}`,
|
||||
keywords: `${t('authentication:login')}`,
|
||||
title: t('authentication:login'),
|
||||
})
|
||||
}
|
||||
@@ -1,29 +1,55 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { MinimalTemplate } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { LogoutClient } from './LogoutClient'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'logout'
|
||||
|
||||
export { generateLogoutMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
export const Logout: React.FC<
|
||||
AdminViewProps & {
|
||||
inactivity?: boolean
|
||||
}
|
||||
> = ({ inactivity, initPageResult, searchParams }) => {
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('authentication:logoutUser')}`,
|
||||
keywords: `${t('authentication:logout')}`,
|
||||
title: t('authentication:logout'),
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
baseClass: string
|
||||
page: InitPageResult
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
} & {
|
||||
inactivity?: boolean
|
||||
}
|
||||
|
||||
export const Logout: React.FC<Props> = ({ inactivity, page, searchParams }) => {
|
||||
const {
|
||||
req: {
|
||||
payload: {
|
||||
config: {
|
||||
routes: { admin },
|
||||
},
|
||||
},
|
||||
payload: { config },
|
||||
},
|
||||
} = initPageResult
|
||||
} = page
|
||||
|
||||
const {
|
||||
routes: { admin },
|
||||
} = config
|
||||
|
||||
return (
|
||||
<MinimalTemplate className={baseClass}>
|
||||
@@ -38,6 +64,6 @@ export const Logout: React.FC<
|
||||
)
|
||||
}
|
||||
|
||||
export const LogoutInactivity: React.FC<AdminViewProps> = (props) => {
|
||||
export const LogoutInactivity: React.FC<Props> = (props) => {
|
||||
return <Logout inactivity {...props} />
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateLogoutMetadata: GenerateViewMetadata = async ({ config, i18n: { t } }) => {
|
||||
return meta({
|
||||
config,
|
||||
description: `${t('authentication:logoutUser')}`,
|
||||
keywords: `${t('authentication:logout')}`,
|
||||
title: t('authentication:logout'),
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
import { Button, Gutter, useConfig, useStepNav, useTranslation } from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
// import Meta from '../../utilities/Meta'
|
||||
@@ -42,7 +41,7 @@ const NotFound: React.FC<{
|
||||
<Gutter className={`${baseClass}__wrap`}>
|
||||
<h1>{t('general:nothingFound')}</h1>
|
||||
<p>{t('general:sorryNotFound')}</p>
|
||||
<Button Link={Link} className={`${baseClass}__button`} el="link" to={`${admin}`}>
|
||||
<Button className={`${baseClass}__button`} el="link" to={`${admin}`}>
|
||||
{t('general:backToDashboard')}
|
||||
</Button>
|
||||
</Gutter>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import {
|
||||
Button,
|
||||
ConfirmPassword,
|
||||
@@ -11,17 +14,40 @@ import {
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import './index.scss'
|
||||
|
||||
export const resetPasswordBaseClass = 'reset-password'
|
||||
const baseClass = 'reset-password'
|
||||
|
||||
export { generateResetPasswordMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params }) => {
|
||||
const { req } = initPageResult
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:resetPassword'),
|
||||
keywords: t('authentication:resetPassword'),
|
||||
title: t('authentication:resetPassword'),
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
page: InitPageResult
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
}
|
||||
export const ResetPassword: React.FC<Props> = ({ page, params }) => {
|
||||
const { req } = page
|
||||
const { token } = params
|
||||
|
||||
const {
|
||||
@@ -48,8 +74,8 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
|
||||
|
||||
if (user) {
|
||||
return (
|
||||
<MinimalTemplate className={resetPasswordBaseClass}>
|
||||
<div className={`${resetPasswordBaseClass}__wrap`}>
|
||||
<MinimalTemplate className={baseClass}>
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
<h1>{i18n.t('authentication:alreadyLoggedIn')}</h1>
|
||||
<p>
|
||||
<Translation
|
||||
@@ -61,7 +87,7 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
|
||||
/>
|
||||
</p>
|
||||
<br />
|
||||
<Button Link={Link} buttonStyle="secondary" el="link" to={admin}>
|
||||
<Button buttonStyle="secondary" el="link" to={admin}>
|
||||
{i18n.t('general:backToDashboard')}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -70,8 +96,8 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
|
||||
}
|
||||
|
||||
return (
|
||||
<MinimalTemplate className={resetPasswordBaseClass}>
|
||||
<div className={`${resetPasswordBaseClass}__wrap`}>
|
||||
<MinimalTemplate className={baseClass}>
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
<h1>{i18n.t('authentication:resetPassword')}</h1>
|
||||
<Form
|
||||
action={`${serverURL}${api}/${userSlug}/reset-password`}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateResetPasswordMetadata: GenerateViewMetadata = async ({
|
||||
config,
|
||||
i18n: { t },
|
||||
}) => {
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:resetPassword'),
|
||||
keywords: t('authentication:resetPassword'),
|
||||
title: t('authentication:resetPassword'),
|
||||
})
|
||||
}
|
||||
@@ -1,25 +1,22 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { Metadata } from 'next'
|
||||
import type { InitPageResult, SanitizedConfig } from 'payload/types'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { DefaultTemplate, MinimalTemplate } from '@payloadcms/ui'
|
||||
import { redirect } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { Account } from '../Account'
|
||||
import { CreateFirstUser } from '../CreateFirstUser'
|
||||
import { Dashboard } from '../Dashboard'
|
||||
import { Document as DocumentView } from '../Document'
|
||||
import { ForgotPassword, forgotPasswordBaseClass } from '../ForgotPassword'
|
||||
import { ForgotPassword } from '../ForgotPassword'
|
||||
import { ListView } from '../List'
|
||||
import { Login, loginBaseClass } from '../Login'
|
||||
import { Login } from '../Login'
|
||||
import { Logout, LogoutInactivity } from '../Logout'
|
||||
import { ResetPassword, resetPasswordBaseClass } from '../ResetPassword'
|
||||
import { ResetPassword } from '../ResetPassword'
|
||||
import { Unauthorized } from '../Unauthorized'
|
||||
import { Verify, verifyBaseClass } from '../Verify'
|
||||
|
||||
export { generatePageMetadata } from './meta'
|
||||
import Verify from '../Verify'
|
||||
|
||||
type Args = {
|
||||
config: Promise<SanitizedConfig>
|
||||
@@ -31,23 +28,11 @@ type Args = {
|
||||
}
|
||||
}
|
||||
|
||||
export type GenerateViewMetadata = (args: {
|
||||
config: SanitizedConfig
|
||||
i18n: I18n
|
||||
params?: { [key: string]: string | string[] }
|
||||
}) => Promise<Metadata>
|
||||
|
||||
export type AdminViewProps = {
|
||||
initPageResult: InitPageResult
|
||||
params?: { [key: string]: string | string[] | undefined }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
|
||||
const baseClasses = {
|
||||
forgot: forgotPasswordBaseClass,
|
||||
login: loginBaseClass,
|
||||
reset: resetPasswordBaseClass,
|
||||
verify: verifyBaseClass,
|
||||
forgot: 'forgot-password',
|
||||
login: 'login',
|
||||
reset: 'reset-password',
|
||||
verify: 'verify',
|
||||
}
|
||||
|
||||
const oneSegmentViews = {
|
||||
@@ -61,19 +46,12 @@ const oneSegmentViews = {
|
||||
|
||||
export const RootPage = async ({ config: configPromise, params, searchParams }: Args) => {
|
||||
const config = await configPromise
|
||||
|
||||
const {
|
||||
admin: { user: userSlug },
|
||||
routes: { admin: adminRoute },
|
||||
} = config
|
||||
|
||||
let ViewToRender: React.FC<AdminViewProps>
|
||||
let ViewToRender
|
||||
let templateClassName
|
||||
let initPageResult: InitPageResult
|
||||
let pageData
|
||||
let templateType: 'default' | 'minimal' = 'default'
|
||||
|
||||
let route = adminRoute
|
||||
|
||||
let route = config.routes.admin
|
||||
if (Array.isArray(params.segments)) {
|
||||
route = route + '/' + params.segments.join('/')
|
||||
}
|
||||
@@ -92,12 +70,7 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
ViewToRender = Dashboard
|
||||
templateClassName = 'dashboard'
|
||||
templateType = 'default'
|
||||
initPageResult = await initPage({
|
||||
config,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route,
|
||||
searchParams,
|
||||
})
|
||||
pageData = await initPage({ config, redirectUnauthenticatedUser: true, route, searchParams })
|
||||
break
|
||||
}
|
||||
case 1: {
|
||||
@@ -108,13 +81,13 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
// --> /logout
|
||||
// --> /logout-inactivity
|
||||
// --> /unauthorized
|
||||
initPageResult = await initPage({ config, route, searchParams })
|
||||
pageData = await initPage({ config, route, searchParams })
|
||||
ViewToRender = oneSegmentViews[segmentOne]
|
||||
templateClassName = baseClasses[segmentOne]
|
||||
templateType = 'minimal'
|
||||
} else if (segmentOne === 'account') {
|
||||
// --> /account
|
||||
initPageResult = await initPage({
|
||||
pageData = await initPage({
|
||||
config,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route,
|
||||
@@ -129,14 +102,14 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
case 2: {
|
||||
if (segmentOne === 'reset') {
|
||||
// --> /reset/:token
|
||||
initPageResult = await initPage({ config, route, searchParams })
|
||||
pageData = await initPage({ config, route, searchParams })
|
||||
ViewToRender = ResetPassword
|
||||
templateClassName = baseClasses[segmentTwo]
|
||||
templateType = 'minimal'
|
||||
}
|
||||
if (isCollection) {
|
||||
// --> /collections/:collectionSlug
|
||||
initPageResult = await initPage({
|
||||
pageData = await initPage({
|
||||
config,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route,
|
||||
@@ -147,7 +120,7 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
templateType = 'default'
|
||||
} else if (isGlobal) {
|
||||
// --> /globals/:globalSlug
|
||||
initPageResult = await initPage({
|
||||
pageData = await initPage({
|
||||
config,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route,
|
||||
@@ -162,7 +135,7 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
default:
|
||||
if (segmentTwo === 'verify') {
|
||||
// --> /:collectionSlug/verify/:token
|
||||
initPageResult = await initPage({ config, route, searchParams })
|
||||
pageData = await initPage({ config, route, searchParams })
|
||||
ViewToRender = Verify
|
||||
templateClassName = 'verify'
|
||||
templateType = 'minimal'
|
||||
@@ -173,7 +146,7 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
// --> /collections/:collectionSlug/:id/versions
|
||||
// --> /collections/:collectionSlug/:id/versions/:versionId
|
||||
// --> /collections/:collectionSlug/:id/api
|
||||
initPageResult = await initPage({
|
||||
pageData = await initPage({
|
||||
config,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route,
|
||||
@@ -188,7 +161,7 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
// --> /globals/:globalSlug/preview
|
||||
// --> /globals/:globalSlug/versions/:versionId
|
||||
// --> /globals/:globalSlug/api
|
||||
initPageResult = await initPage({
|
||||
pageData = await initPage({
|
||||
config,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route,
|
||||
@@ -201,47 +174,22 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
break
|
||||
}
|
||||
|
||||
const dbHasUser = await initPageResult.req.payload.db
|
||||
.findOne({
|
||||
collection: userSlug,
|
||||
req: initPageResult.req,
|
||||
})
|
||||
?.then((doc) => !!doc)
|
||||
|
||||
const createFirstUserRoute = `${adminRoute}/create-first-user`
|
||||
|
||||
if (!dbHasUser && route !== createFirstUserRoute) {
|
||||
redirect(createFirstUserRoute)
|
||||
}
|
||||
|
||||
if (dbHasUser && route === createFirstUserRoute) {
|
||||
redirect(adminRoute)
|
||||
}
|
||||
|
||||
if (initPageResult) {
|
||||
if (pageData) {
|
||||
if (templateType === 'minimal') {
|
||||
return (
|
||||
<MinimalTemplate className={templateClassName}>
|
||||
<ViewToRender
|
||||
initPageResult={initPageResult}
|
||||
params={params}
|
||||
searchParams={searchParams}
|
||||
/>
|
||||
<ViewToRender page={pageData} params={params} searchParams={searchParams} />
|
||||
</MinimalTemplate>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<DefaultTemplate
|
||||
config={config}
|
||||
i18n={initPageResult.req.i18n}
|
||||
permissions={initPageResult.permissions}
|
||||
user={initPageResult.req.user}
|
||||
i18n={pageData.req.i18n}
|
||||
permissions={pageData.permissions}
|
||||
user={pageData.req.user}
|
||||
>
|
||||
<ViewToRender
|
||||
initPageResult={initPageResult}
|
||||
params={params}
|
||||
searchParams={searchParams}
|
||||
/>
|
||||
<ViewToRender page={pageData} params={params} searchParams={searchParams} />
|
||||
</DefaultTemplate>
|
||||
)
|
||||
}
|
||||
@@ -249,3 +197,21 @@ export const RootPage = async ({ config: configPromise, params, searchParams }:
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export const generateMeta = async ({ config: configPromise, params, searchParams }: Args) => {
|
||||
const config = await configPromise
|
||||
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: 'Payload',
|
||||
keywords: 'Payload',
|
||||
title: 'Payload',
|
||||
// description: `${t('authentication:logoutUser')}`,
|
||||
// keywords: `${t('authentication:logout')}`,
|
||||
// title: t('authentication:logout'),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
import { generateAccountMetadata } from '../Account'
|
||||
import { generateCreateFirstUserMetadata } from '../CreateFirstUser'
|
||||
import { generateDashboardMetadata } from '../Dashboard'
|
||||
import { generateForgotPasswordMetadata } from '../ForgotPassword'
|
||||
import { generateListMetadata } from '../List'
|
||||
import { generateLoginMetadata } from '../Login'
|
||||
import { generateResetPasswordMetadata } from '../ResetPassword'
|
||||
import { generateUnauthorizedMetadata } from '../Unauthorized'
|
||||
import { generateVerifyMetadata } from '../Verify'
|
||||
import { Metadata } from 'next'
|
||||
import { generateDocumentMetadata } from '../Document/meta'
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
|
||||
const oneSegmentMeta = {
|
||||
'create-first-user': generateCreateFirstUserMetadata,
|
||||
forgot: generateForgotPasswordMetadata,
|
||||
login: generateLoginMetadata,
|
||||
logout: generateUnauthorizedMetadata,
|
||||
'logout-inactivity': generateUnauthorizedMetadata,
|
||||
unauthorized: generateUnauthorizedMetadata,
|
||||
}
|
||||
|
||||
type Args = {
|
||||
config: Promise<SanitizedConfig>
|
||||
params: {
|
||||
[key: string]: string | string[]
|
||||
}
|
||||
searchParams: {
|
||||
[key: string]: string | string[]
|
||||
}
|
||||
}
|
||||
|
||||
export const generatePageMetadata = async ({ config: configPromise, params }: Args) => {
|
||||
const config = await configPromise
|
||||
|
||||
let route = config.routes.admin
|
||||
|
||||
if (Array.isArray(params.segments)) {
|
||||
route = route + '/' + params.segments.join('/')
|
||||
}
|
||||
|
||||
const segments = Array.isArray(params.segments) ? params.segments : []
|
||||
|
||||
const [segmentOne, segmentTwo] = segments
|
||||
|
||||
const isGlobal = segmentOne === 'globals'
|
||||
const isCollection = segmentOne === 'collections'
|
||||
|
||||
const i18n = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
let meta: Metadata
|
||||
|
||||
// TODO: handle custom routes
|
||||
|
||||
const collectionConfig =
|
||||
isCollection &&
|
||||
segments.length > 1 &&
|
||||
config?.collections?.find((collection) => collection.slug === segmentTwo)
|
||||
|
||||
const globalConfig =
|
||||
isGlobal && segments.length > 1 && config?.globals?.find((global) => global.slug === segmentTwo)
|
||||
|
||||
switch (segments.length) {
|
||||
case 0: {
|
||||
meta = await generateDashboardMetadata({ config, i18n })
|
||||
break
|
||||
}
|
||||
case 1: {
|
||||
if (oneSegmentMeta[segmentOne] && segmentOne !== 'account') {
|
||||
// --> /create-first-user
|
||||
// --> /forgot
|
||||
// --> /login
|
||||
// --> /logout
|
||||
// --> /logout-inactivity
|
||||
// --> /unauthorized
|
||||
meta = await oneSegmentMeta[segmentOne]({ config, i18n })
|
||||
break
|
||||
} else if (segmentOne === 'account') {
|
||||
// --> /account
|
||||
meta = await generateAccountMetadata({ config, i18n })
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
case 2: {
|
||||
if (segmentOne === 'reset') {
|
||||
// --> /reset/:token
|
||||
meta = await generateResetPasswordMetadata({ config, i18n })
|
||||
}
|
||||
if (isCollection) {
|
||||
// --> /collections/:collectionSlug
|
||||
meta = await generateListMetadata({ config, i18n, collectionConfig })
|
||||
} else if (isGlobal) {
|
||||
// --> /globals/:globalSlug
|
||||
meta = await generateDocumentMetadata({
|
||||
config,
|
||||
i18n,
|
||||
globalConfig,
|
||||
isEditing: false,
|
||||
params,
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
default: {
|
||||
if (segmentTwo === 'verify') {
|
||||
// --> /:collectionSlug/verify/:token
|
||||
meta = await generateVerifyMetadata({ config, i18n })
|
||||
} else if (isCollection) {
|
||||
// Custom Views
|
||||
// --> /collections/:collectionSlug/:id
|
||||
// --> /collections/:collectionSlug/:id/preview
|
||||
// --> /collections/:collectionSlug/:id/versions
|
||||
// --> /collections/:collectionSlug/:id/versions/:version
|
||||
// --> /collections/:collectionSlug/:id/api
|
||||
const isEditing = ['preview', 'versions', 'api', 'create'].includes(segmentTwo)
|
||||
meta = await generateDocumentMetadata({ config, i18n, collectionConfig, isEditing, params })
|
||||
} else if (isGlobal) {
|
||||
// Custom Views
|
||||
// --> /globals/:globalSlug/versions
|
||||
// --> /globals/:globalSlug/versions/:version
|
||||
// --> /globals/:globalSlug/preview
|
||||
// --> /globals/:globalSlug/api
|
||||
const isEditing = ['preview', 'versions', 'api', 'create'].includes(segmentTwo)
|
||||
meta = await generateDocumentMetadata({ config, i18n, globalConfig, isEditing, params })
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
import { Button, useTranslation } from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
export const UnauthorizedClient: React.FC<{ logoutRoute: string }> = ({ logoutRoute }) => {
|
||||
@@ -11,7 +10,7 @@ export const UnauthorizedClient: React.FC<{ logoutRoute: string }> = ({ logoutRo
|
||||
<h2>{t('error:unauthorized')}</h2>
|
||||
<p>{t('error:notAllowedToAccessPage')}</p>
|
||||
<br />
|
||||
<Button Link={Link} el="link" to={logoutRoute}>
|
||||
<Button el="link" to={logoutRoute}>
|
||||
{t('authentication:logOut')}
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -1,22 +1,43 @@
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
import { MinimalTemplate } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { UnauthorizedClient } from './UnauthorizedClient'
|
||||
|
||||
export { generateUnauthorizedMetadata } from './meta'
|
||||
|
||||
export const Unauthorized: React.FC<AdminViewProps> = ({ initPageResult }) => {
|
||||
export const generateMetadata = async ({ page }: { page: InitPageResult }): Promise<Metadata> => {
|
||||
const {
|
||||
req: {
|
||||
payload: {
|
||||
config: {
|
||||
admin: { logoutRoute },
|
||||
routes: { admin },
|
||||
},
|
||||
},
|
||||
payload: { config },
|
||||
t,
|
||||
},
|
||||
} = initPageResult
|
||||
} = page
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: t('error:unauthorized'),
|
||||
keywords: t('error:unauthorized'),
|
||||
title: t('error:unauthorized'),
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
page: InitPageResult
|
||||
}
|
||||
export const Unauthorized: React.FC<Props> = ({ page }) => {
|
||||
const {
|
||||
req: {
|
||||
payload: { config },
|
||||
},
|
||||
} = page
|
||||
|
||||
const {
|
||||
admin: { logoutRoute },
|
||||
routes: { admin },
|
||||
} = config
|
||||
|
||||
return <UnauthorizedClient logoutRoute={`${admin}${logoutRoute}`} />
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateUnauthorizedMetadata: GenerateViewMetadata = async ({
|
||||
config,
|
||||
i18n: { t },
|
||||
}) => {
|
||||
return meta({
|
||||
config,
|
||||
description: t('error:unauthorized'),
|
||||
keywords: t('error:unauthorized'),
|
||||
title: t('error:unauthorized'),
|
||||
})
|
||||
}
|
||||
@@ -1,20 +1,47 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Logo } from '@payloadcms/ui'
|
||||
import { redirect } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import type { AdminViewProps } from '../Root'
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { getNextI18n } from '../../utilities/getNextI18n'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import './index.scss'
|
||||
|
||||
export const verifyBaseClass = 'verify'
|
||||
const baseClass = 'verify'
|
||||
|
||||
export { generateVerifyMetadata } from './meta'
|
||||
export const generateMetadata = async ({
|
||||
config: configPromise,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig>
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
export const Verify: React.FC<AdminViewProps> = async ({ initPageResult, params }) => {
|
||||
const { t } = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:verifyUser'),
|
||||
keywords: t('authentication:verify'),
|
||||
title: t('authentication:verify'),
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
page: InitPageResult
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
}
|
||||
export const Verify: React.FC<Props> = async ({ page, params }) => {
|
||||
// /:collectionSlug/verify/:token
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [collectionSlug, verify, token] = params.segments
|
||||
const { req } = initPageResult
|
||||
const { req } = page
|
||||
|
||||
const {
|
||||
payload: { config },
|
||||
@@ -41,10 +68,11 @@ export const Verify: React.FC<AdminViewProps> = async ({ initPageResult, params
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={`${verifyBaseClass}__brand`}>
|
||||
<div className={`${baseClass}__brand`}>
|
||||
<Logo config={config} />
|
||||
</div>
|
||||
<h2>{textToRender}</h2>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
export default Verify
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { GenerateViewMetadata } from '../Root'
|
||||
|
||||
export const generateVerifyMetadata: GenerateViewMetadata = async ({ config, i18n: { t } }) => {
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:verifyUser'),
|
||||
keywords: t('authentication:verify'),
|
||||
title: t('authentication:verify'),
|
||||
})
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
formatDate,
|
||||
useComponentMap,
|
||||
useConfig,
|
||||
useDocumentInfo,
|
||||
usePayloadAPI,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
@@ -27,8 +26,11 @@ import './index.scss'
|
||||
const baseClass = 'view-version'
|
||||
|
||||
export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
id,
|
||||
collectionSlug,
|
||||
doc,
|
||||
docPermissions,
|
||||
globalSlug,
|
||||
initialComparisonDoc,
|
||||
localeOptions,
|
||||
mostRecentDoc,
|
||||
@@ -38,7 +40,6 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
const config = useConfig()
|
||||
|
||||
const { i18n } = useTranslation()
|
||||
const { id, collectionSlug, globalSlug } = useDocumentInfo()
|
||||
|
||||
const { getComponentMap, getFieldMap } = useComponentMap()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Option } from '@payloadcms/ui'
|
||||
import type { CollectionPermission, GlobalPermission } from 'payload/auth'
|
||||
import type { Document } from 'payload/types'
|
||||
import type { CollectionPermission, GlobalPermission, Permissions, User } from 'payload/auth'
|
||||
import type { Document, SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
export type CompareOption = {
|
||||
label: string
|
||||
@@ -10,11 +10,16 @@ export type CompareOption = {
|
||||
}
|
||||
|
||||
export type DefaultVersionsViewProps = {
|
||||
collectionSlug?: SanitizedCollectionConfig['slug']
|
||||
doc: Document
|
||||
docPermissions: CollectionPermission | GlobalPermission
|
||||
globalSlug?: SanitizedCollectionConfig['slug']
|
||||
id?: number | string
|
||||
initialComparisonDoc: Document
|
||||
localeOptions: Option[]
|
||||
mostRecentDoc: Document
|
||||
permissions: Permissions
|
||||
publishedDoc: Document
|
||||
user: User
|
||||
versionID?: string
|
||||
}
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
import type { Option } from '@payloadcms/ui'
|
||||
import type { CollectionPermission, GlobalPermission } from 'payload/auth'
|
||||
import type { Document, ServerSideEditViewProps } from 'payload/types'
|
||||
import type { Document } from 'payload/types'
|
||||
|
||||
import { notFound } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import type { InitPageResult } from '../../utilities/initPage'
|
||||
|
||||
import { DefaultVersionView } from './Default'
|
||||
|
||||
export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
|
||||
const { initPageResult, routeSegments } = props
|
||||
|
||||
type Props = {
|
||||
page: InitPageResult
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}
|
||||
export const VersionView: React.FC = async (props: Props) => {
|
||||
const { page, params } = props
|
||||
const {
|
||||
collectionConfig,
|
||||
docID: id,
|
||||
globalConfig,
|
||||
permissions,
|
||||
req: { payload, payload: { config } = {} } = {},
|
||||
} = initPageResult
|
||||
req: { payload, payload: { config } = {}, user } = {},
|
||||
} = page
|
||||
|
||||
// /entityType/:entitySlug/:id/versions/:versionID
|
||||
const [entityType, entitySlug, docID, versions, versionID] = routeSegments
|
||||
const [entityType, entitySlug, id, versions, versionID] = params.segments
|
||||
|
||||
const collectionSlug = collectionConfig?.slug
|
||||
const globalSlug = globalConfig?.slug
|
||||
@@ -109,12 +114,17 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
|
||||
|
||||
return (
|
||||
<DefaultVersionView
|
||||
collectionSlug={collectionSlug}
|
||||
doc={doc}
|
||||
docPermissions={docPermissions}
|
||||
globalSlug={globalSlug}
|
||||
id={id}
|
||||
initialComparisonDoc={mostRecentDoc}
|
||||
localeOptions={localeOptions}
|
||||
mostRecentDoc={mostRecentDoc}
|
||||
permissions={permissions}
|
||||
publishedDoc={publishedDoc}
|
||||
user={user}
|
||||
versionID={versionID}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
SetViewActions,
|
||||
Table,
|
||||
useComponentMap,
|
||||
useDocumentInfo,
|
||||
usePayloadAPI,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
@@ -19,15 +18,26 @@ import React, { Fragment, useEffect, useRef } from 'react'
|
||||
|
||||
export const VersionsViewClient: React.FC<{
|
||||
baseClass: string
|
||||
collectionSlug?: string
|
||||
columns: Column[]
|
||||
fetchURL: string
|
||||
globalSlug?: string
|
||||
id?: number | string
|
||||
initialData: PaginatedDocs
|
||||
paginationLimits?: SanitizedCollectionConfig['admin']['pagination']['limits']
|
||||
}> = (props) => {
|
||||
const { baseClass, columns, fetchURL, initialData, paginationLimits } = props
|
||||
const {
|
||||
id,
|
||||
baseClass,
|
||||
collectionSlug,
|
||||
columns,
|
||||
fetchURL,
|
||||
globalSlug,
|
||||
initialData,
|
||||
paginationLimits,
|
||||
} = props
|
||||
|
||||
const { getComponentMap } = useComponentMap()
|
||||
const { id, collectionSlug, globalSlug } = useDocumentInfo()
|
||||
|
||||
const componentMap = getComponentMap({
|
||||
collectionSlug,
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import type { ServerSideEditViewProps } from 'payload/types'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { Gutter } from '@payloadcms/ui'
|
||||
import { notFound } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import type { ServerSideEditViewProps } from '../Edit/types'
|
||||
|
||||
import { SetStepNav } from '../Edit/Default/SetStepNav'
|
||||
import { sanitizeEditViewProps } from '../Edit/sanitizeEditViewProps'
|
||||
import { buildVersionColumns } from './buildColumns'
|
||||
import { VersionsViewClient } from './index.client'
|
||||
import './index.scss'
|
||||
@@ -12,29 +14,25 @@ import './index.scss'
|
||||
export const baseClass = 'versions'
|
||||
|
||||
export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
const { initPageResult, searchParams } = props
|
||||
const { config, i18n, payload, searchParams, user } = props
|
||||
|
||||
const {
|
||||
collectionConfig,
|
||||
docID: id,
|
||||
globalConfig,
|
||||
req: {
|
||||
i18n,
|
||||
payload,
|
||||
payload: { config },
|
||||
user,
|
||||
},
|
||||
} = initPageResult
|
||||
const id = 'id' in props ? props.id : undefined
|
||||
const collectionConfig = 'collectionConfig' in props && props?.collectionConfig
|
||||
const globalConfig = 'globalConfig' in props && props?.globalConfig
|
||||
|
||||
const collectionSlug = collectionConfig?.slug
|
||||
const globalSlug = globalConfig?.slug
|
||||
const { limit, page, sort } = searchParams
|
||||
|
||||
const {
|
||||
routes: { api: apiRoute },
|
||||
routes: { admin: adminRoute, api: apiRoute },
|
||||
serverURL,
|
||||
} = config
|
||||
|
||||
let docURL: string
|
||||
let entityLabel: string
|
||||
let slug: string
|
||||
let editURL: string
|
||||
let versionsData
|
||||
|
||||
if (collectionSlug) {
|
||||
@@ -53,8 +51,12 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error) // eslint-disable-line no-console
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
docURL = `${serverURL}${apiRoute}/${slug}/${id}`
|
||||
entityLabel = getTranslation(collectionConfig.labels.singular, i18n)
|
||||
editURL = `${adminRoute}/collections/${collectionSlug}/${id}`
|
||||
}
|
||||
|
||||
if (globalSlug) {
|
||||
@@ -72,12 +74,16 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error) // eslint-disable-line no-console
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
if (!versionsData) {
|
||||
return notFound()
|
||||
}
|
||||
|
||||
docURL = `${serverURL}${apiRoute}/globals/${globalSlug}`
|
||||
entityLabel = getTranslation(globalConfig.label, i18n)
|
||||
editURL = `${adminRoute}/globals/${globalSlug}`
|
||||
}
|
||||
|
||||
const columns = buildVersionColumns({
|
||||
@@ -94,6 +100,8 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
? `${serverURL}${apiRoute}/globals/${globalSlug}/versions`
|
||||
: ''
|
||||
|
||||
const clientSideProps = sanitizeEditViewProps(props)
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<SetStepNav
|
||||
@@ -107,9 +115,11 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
<main className={baseClass}>
|
||||
<Gutter className={`${baseClass}__wrap`}>
|
||||
<VersionsViewClient
|
||||
{...clientSideProps}
|
||||
baseClass={baseClass}
|
||||
columns={columns}
|
||||
fetchURL={fetchURL}
|
||||
id={id}
|
||||
initialData={versionsData}
|
||||
paginationLimits={collectionConfig?.admin?.pagination?.limits}
|
||||
/>
|
||||
|
||||
@@ -14,14 +14,11 @@ const withPayload = (nextConfig = {}) => {
|
||||
},
|
||||
serverComponentsExternalPackages: [
|
||||
...(nextConfig?.experimental?.serverComponentsExternalPackages || []),
|
||||
'@payloadcms/db-mongodb',
|
||||
'@payloadcms/db-postgres',
|
||||
'drizzle-kit',
|
||||
'drizzle-kit/payload',
|
||||
'libsql',
|
||||
'pino',
|
||||
'pino-pretty',
|
||||
'payload',
|
||||
],
|
||||
},
|
||||
webpack: (webpackConfig, webpackOptions) => {
|
||||
@@ -70,4 +67,4 @@ const withPayload = (nextConfig = {}) => {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = withPayload
|
||||
module.exports = { withPayload }
|
||||
|
||||
@@ -1,41 +1,2 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const { getTsconfig } = require('get-tsconfig')
|
||||
const path = require('path')
|
||||
const swcRegister = require('@swc/register')
|
||||
|
||||
const tsConfig = getTsconfig()
|
||||
|
||||
const swcOptions = {
|
||||
ignore: [/.*[\\/]node_modules[\\/].*/],
|
||||
jsc: {
|
||||
baseUrl: path.resolve(),
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
tsx: true,
|
||||
},
|
||||
paths: undefined,
|
||||
},
|
||||
module: {
|
||||
type: 'commonjs',
|
||||
},
|
||||
sourceMaps: 'inline',
|
||||
}
|
||||
if (tsConfig?.config?.compilerOptions?.paths) {
|
||||
swcOptions.jsc.paths = tsConfig.config.compilerOptions.paths
|
||||
if (tsConfig?.config?.compilerOptions?.baseUrl) {
|
||||
swcOptions.jsc.baseUrl = path.resolve(tsConfig.config.compilerOptions.baseUrl)
|
||||
}
|
||||
}
|
||||
// Allow disabling SWC for debugging
|
||||
if (process.env.DISABLE_SWC !== 'true') {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error - bad @swc/register types
|
||||
swcRegister(swcOptions)
|
||||
}
|
||||
|
||||
const bin = async () => {
|
||||
await import('./dist/bin/index.js')
|
||||
}
|
||||
|
||||
bin()
|
||||
require('./dist/bin')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.0.0-alpha.19",
|
||||
"version": "3.0.0-alpha.10",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -113,7 +113,10 @@
|
||||
"rimraf": "3.0.2",
|
||||
"serve-static": "1.15.0",
|
||||
"ts-essentials": "7.0.3",
|
||||
"sharp": "0.32.6"
|
||||
"sharp": "0.33.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"sharp": "0.33.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
|
||||
@@ -1,29 +1,3 @@
|
||||
import type { ClientValidate, Field } from '../../fields/config/types'
|
||||
|
||||
export type Data = {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export type Row = {
|
||||
blockType?: string
|
||||
collapsed?: boolean
|
||||
errorPaths?: Set<string>
|
||||
id: string
|
||||
}
|
||||
|
||||
export type FormField = {
|
||||
disableFormData?: boolean
|
||||
errorMessage?: string
|
||||
errorPaths?: Set<string>
|
||||
fieldSchema?: Field
|
||||
initialValue: unknown
|
||||
passesCondition?: boolean
|
||||
rows?: Row[]
|
||||
valid: boolean
|
||||
validate?: ClientValidate
|
||||
value: unknown
|
||||
}
|
||||
|
||||
export type FormState = {
|
||||
[path: string]: FormField
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user