chore(next): lints
This commit is contained in:
10
packages/next/.eslintignore
Normal file
10
packages/next/.eslintignore
Normal file
@@ -0,0 +1,10 @@
|
||||
.tmp
|
||||
**/.git
|
||||
**/.hg
|
||||
**/.pnp.*
|
||||
**/.svn
|
||||
**/.yarn/**
|
||||
**/build
|
||||
**/dist/**
|
||||
**/node_modules
|
||||
**/temp
|
||||
44
packages/next/.eslintrc.js
Normal file
44
packages/next/.eslintrc.js
Normal file
@@ -0,0 +1,44 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'@payloadcms',
|
||||
// 'next'
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
|
||||
},
|
||||
{
|
||||
files: ['package.json', 'tsconfig.json'],
|
||||
rules: {
|
||||
'perfectionist/sort-array-includes': 'off',
|
||||
'perfectionist/sort-astro-attributes': 'off',
|
||||
'perfectionist/sort-classes': 'off',
|
||||
'perfectionist/sort-enums': 'off',
|
||||
'perfectionist/sort-exports': 'off',
|
||||
'perfectionist/sort-imports': 'off',
|
||||
'perfectionist/sort-interfaces': 'off',
|
||||
'perfectionist/sort-jsx-props': 'off',
|
||||
'perfectionist/sort-keys': 'off',
|
||||
'perfectionist/sort-maps': 'off',
|
||||
'perfectionist/sort-named-exports': 'off',
|
||||
'perfectionist/sort-named-imports': 'off',
|
||||
'perfectionist/sort-object-types': 'off',
|
||||
'perfectionist/sort-objects': 'off',
|
||||
'perfectionist/sort-svelte-attributes': 'off',
|
||||
'perfectionist/sort-union-types': 'off',
|
||||
'perfectionist/sort-vue-attributes': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
root: true,
|
||||
settings: {
|
||||
next: {
|
||||
rootDir: '../../app/',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
"clean": "rimraf {dist,*.tsbuildinfo}",
|
||||
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" \"src/app/api/**\" dist/ && pnpm copyfiles:api",
|
||||
"copyfiles:api": "copyfiles -u 1 \"src/app/api/**\" dist/template",
|
||||
"fix": "eslint \"src/**/*.{ts,tsx}\" --fix",
|
||||
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
||||
"prepublishOnly": "pnpm clean && pnpm build"
|
||||
},
|
||||
"exports": {
|
||||
@@ -38,6 +40,9 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/eslint-plugin-next": "^14.1.0",
|
||||
"@types/react": "18.2.15",
|
||||
"@types/react-dom": "18.2.7",
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"payload": "workspace:*",
|
||||
"sass": "^1.70.0"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
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,6 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import { GET_STATIC_FILE } from '@payloadcms/next/routes'
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { GET_STATIC_FILE } from '@payloadcms/next/routes'
|
||||
|
||||
export const GET = GET_STATIC_FILE(config)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import { GRAPHQL_POST } from '@payloadcms/next/routes'
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from 'payload-config'
|
||||
import { GRAPHQL_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export const POST = GRAPHQL_POST(config)
|
||||
|
||||
@@ -11,7 +11,7 @@ import { install } from './install'
|
||||
main()
|
||||
|
||||
async function main() {
|
||||
if (debug) console.log({ pwd: process.cwd(), debug })
|
||||
if (debug) console.log({ debug, pwd: process.cwd() })
|
||||
switch (script.toLowerCase()) {
|
||||
case 'install': {
|
||||
if (debug) console.log('Running install')
|
||||
|
||||
@@ -17,11 +17,11 @@ export const install = (args?: { debug?: boolean }): Promise<void> => {
|
||||
|
||||
if (debug) {
|
||||
console.log({
|
||||
useSrc,
|
||||
basePath,
|
||||
apiTemplateDir,
|
||||
userApiDir,
|
||||
basePath,
|
||||
cwd: process.cwd(),
|
||||
useSrc,
|
||||
userApiDir,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { SanitizedConfig } from 'payload/config'
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
|
||||
export default {} as Promise<SanitizedConfig>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React from 'react'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { DefaultTemplate } from '@payloadcms/ui'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import React from 'react'
|
||||
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
|
||||
export const metadata = {
|
||||
title: 'Next.js',
|
||||
description: 'Generated by Next.js',
|
||||
title: 'Next.js',
|
||||
}
|
||||
|
||||
export const AdminLayout = async ({
|
||||
@@ -17,10 +18,10 @@ export const AdminLayout = async ({
|
||||
children: React.ReactNode
|
||||
config: Promise<SanitizedConfig> | SanitizedConfig
|
||||
}) => {
|
||||
const { user, permissions, i18n } = await initPage({ config })
|
||||
const { i18n, permissions, user } = await initPage({ config })
|
||||
|
||||
return (
|
||||
<DefaultTemplate config={config} user={user} permissions={permissions} i18n={i18n}>
|
||||
<DefaultTemplate config={config} i18n={i18n} permissions={permissions} user={user}>
|
||||
{children}
|
||||
</DefaultTemplate>
|
||||
)
|
||||
|
||||
@@ -1,39 +1,40 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { DocumentHeader } from '@payloadcms/ui'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
|
||||
export const metadata = {
|
||||
title: 'Next.js',
|
||||
description: 'Generated by Next.js',
|
||||
title: 'Next.js',
|
||||
}
|
||||
|
||||
export const DocumentLayout = async ({
|
||||
children,
|
||||
config: configPromise,
|
||||
collectionSlug,
|
||||
config: configPromise,
|
||||
globalSlug,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
config: Promise<SanitizedConfig>
|
||||
collectionSlug?: string
|
||||
config: Promise<SanitizedConfig>
|
||||
globalSlug?: string
|
||||
}) => {
|
||||
const { config, collectionConfig, globalConfig, i18n } = await initPage({
|
||||
config: configPromise,
|
||||
const { collectionConfig, config, globalConfig, i18n } = await initPage({
|
||||
collectionSlug,
|
||||
config: configPromise,
|
||||
globalSlug,
|
||||
})
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<DocumentHeader
|
||||
i18n={i18n}
|
||||
config={config}
|
||||
collectionConfig={collectionConfig}
|
||||
config={config}
|
||||
globalConfig={globalConfig}
|
||||
i18n={i18n}
|
||||
/>
|
||||
{children}
|
||||
</Fragment>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import React from 'react'
|
||||
import { headers, cookies } from 'next/headers'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { translations } from '@payloadcms/translations/client'
|
||||
import { RootProvider, buildComponentMap } from '@payloadcms/ui'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import { cookies, headers } from 'next/headers'
|
||||
import { deepMerge } from 'payload/utilities'
|
||||
import React from 'react'
|
||||
|
||||
import { createClientConfig } from '../../utilities/createClientConfig'
|
||||
import { getRequestLanguage } from '../../utilities/getRequestLanguage'
|
||||
import { deepMerge } from 'payload/utilities'
|
||||
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
|
||||
export const metadata = {
|
||||
title: 'Next.js',
|
||||
description: 'Generated by Next.js',
|
||||
title: 'Next.js',
|
||||
}
|
||||
|
||||
const rtlLanguages = ['ar', 'fa', 'ha', 'ku', 'ur', 'ps', 'dv', 'ks', 'khw', 'he', 'yi']
|
||||
@@ -28,8 +29,8 @@ export const RootLayout = async ({
|
||||
|
||||
const lang =
|
||||
getRequestLanguage({
|
||||
headers: headers(),
|
||||
cookies: cookies(),
|
||||
headers: headers(),
|
||||
}) ?? clientConfig.i18n.fallbackLanguage
|
||||
|
||||
const dir = rtlLanguages.includes(lang) ? 'RTL' : 'LTR'
|
||||
@@ -44,15 +45,15 @@ export const RootLayout = async ({
|
||||
const componentMap = buildComponentMap({ config })
|
||||
|
||||
return (
|
||||
<html lang={lang} dir={dir}>
|
||||
<html dir={dir} lang={lang}>
|
||||
<body>
|
||||
<RootProvider
|
||||
config={clientConfig}
|
||||
translations={mergedTranslations[lang]}
|
||||
lang={lang}
|
||||
fallbackLang={clientConfig.i18n.fallbackLanguage}
|
||||
languageOptions={languageOptions}
|
||||
componentMap={componentMap}
|
||||
config={clientConfig}
|
||||
fallbackLang={clientConfig.i18n.fallbackLanguage}
|
||||
lang={lang}
|
||||
languageOptions={languageOptions}
|
||||
translations={mergedTranslations[lang]}
|
||||
>
|
||||
{children}
|
||||
</RootProvider>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { FileShape, NextFileUploadOptions } from '.'
|
||||
import type { FileShape, NextFileUploadOptions } from '.'
|
||||
|
||||
import {
|
||||
isFunc,
|
||||
checkAndMakeDir,
|
||||
debugLog,
|
||||
isFunc,
|
||||
moveFile,
|
||||
promiseCallback,
|
||||
checkAndMakeDir,
|
||||
saveBufferToFile,
|
||||
} from './utilities'
|
||||
|
||||
@@ -34,13 +35,13 @@ const moveFromBuffer: MoveFile = (filePath, options, fileUploadOptions) => (reso
|
||||
|
||||
type FileFactoryOptions = {
|
||||
buffer: Buffer
|
||||
name: string
|
||||
tempFilePath: string
|
||||
hash: Buffer | string
|
||||
size: number
|
||||
encoding: string
|
||||
truncated: boolean
|
||||
hash: Buffer | string
|
||||
mimetype: string
|
||||
name: string
|
||||
size: number
|
||||
tempFilePath: string
|
||||
truncated: boolean
|
||||
}
|
||||
type FileFactory = (
|
||||
options: FileFactoryOptions,
|
||||
@@ -56,12 +57,9 @@ export const fileFactory: FileFactory = (options, fileUploadOptions) => {
|
||||
return {
|
||||
name: options.name,
|
||||
data: options.buffer,
|
||||
size: options.size,
|
||||
encoding: options.encoding,
|
||||
tempFilePath: options.tempFilePath,
|
||||
truncated: options.truncated,
|
||||
mimetype: options.mimetype,
|
||||
md5: options.hash,
|
||||
mimetype: options.mimetype,
|
||||
mv: (filePath: string, callback) => {
|
||||
// Define a proper move function.
|
||||
const moveFunc = fileUploadOptions.useTempFiles
|
||||
@@ -73,5 +71,8 @@ export const fileFactory: FileFactory = (options, fileUploadOptions) => {
|
||||
const defaultReject = () => undefined
|
||||
return isFunc(callback) ? moveFunc(callback, defaultReject) : new Promise(moveFunc)
|
||||
},
|
||||
size: options.size,
|
||||
tempFilePath: options.tempFilePath,
|
||||
truncated: options.truncated,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import { NextFileUploadOptions } from '.'
|
||||
|
||||
import crypto from 'crypto'
|
||||
import fs, { WriteStream } from 'fs'
|
||||
import path from 'path'
|
||||
import crypto from 'crypto'
|
||||
import { debugLog, checkAndMakeDir, getTempFilename, deleteFile } from './utilities'
|
||||
|
||||
import type { NextFileUploadOptions } from '.'
|
||||
|
||||
import { checkAndMakeDir, debugLog, deleteFile, getTempFilename } from './utilities'
|
||||
|
||||
type Handler = (
|
||||
options: NextFileUploadOptions,
|
||||
fieldname: string,
|
||||
filename: string,
|
||||
) => {
|
||||
cleanup: () => void
|
||||
complete: () => Buffer
|
||||
dataHandler: (data: Buffer) => void
|
||||
getFilePath: () => string
|
||||
getFileSize: () => number
|
||||
getHash: () => string
|
||||
complete: () => Buffer
|
||||
cleanup: () => void
|
||||
getWritePromise: () => Promise<boolean>
|
||||
}
|
||||
|
||||
@@ -41,6 +42,23 @@ export const tempFileHandler: Handler = (options, fieldname, filename) => {
|
||||
})
|
||||
|
||||
return {
|
||||
cleanup: () => {
|
||||
completed = true
|
||||
debugLog(options, `Cleaning up temporary file ${tempFilePath}...`)
|
||||
writeStream.end()
|
||||
deleteFile(tempFilePath, (err) =>
|
||||
err
|
||||
? debugLog(options, `Cleaning up temporary file ${tempFilePath} failed: ${err}`)
|
||||
: debugLog(options, `Cleaning up temporary file ${tempFilePath} done.`),
|
||||
)
|
||||
},
|
||||
complete: () => {
|
||||
completed = true
|
||||
debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`)
|
||||
if (writeStream instanceof WriteStream) writeStream.end()
|
||||
// Return empty buff since data was uploaded into a temp file.
|
||||
return Buffer.concat([])
|
||||
},
|
||||
dataHandler: (data) => {
|
||||
if (completed === true) {
|
||||
debugLog(options, `Error: got ${fieldname}->${filename} data chunk for completed upload!`)
|
||||
@@ -54,23 +72,6 @@ export const tempFileHandler: Handler = (options, fieldname, filename) => {
|
||||
getFilePath: () => tempFilePath,
|
||||
getFileSize: () => fileSize,
|
||||
getHash: () => hash.digest('hex'),
|
||||
complete: () => {
|
||||
completed = true
|
||||
debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`)
|
||||
if (writeStream instanceof WriteStream) writeStream.end()
|
||||
// Return empty buff since data was uploaded into a temp file.
|
||||
return Buffer.concat([])
|
||||
},
|
||||
cleanup: () => {
|
||||
completed = true
|
||||
debugLog(options, `Cleaning up temporary file ${tempFilePath}...`)
|
||||
writeStream.end()
|
||||
deleteFile(tempFilePath, (err) =>
|
||||
err
|
||||
? debugLog(options, `Cleaning up temporary file ${tempFilePath} failed: ${err}`)
|
||||
: debugLog(options, `Cleaning up temporary file ${tempFilePath} done.`),
|
||||
)
|
||||
},
|
||||
getWritePromise: () => writePromise,
|
||||
}
|
||||
}
|
||||
@@ -84,6 +85,14 @@ export const memHandler: Handler = (options, fieldname, filename) => {
|
||||
const getBuffer = () => Buffer.concat(buffers, fileSize)
|
||||
|
||||
return {
|
||||
cleanup: () => {
|
||||
completed = true
|
||||
},
|
||||
complete: () => {
|
||||
debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`)
|
||||
completed = true
|
||||
return getBuffer()
|
||||
},
|
||||
dataHandler: (data) => {
|
||||
if (completed === true) {
|
||||
debugLog(options, `Error: got ${fieldname}->${filename} data chunk for completed upload!`)
|
||||
@@ -97,14 +106,6 @@ export const memHandler: Handler = (options, fieldname, filename) => {
|
||||
getFilePath: () => '',
|
||||
getFileSize: () => fileSize,
|
||||
getHash: () => hash.digest('hex'),
|
||||
complete: () => {
|
||||
debugLog(options, `Upload ${fieldname}->${filename} completed, bytes:${fileSize}.`)
|
||||
completed = true
|
||||
return getBuffer()
|
||||
},
|
||||
cleanup: () => {
|
||||
completed = true
|
||||
},
|
||||
getWritePromise: () => Promise.resolve(true),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +1,70 @@
|
||||
import path from 'path'
|
||||
|
||||
import type { BusboyConfig } from 'busboy'
|
||||
|
||||
import { processMultipart } from './processMultipart'
|
||||
import path from 'path'
|
||||
|
||||
import { isEligibleRequest } from './isEligibleRequest'
|
||||
import { processMultipart } from './processMultipart'
|
||||
import { debugLog } from './utilities'
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
debug: false,
|
||||
uploadTimeout: 60000,
|
||||
fileHandler: false,
|
||||
uriDecodeFileNames: false,
|
||||
safeFileNames: false,
|
||||
preserveExtension: false,
|
||||
abortOnLimit: false,
|
||||
responseOnLimit: 'File size limit has been reached',
|
||||
limitHandler: false,
|
||||
createParentPath: false,
|
||||
debug: false,
|
||||
fileHandler: false,
|
||||
limitHandler: false,
|
||||
parseNested: false,
|
||||
useTempFiles: false,
|
||||
preserveExtension: false,
|
||||
responseOnLimit: 'File size limit has been reached',
|
||||
safeFileNames: false,
|
||||
tempFileDir: path.join(process.cwd(), 'tmp'),
|
||||
uploadTimeout: 60000,
|
||||
uriDecodeFileNames: false,
|
||||
useTempFiles: false,
|
||||
}
|
||||
|
||||
export type FileShape = {
|
||||
name: string
|
||||
data: Buffer
|
||||
size: number
|
||||
encoding: string
|
||||
md5: Buffer | string
|
||||
mimetype: string
|
||||
mv: (filePath: string, callback: () => void) => Promise<void> | void
|
||||
name: string
|
||||
size: number
|
||||
tempFilePath: string
|
||||
truncated: boolean
|
||||
mimetype: string
|
||||
md5: Buffer | string
|
||||
mv: (filePath: string, callback: () => void) => void | Promise<void>
|
||||
}
|
||||
|
||||
export type NextFileUploadOptions = {
|
||||
/**
|
||||
* Returns a HTTP 413 when the file is bigger than the size limit if `true`.
|
||||
* Otherwise, it will add a `truncated = true` to the resulting file structure.
|
||||
* @default false
|
||||
*/
|
||||
abortOnLimit?: boolean | undefined
|
||||
/**
|
||||
* Automatically creates the directory path specified in `.mv(filePathName)`
|
||||
* @default false
|
||||
*/
|
||||
createParentPath?: boolean | undefined
|
||||
/**
|
||||
* Applies uri decoding to file names if set `true`.
|
||||
* Turn on/off upload process logging. Can be useful for troubleshooting.
|
||||
* @default false
|
||||
*/
|
||||
uriDecodeFileNames?: boolean | undefined
|
||||
debug?: boolean | undefined
|
||||
/**
|
||||
* Strips characters from the upload's filename.
|
||||
* You can use custom regex to determine what to strip.
|
||||
* If set to `true`, non-alphanumeric characters _except_ dashes and underscores will be stripped.
|
||||
* This option is off by default.
|
||||
* User defined limit handler which will be invoked if the file is bigger than configured limits.
|
||||
* @default false
|
||||
*
|
||||
* @example
|
||||
* // strip slashes from file names
|
||||
* app.use(fileUpload({ safeFileNames: /\\/g }))
|
||||
*
|
||||
* @example
|
||||
* app.use(fileUpload({ safeFileNames: true }))
|
||||
*/
|
||||
safeFileNames?: boolean | RegExp | undefined
|
||||
limitHandler?: ((args: { request: Request; size: number }) => void) | boolean | undefined
|
||||
/**
|
||||
* By default, `req.body` and `req.files` are flattened like this:
|
||||
* `{'name': 'John', 'hobbies[0]': 'Cinema', 'hobbies[1]': 'Bike'}
|
||||
*
|
||||
* When this option is enabled they are parsed in order to be nested like this:
|
||||
* `{'name': 'John', 'hobbies': ['Cinema', 'Bike']}`
|
||||
* @default false
|
||||
*/
|
||||
parseNested?: boolean | undefined
|
||||
/**
|
||||
* Preserves filename extension when using `safeFileNames` option.
|
||||
* If set to `true`, will default to an extension length of `3`.
|
||||
@@ -79,30 +84,26 @@ export type NextFileUploadOptions = {
|
||||
* // myFileName.ext --> myFileNamee.xt
|
||||
*/
|
||||
preserveExtension?: boolean | number | undefined
|
||||
/**
|
||||
* Returns a HTTP 413 when the file is bigger than the size limit if `true`.
|
||||
* Otherwise, it will add a `truncated = true` to the resulting file structure.
|
||||
* @default false
|
||||
*/
|
||||
abortOnLimit?: boolean | undefined
|
||||
/**
|
||||
* Response which will be send to client if file size limit exceeded when `abortOnLimit` set to `true`.
|
||||
* @default 'File size limit has been reached'
|
||||
*/
|
||||
responseOnLimit?: string | undefined
|
||||
/**
|
||||
* User defined limit handler which will be invoked if the file is bigger than configured limits.
|
||||
* Strips characters from the upload's filename.
|
||||
* You can use custom regex to determine what to strip.
|
||||
* If set to `true`, non-alphanumeric characters _except_ dashes and underscores will be stripped.
|
||||
* This option is off by default.
|
||||
* @default false
|
||||
*
|
||||
* @example
|
||||
* // strip slashes from file names
|
||||
* app.use(fileUpload({ safeFileNames: /\\/g }))
|
||||
*
|
||||
* @example
|
||||
* app.use(fileUpload({ safeFileNames: true }))
|
||||
*/
|
||||
limitHandler?: boolean | ((args: { request: Request; size: number }) => void) | undefined
|
||||
/**
|
||||
* By default this module uploads files into RAM.
|
||||
* Setting this option to `true` turns on using temporary files instead of utilising RAM.
|
||||
* This avoids memory overflow issues when uploading large files or in case of uploading
|
||||
* lots of files at same time.
|
||||
* @default false
|
||||
*/
|
||||
useTempFiles?: boolean | undefined
|
||||
safeFileNames?: RegExp | boolean | undefined
|
||||
/**
|
||||
* Path to store temporary files.
|
||||
* Used along with the `useTempFiles` option. By default this module uses `'tmp'` folder
|
||||
@@ -111,25 +112,24 @@ export type NextFileUploadOptions = {
|
||||
* @default './tmp'
|
||||
*/
|
||||
tempFileDir?: string | undefined
|
||||
/**
|
||||
* By default, `req.body` and `req.files` are flattened like this:
|
||||
* `{'name': 'John', 'hobbies[0]': 'Cinema', 'hobbies[1]': 'Bike'}
|
||||
*
|
||||
* When this option is enabled they are parsed in order to be nested like this:
|
||||
* `{'name': 'John', 'hobbies': ['Cinema', 'Bike']}`
|
||||
* @default false
|
||||
*/
|
||||
parseNested?: boolean | undefined
|
||||
/**
|
||||
* Turn on/off upload process logging. Can be useful for troubleshooting.
|
||||
* @default false
|
||||
*/
|
||||
debug?: boolean | undefined
|
||||
/**
|
||||
* This defines how long to wait for data before aborting. Set to `0` if you want to turn off timeout checks.
|
||||
* @default 60_000
|
||||
*/
|
||||
uploadTimeout?: number | undefined
|
||||
/**
|
||||
* Applies uri decoding to file names if set `true`.
|
||||
* @default false
|
||||
*/
|
||||
uriDecodeFileNames?: boolean | undefined
|
||||
/**
|
||||
* By default this module uploads files into RAM.
|
||||
* Setting this option to `true` turns on using temporary files instead of utilising RAM.
|
||||
* This avoids memory overflow issues when uploading large files or in case of uploading
|
||||
* lots of files at same time.
|
||||
* @default false
|
||||
*/
|
||||
useTempFiles?: boolean | undefined
|
||||
} & Partial<BusboyConfig>
|
||||
|
||||
type NextFileUploadResponseFile = {
|
||||
@@ -141,29 +141,29 @@ type NextFileUploadResponseFile = {
|
||||
}
|
||||
|
||||
export type NextFileUploadResponse = {
|
||||
files: Record<string, NextFileUploadResponseFile>
|
||||
fields: Record<string, string>
|
||||
error?: {
|
||||
code: number
|
||||
message: string
|
||||
}
|
||||
fields: Record<string, string>
|
||||
files: Record<string, NextFileUploadResponseFile>
|
||||
}
|
||||
|
||||
type NextFileUpload = (args: {
|
||||
options?: NextFileUploadOptions
|
||||
request: Request
|
||||
}) => Promise<NextFileUploadResponse>
|
||||
export const nextFileUpload: NextFileUpload = async ({ request, options }) => {
|
||||
export const nextFileUpload: NextFileUpload = async ({ options, request }) => {
|
||||
const uploadOptions = { ...DEFAULT_OPTIONS, ...options }
|
||||
if (!isEligibleRequest(request)) {
|
||||
debugLog(uploadOptions, 'Request is not eligible for file upload!')
|
||||
return {
|
||||
files: undefined,
|
||||
fields: undefined,
|
||||
error: {
|
||||
code: 500,
|
||||
message: 'Request is not eligible for file upload',
|
||||
},
|
||||
fields: undefined,
|
||||
files: undefined,
|
||||
}
|
||||
} else {
|
||||
return processMultipart({ options: uploadOptions, request })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const ACCEPTABLE_CONTENT_TYPE = /^multipart\/[\w'"()+-_?/:=,.]+(?:; ?[\w'"()+-_?/:=,.]*)+$/i
|
||||
const ACCEPTABLE_CONTENT_TYPE = /^multipart\/['"()+-_]+(?:; ?['"()+-_]*)+$/i
|
||||
const UNACCEPTABLE_METHODS = new Set(['GET', 'HEAD', 'DELETE', 'OPTIONS', 'CONNECT', 'TRACE'])
|
||||
|
||||
const hasBody = (req: Request): boolean => {
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import Busboy from 'busboy'
|
||||
import { createUploadTimer } from './uploadTimer'
|
||||
import { fileFactory } from './fileFactory'
|
||||
import { tempFileHandler, memHandler } from './handlers'
|
||||
|
||||
import { processNested } from './processNested'
|
||||
import { isFunc, debugLog, buildFields, parseFileName } from './utilities'
|
||||
import { NextFileUploadOptions, NextFileUploadResponse } from '.'
|
||||
import { APIError } from 'payload/errors'
|
||||
|
||||
import type { NextFileUploadOptions, NextFileUploadResponse } from '.'
|
||||
|
||||
import { fileFactory } from './fileFactory'
|
||||
import { memHandler, tempFileHandler } from './handlers'
|
||||
import { processNested } from './processNested'
|
||||
import { createUploadTimer } from './uploadTimer'
|
||||
import { buildFields, debugLog, isFunc, parseFileName } from './utilities'
|
||||
|
||||
const waitFlushProperty = Symbol('wait flush property symbol')
|
||||
|
||||
type ProcessMultipart = (args: {
|
||||
options: NextFileUploadOptions
|
||||
request: Request
|
||||
}) => Promise<NextFileUploadResponse>
|
||||
export const processMultipart: ProcessMultipart = async ({ request, options }) => {
|
||||
export const processMultipart: ProcessMultipart = async ({ options, request }) => {
|
||||
let parsingRequest = true
|
||||
let result: NextFileUploadResponse = {
|
||||
const result: NextFileUploadResponse = {
|
||||
fields: undefined,
|
||||
files: undefined,
|
||||
}
|
||||
@@ -36,11 +37,11 @@ export const processMultipart: ProcessMultipart = async ({ request, options }) =
|
||||
// Build req.files fields
|
||||
busboy.on('file', (field, file, info) => {
|
||||
// Parse file name(cutting huge names, decoding, etc..).
|
||||
const { filename: name, encoding, mimeType: mime } = info
|
||||
const { encoding, filename: name, mimeType: mime } = info
|
||||
const filename = parseFileName(options, name)
|
||||
|
||||
// Define methods and handlers for upload process.
|
||||
const { dataHandler, getFilePath, getFileSize, getHash, complete, cleanup, getWritePromise } =
|
||||
const { cleanup, complete, dataHandler, getFilePath, getFileSize, getHash, getWritePromise } =
|
||||
options.useTempFiles
|
||||
? tempFileHandler(options, field, filename) // Upload into temporary file.
|
||||
: memHandler(options, field, filename) // Upload into RAM.
|
||||
@@ -99,14 +100,14 @@ export const processMultipart: ProcessMultipart = async ({ request, options }) =
|
||||
field,
|
||||
fileFactory(
|
||||
{
|
||||
buffer: complete(),
|
||||
name: filename,
|
||||
tempFilePath: getFilePath(),
|
||||
hash: getHash(),
|
||||
size,
|
||||
buffer: complete(),
|
||||
encoding,
|
||||
truncated: Boolean('truncated' in file && file.truncated),
|
||||
hash: getHash(),
|
||||
mimetype: mime,
|
||||
size,
|
||||
tempFilePath: getFilePath(),
|
||||
truncated: Boolean('truncated' in file && file.truncated),
|
||||
},
|
||||
options,
|
||||
),
|
||||
|
||||
@@ -3,7 +3,7 @@ import { isSafeFromPollution } from './utilities'
|
||||
export const processNested = function (data) {
|
||||
if (!data || data.length < 1) return Object.create(null)
|
||||
|
||||
let d = Object.create(null),
|
||||
const d = Object.create(null),
|
||||
keys = Object.keys(data)
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
@@ -13,7 +13,7 @@ export const processNested = function (data) {
|
||||
keyParts = key.replace(new RegExp(/\[/g), '.').replace(new RegExp(/\]/g), '').split('.')
|
||||
|
||||
for (let index = 0; index < keyParts.length; index++) {
|
||||
let k = keyParts[index]
|
||||
const k = keyParts[index]
|
||||
|
||||
// Ensure we don't allow prototype pollution
|
||||
if (!isSafeFromPollution(current, k)) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { Readable } from 'stream'
|
||||
import { NextFileUploadOptions } from '.'
|
||||
|
||||
import type { NextFileUploadOptions } from '.'
|
||||
|
||||
// Parameters for safe file name parsing.
|
||||
const SAFE_FILE_NAME_REGEX = /[^\w-]/g
|
||||
@@ -132,16 +133,16 @@ type CopyFile = (src: string, dst: string, callback: (err: Error) => void) => vo
|
||||
const copyFile: CopyFile = (src, dst, callback) => {
|
||||
// cbCalled flag and runCb helps to run cb only once.
|
||||
let cbCalled = false
|
||||
let runCb = (err?: Error) => {
|
||||
const runCb = (err?: Error) => {
|
||||
if (cbCalled) return
|
||||
cbCalled = true
|
||||
callback(err)
|
||||
}
|
||||
// Create read stream
|
||||
let readable = fs.createReadStream(src)
|
||||
const readable = fs.createReadStream(src)
|
||||
readable.on('error', runCb)
|
||||
// Create write stream
|
||||
let writable = fs.createWriteStream(dst)
|
||||
const writable = fs.createWriteStream(dst)
|
||||
writable.on('error', (err: Error) => {
|
||||
readable.destroy()
|
||||
runCb(err)
|
||||
@@ -182,13 +183,13 @@ export const saveBufferToFile = (buffer, filePath, callback) => {
|
||||
}
|
||||
// Setup readable stream from buffer.
|
||||
let streamData = buffer
|
||||
let readStream = new Readable()
|
||||
const readStream = new Readable()
|
||||
readStream._read = () => {
|
||||
readStream.push(streamData)
|
||||
streamData = null
|
||||
}
|
||||
// Setup file system writable stream.
|
||||
let fstream = fs.createWriteStream(filePath)
|
||||
const fstream = fs.createWriteStream(filePath)
|
||||
// console.log("Calling saveBuffer");
|
||||
fstream.on('error', (err) => {
|
||||
// console.log("err cb")
|
||||
@@ -217,7 +218,7 @@ const uriDecodeFileName = (opts, fileName) => {
|
||||
try {
|
||||
return decodeURIComponent(fileName)
|
||||
} catch (err) {
|
||||
const matcher = /(%[a-f0-9]{2})/gi
|
||||
const matcher = /(%[a-f\d]{2})/gi
|
||||
return fileName
|
||||
.split(matcher)
|
||||
.map((str) => {
|
||||
@@ -238,8 +239,8 @@ type ParseFileNameExtension = (
|
||||
preserveExtension: boolean | number,
|
||||
fileName: string,
|
||||
) => {
|
||||
name: string
|
||||
extension: string
|
||||
name: string
|
||||
}
|
||||
export const parseFileNameExtension: ParseFileNameExtension = (preserveExtension, fileName) => {
|
||||
const defaultResult = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import fs from 'fs'
|
||||
function iteratorToStream(iterator) {
|
||||
return new ReadableStream({
|
||||
async pull(controller) {
|
||||
const { value, done } = await iterator.next()
|
||||
const { done, value } = await iterator.next()
|
||||
if (done) {
|
||||
controller.close()
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import { Chevron } from '@payloadcms/ui'
|
||||
import * as React from 'react'
|
||||
|
||||
import { Chevron } from '@payloadcms/ui'
|
||||
import './index.scss'
|
||||
|
||||
const chars = {
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
'use client'
|
||||
import * as React from 'react'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
import {
|
||||
CopyToClipboard,
|
||||
Gutter,
|
||||
Checkbox,
|
||||
SetDocumentStepNav as SetStepNav,
|
||||
CopyToClipboard,
|
||||
Form,
|
||||
Select,
|
||||
Number as NumberInput,
|
||||
useConfig,
|
||||
Gutter,
|
||||
MinimizeMaximize,
|
||||
Number as NumberInput,
|
||||
Select,
|
||||
SetDocumentStepNav as SetStepNav,
|
||||
useActions,
|
||||
useTranslation,
|
||||
useLocale,
|
||||
useConfig,
|
||||
useDocumentInfo,
|
||||
useLocale,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import { RenderJSON } from './RenderJSON'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import qs from 'qs'
|
||||
import * as React from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { RenderJSON } from './RenderJSON'
|
||||
import './index.scss'
|
||||
import { EditViewProps } from 'payload/config'
|
||||
|
||||
const baseClass = 'query-inspector'
|
||||
|
||||
export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
const { collectionSlug, globalSlug } = props
|
||||
|
||||
const { initialData, id } = useDocumentInfo()
|
||||
const { id, initialData } = useDocumentInfo()
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const { setViewActions } = useActions()
|
||||
@@ -36,11 +37,11 @@ export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
const { code } = useLocale()
|
||||
|
||||
const {
|
||||
collections,
|
||||
globals,
|
||||
localization,
|
||||
routes: { api: apiRoute },
|
||||
serverURL,
|
||||
collections,
|
||||
globals,
|
||||
} = useConfig()
|
||||
|
||||
const collectionConfig =
|
||||
@@ -78,9 +79,9 @@ export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
|
||||
const fetchURL = `${serverURL}${apiRoute}${docEndpoint}${qs.stringify(
|
||||
{
|
||||
locale,
|
||||
draft,
|
||||
depth,
|
||||
draft,
|
||||
locale,
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)}`
|
||||
@@ -89,11 +90,11 @@ export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const res = await fetch(fetchURL, {
|
||||
method: 'GET',
|
||||
credentials: authenticated ? 'include' : 'omit',
|
||||
headers: {
|
||||
'Accept-Language': i18n.language,
|
||||
},
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
try {
|
||||
@@ -131,12 +132,12 @@ export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
>
|
||||
<SetStepNav
|
||||
collectionSlug={collectionSlug}
|
||||
useAsTitle={collectionConfig ? collectionConfig?.admin?.useAsTitle : undefined}
|
||||
pluralLabel={collectionConfig ? collectionConfig?.labels?.plural : undefined}
|
||||
globalLabel={globalConfig?.label}
|
||||
globalSlug={globalSlug}
|
||||
id={id}
|
||||
isEditing={isEditing}
|
||||
pluralLabel={collectionConfig ? collectionConfig?.labels?.plural : undefined}
|
||||
useAsTitle={collectionConfig ? collectionConfig?.admin?.useAsTitle : undefined}
|
||||
view="API"
|
||||
/>
|
||||
<div className={`${baseClass}__configuration`}>
|
||||
@@ -151,24 +152,24 @@ export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
<Form
|
||||
initialState={{
|
||||
authenticated: {
|
||||
value: authenticated || false,
|
||||
initialValue: authenticated || false,
|
||||
valid: true,
|
||||
},
|
||||
draft: {
|
||||
value: draft || false,
|
||||
initialValue: draft || false,
|
||||
valid: true,
|
||||
value: authenticated || false,
|
||||
},
|
||||
depth: {
|
||||
value: Number(depth || 0),
|
||||
initialValue: Number(depth || 0),
|
||||
valid: true,
|
||||
value: Number(depth || 0),
|
||||
},
|
||||
draft: {
|
||||
initialValue: draft || false,
|
||||
valid: true,
|
||||
value: draft || false,
|
||||
},
|
||||
locale: {
|
||||
value: locale,
|
||||
initialValue: locale,
|
||||
valid: true,
|
||||
value: locale,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -176,36 +177,36 @@ export const APIViewClient: React.FC<EditViewProps> = (props) => {
|
||||
<div className={`${baseClass}__filter-query-checkboxes`}>
|
||||
{draftsEnabled && (
|
||||
<Checkbox
|
||||
name="draft"
|
||||
path="draft"
|
||||
label="Draft"
|
||||
name="draft"
|
||||
onChange={() => setDraft(!draft)}
|
||||
path="draft"
|
||||
/>
|
||||
)}
|
||||
<Checkbox
|
||||
name="authenticated"
|
||||
path="authenticated"
|
||||
label="Authenticated"
|
||||
name="authenticated"
|
||||
onChange={() => setAuthenticated(!authenticated)}
|
||||
path="authenticated"
|
||||
/>
|
||||
</div>
|
||||
{localeOptions && (
|
||||
<Select
|
||||
label="Locale"
|
||||
name="locale"
|
||||
onChange={(value) => setLocale(value)}
|
||||
options={localeOptions}
|
||||
path="locale"
|
||||
onChange={(value) => setLocale(value)}
|
||||
/>
|
||||
)}
|
||||
<NumberInput
|
||||
label="Depth"
|
||||
name="depth"
|
||||
path="depth"
|
||||
min={0}
|
||||
max={10}
|
||||
step={1}
|
||||
min={0}
|
||||
name="depth"
|
||||
onChange={(value) => setDepth(value.toString())}
|
||||
path="depth"
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from 'react'
|
||||
import { ServerSideEditViewProps } from '../../../../ui/src/views/types'
|
||||
import { APIViewClient } from './index.client'
|
||||
|
||||
import type { ServerSideEditViewProps } from '../../../../ui/src/views/types'
|
||||
|
||||
import { sanitizedEditViewProps } from '../Edit/sanitizedEditViewProps'
|
||||
import { APIViewClient } from './index.client'
|
||||
|
||||
export const APIView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
const clientSideProps = sanitizedEditViewProps(props)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import { Label, ReactSelect } from '@payloadcms/ui'
|
||||
import { useTranslation } from '@payloadcms/ui/providers'
|
||||
import React from 'react'
|
||||
|
||||
import { ReactSelect, Label } from '@payloadcms/ui'
|
||||
import { ToggleTheme } from '../ToggleTheme'
|
||||
import './index.scss'
|
||||
|
||||
@@ -13,7 +13,7 @@ export const Settings: React.FC<{
|
||||
}> = (props) => {
|
||||
const { className } = props
|
||||
|
||||
const { i18n, t, languageOptions } = useTranslation()
|
||||
const { i18n, languageOptions, t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className={[baseClass, className].filter(Boolean).join(' ')}>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from '@payloadcms/ui'
|
||||
|
||||
import type { OnChange, Theme } from '@payloadcms/ui'
|
||||
import { useTheme, RadioGroupInput } from '@payloadcms/ui'
|
||||
|
||||
import { useTranslation } from '@payloadcms/ui'
|
||||
import { RadioGroupInput, useTheme } from '@payloadcms/ui'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
export const ToggleTheme: React.FC = () => {
|
||||
const {
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { Data, DocumentPreferences, SanitizedConfig } from 'payload/types'
|
||||
import React, { Fragment } from 'react'
|
||||
import type { ServerSideEditViewProps } from '@payloadcms/ui'
|
||||
import type { Data, DocumentPreferences, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import {
|
||||
RenderCustomComponent,
|
||||
HydrateClientUser,
|
||||
RenderCustomComponent,
|
||||
SetDocumentInfo,
|
||||
buildStateFromSchema,
|
||||
formatFields,
|
||||
ServerSideEditViewProps,
|
||||
SetDocumentInfo,
|
||||
} from '@payloadcms/ui'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { notFound } from 'next/navigation'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { EditView } from '../Edit'
|
||||
import { Settings } from './Settings'
|
||||
|
||||
@@ -20,15 +22,15 @@ export const Account = async ({
|
||||
config: Promise<SanitizedConfig>
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}) => {
|
||||
const { config, payload, permissions, user, i18n, locale } = await initPage({
|
||||
const { config, i18n, locale, payload, permissions, user } = await initPage({
|
||||
config: configPromise,
|
||||
redirectUnauthenticatedUser: true,
|
||||
searchParams,
|
||||
route: `/account`,
|
||||
searchParams,
|
||||
})
|
||||
|
||||
const {
|
||||
admin: { user: userSlug, components: { views: { Account: CustomAccountComponent } = {} } = {} },
|
||||
admin: { components: { views: { Account: CustomAccountComponent } = {} } = {}, user: userSlug },
|
||||
routes: { api },
|
||||
serverURL,
|
||||
} = config
|
||||
@@ -44,8 +46,8 @@ export const Account = async ({
|
||||
|
||||
try {
|
||||
data = await payload.findByID({
|
||||
collection: userSlug,
|
||||
id: user.id,
|
||||
collection: userSlug,
|
||||
depth: 0,
|
||||
user,
|
||||
})
|
||||
@@ -64,12 +66,12 @@ export const Account = async ({
|
||||
const { docs: [{ value: docPreferences } = { value: null }] = [] } = (await payload.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
where: {
|
||||
key: {
|
||||
equals: preferencesKey,
|
||||
},
|
||||
},
|
||||
limit: 1,
|
||||
})) as any as { docs: { value: DocumentPreferences }[] }
|
||||
|
||||
const initialState = await buildStateFromSchema({
|
||||
@@ -84,38 +86,38 @@ export const Account = async ({
|
||||
})
|
||||
|
||||
const componentProps: ServerSideEditViewProps = {
|
||||
id: user?.id,
|
||||
action: `${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale}`,
|
||||
apiURL: `${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale}`,
|
||||
collectionSlug: userSlug,
|
||||
config,
|
||||
data,
|
||||
hasSavePermission: collectionPermissions?.update?.permission,
|
||||
initialState,
|
||||
docPermissions: collectionPermissions,
|
||||
docPreferences,
|
||||
user,
|
||||
updatedAt: '', // TODO
|
||||
id: user?.id,
|
||||
config,
|
||||
hasSavePermission: collectionPermissions?.update?.permission,
|
||||
i18n,
|
||||
initialState,
|
||||
payload,
|
||||
permissions,
|
||||
searchParams,
|
||||
updatedAt: '', // TODO
|
||||
user,
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<HydrateClientUser user={user} permissions={permissions} />
|
||||
<HydrateClientUser permissions={permissions} user={user} />
|
||||
<SetDocumentInfo
|
||||
AfterFields={<Settings />}
|
||||
action={`${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale}`}
|
||||
apiURL={`${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale}`}
|
||||
collectionSlug={userSlug}
|
||||
initialData={data}
|
||||
hasSavePermission={collectionPermissions?.update?.permission}
|
||||
initialState={initialState}
|
||||
docPermissions={collectionPermissions}
|
||||
docPreferences={docPreferences}
|
||||
hasSavePermission={collectionPermissions?.update?.permission}
|
||||
id={user?.id}
|
||||
AfterFields={<Settings />}
|
||||
initialData={data}
|
||||
initialState={initialState}
|
||||
/>
|
||||
<RenderCustomComponent
|
||||
CustomComponent={
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
|
||||
import { RenderFields, useComponentMap } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
export const CreateFirstUserFields: React.FC<{
|
||||
userSlug: string
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { Field } from 'payload/types'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Form, FormSubmit, MinimalTemplate, buildStateFromSchema } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import type { Field } from 'payload/types'
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
import { Form, FormSubmit, MinimalTemplate, buildStateFromSchema } from '@payloadcms/ui'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import { Metadata } from 'next'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { CreateFirstUserFields } from './index.client'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'create-first-user'
|
||||
@@ -23,10 +23,10 @@ export const generateMetadata = async ({
|
||||
})
|
||||
|
||||
return meta({
|
||||
title: t('authentication:createFirstUser'),
|
||||
config,
|
||||
description: t('authentication:createFirstUser'),
|
||||
keywords: t('general:create'),
|
||||
config,
|
||||
title: t('authentication:createFirstUser'),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -35,17 +35,17 @@ export const CreateFirstUser: React.FC<{
|
||||
}> = async ({ config: configPromise }) => {
|
||||
const {
|
||||
config,
|
||||
user,
|
||||
locale,
|
||||
i18n: { t },
|
||||
locale,
|
||||
user,
|
||||
} = await initPage({
|
||||
config: configPromise,
|
||||
redirectUnauthenticatedUser: false,
|
||||
})
|
||||
|
||||
const {
|
||||
routes: { api: apiRoute, admin: adminRoute },
|
||||
admin: { user: userSlug },
|
||||
routes: { admin: adminRoute, api: apiRoute },
|
||||
serverURL,
|
||||
} = config
|
||||
|
||||
@@ -85,11 +85,11 @@ export const CreateFirstUser: React.FC<{
|
||||
<p>{t('authentication:beginCreateFirstUser')}</p>
|
||||
<Form
|
||||
action={`${serverURL}${apiRoute}/${userSlug}/first-register`}
|
||||
initialState={formState}
|
||||
method="POST"
|
||||
// onSuccess={onSuccess}
|
||||
redirect={adminRoute}
|
||||
validationOperation="create"
|
||||
initialState={formState}
|
||||
>
|
||||
<CreateFirstUserFields userSlug={userSlug} />
|
||||
<FormSubmit>{t('general:create')}</FormSubmit>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
'use client'
|
||||
import React, { Fragment, useEffect, useState } from 'react'
|
||||
|
||||
import type { EntityToGroup, Group } from '@payloadcms/ui'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import {
|
||||
EntityType,
|
||||
groupNavItems,
|
||||
Button,
|
||||
Card,
|
||||
EntityType,
|
||||
groupNavItems,
|
||||
useActions,
|
||||
useAuth,
|
||||
useConfig,
|
||||
useActions,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import React, { Fragment, useEffect, useState } from 'react'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
@@ -119,9 +119,11 @@ export const DefaultDashboardClient: React.FC<{
|
||||
return (
|
||||
<li key={entityIndex}>
|
||||
<Card
|
||||
Link={Link}
|
||||
actions={
|
||||
hasCreatePermission && type === EntityType.collection ? (
|
||||
<Button
|
||||
Link={Link}
|
||||
aria-label={t('general:createNewLabel', {
|
||||
label: getTranslation(entity.labels.singular, i18n),
|
||||
})}
|
||||
@@ -131,16 +133,14 @@ export const DefaultDashboardClient: React.FC<{
|
||||
iconStyle="with-border"
|
||||
round
|
||||
to={createHREF}
|
||||
Link={Link}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
buttonAriaLabel={buttonAriaLabel}
|
||||
href={href}
|
||||
id={`card-${entity.slug}`}
|
||||
title={title}
|
||||
titleAs="h3"
|
||||
Link={Link}
|
||||
href={href}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import React from 'react'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Gutter, SetStepNav } from '@payloadcms/ui'
|
||||
import { DefaultDashboardClient } from './index.client'
|
||||
import React from 'react'
|
||||
|
||||
import { DefaultDashboardClient } from './index.client'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'dashboard'
|
||||
|
||||
export const DefaultDashboard: React.FC<{
|
||||
config: SanitizedConfig
|
||||
Link: React.ComponentType<any>
|
||||
config: SanitizedConfig
|
||||
}> = (props) => {
|
||||
const {
|
||||
Link,
|
||||
config: {
|
||||
admin: {
|
||||
components: { afterDashboard, beforeDashboard },
|
||||
},
|
||||
},
|
||||
Link,
|
||||
} = props
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import React, { Fragment } from 'react'
|
||||
import { RenderCustomComponent, HydrateClientUser } from '@payloadcms/ui'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { HydrateClientUser, RenderCustomComponent } from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { DefaultDashboard } from './Default'
|
||||
|
||||
@@ -12,7 +14,7 @@ export const Dashboard = async ({
|
||||
config: Promise<SanitizedConfig>
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}) => {
|
||||
const { config, user, permissions } = await initPage({
|
||||
const { config, permissions, user } = await initPage({
|
||||
config: configPromise,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route: '',
|
||||
@@ -23,15 +25,15 @@ export const Dashboard = async ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<HydrateClientUser user={user} permissions={permissions} />
|
||||
<HydrateClientUser permissions={permissions} user={user} />
|
||||
<RenderCustomComponent
|
||||
CustomComponent={
|
||||
typeof CustomDashboardComponent === 'function' ? CustomDashboardComponent : undefined
|
||||
}
|
||||
DefaultComponent={DefaultDashboard}
|
||||
componentProps={{
|
||||
config,
|
||||
Link,
|
||||
config,
|
||||
user,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AdminViewComponent } from 'payload/config'
|
||||
import { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
|
||||
export const getCustomViewByKey = (
|
||||
views:
|
||||
@@ -10,13 +10,13 @@ export const getCustomViewByKey = (
|
||||
return typeof views?.Edit === 'function'
|
||||
? views?.Edit
|
||||
: typeof views?.Edit === 'object' &&
|
||||
views?.Edit?.[customViewKey] &&
|
||||
typeof views?.Edit?.[customViewKey] === 'function'
|
||||
? views?.Edit?.[customViewKey]
|
||||
: views?.Edit?.[customViewKey]
|
||||
? typeof views?.Edit?.[customViewKey] === 'object' &&
|
||||
'Component' in views?.Edit?.[customViewKey] &&
|
||||
typeof views?.Edit?.[customViewKey].Component === 'function' &&
|
||||
views?.Edit?.[customViewKey].Component
|
||||
: null
|
||||
views?.Edit?.[customViewKey] &&
|
||||
typeof views?.Edit?.[customViewKey] === 'function'
|
||||
? views?.Edit?.[customViewKey]
|
||||
: views?.Edit?.[customViewKey]
|
||||
? typeof views?.Edit?.[customViewKey] === 'object' &&
|
||||
'Component' in views?.Edit?.[customViewKey] &&
|
||||
typeof views?.Edit?.[customViewKey].Component === 'function' &&
|
||||
views?.Edit?.[customViewKey].Component
|
||||
: null
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AdminViewComponent } from 'payload/config'
|
||||
import { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
|
||||
export const getCustomViewByPath = (
|
||||
views:
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
import { AdminViewComponent } from 'payload/config'
|
||||
import { SanitizedCollectionConfig, SanitizedConfig, SanitizedGlobalConfig } from 'payload/types'
|
||||
import type { CollectionPermission, GlobalPermission } from 'payload/auth'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type {
|
||||
SanitizedCollectionConfig,
|
||||
SanitizedConfig,
|
||||
SanitizedGlobalConfig,
|
||||
} from 'payload/types'
|
||||
|
||||
import { lazy } from 'react'
|
||||
|
||||
import { getCustomViewByKey } from './getCustomViewByKey'
|
||||
import { CollectionPermission, GlobalPermission } from 'payload/auth'
|
||||
import { getCustomViewByPath } from './getCustomViewByPath'
|
||||
|
||||
export const getViewsFromConfig = async ({
|
||||
routeSegments,
|
||||
docPermissions,
|
||||
config,
|
||||
collectionConfig,
|
||||
config,
|
||||
docPermissions,
|
||||
globalConfig,
|
||||
routeSegments,
|
||||
}: {
|
||||
routeSegments: string[]
|
||||
config: SanitizedConfig
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
config: SanitizedConfig
|
||||
docPermissions: CollectionPermission | GlobalPermission
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
routeSegments: string[]
|
||||
}): Promise<{
|
||||
CustomView: AdminViewComponent
|
||||
DefaultView: AdminViewComponent
|
||||
|
||||
@@ -1,39 +1,42 @@
|
||||
import type { QueryParamTypes } from '@payloadcms/ui'
|
||||
import type { AdminViewComponent } from 'payload/config'
|
||||
import type {
|
||||
DocumentPreferences,
|
||||
Document as DocumentType,
|
||||
Field,
|
||||
SanitizedConfig,
|
||||
} from 'payload/types'
|
||||
import React, { Fragment } from 'react'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import type { DocumentPermissions } from 'payload/types'
|
||||
|
||||
import {
|
||||
EditDepthProvider,
|
||||
FormQueryParamsProvider,
|
||||
HydrateClientUser,
|
||||
RenderCustomComponent,
|
||||
SetDocumentInfo,
|
||||
buildStateFromSchema,
|
||||
formatFields,
|
||||
FormQueryParamsProvider,
|
||||
QueryParamTypes,
|
||||
HydrateClientUser,
|
||||
SetDocumentInfo,
|
||||
} from '@payloadcms/ui'
|
||||
import queryString from 'qs'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { AdminViewComponent } from 'payload/config'
|
||||
import queryString from 'qs'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { ServerSideEditViewProps } from '../../../../ui/src/views/types'
|
||||
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { getViewsFromConfig } from './getViewsFromConfig'
|
||||
import type { DocumentPermissions } from 'payload/types'
|
||||
import { ServerSideEditViewProps } from '../../../../ui/src/views/types'
|
||||
|
||||
export const Document = async ({
|
||||
params,
|
||||
config: configPromise,
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
config: Promise<SanitizedConfig> | SanitizedConfig
|
||||
params: {
|
||||
segments: string[]
|
||||
collection?: string
|
||||
global?: string
|
||||
segments: string[]
|
||||
}
|
||||
config: Promise<SanitizedConfig> | SanitizedConfig
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}) => {
|
||||
const collectionSlug = params.collection
|
||||
@@ -45,14 +48,14 @@ export const Document = async ({
|
||||
|
||||
const route = `/${collectionSlug || globalSlug + (params.segments?.length ? `/${params.segments.join('/')}` : '')}`
|
||||
|
||||
const { config, payload, permissions, user, collectionConfig, globalConfig, locale, i18n } =
|
||||
const { collectionConfig, config, globalConfig, i18n, locale, payload, permissions, user } =
|
||||
await initPage({
|
||||
config: configPromise,
|
||||
redirectUnauthenticatedUser: true,
|
||||
collectionSlug,
|
||||
config: configPromise,
|
||||
globalSlug,
|
||||
searchParams,
|
||||
redirectUnauthenticatedUser: true,
|
||||
route,
|
||||
searchParams,
|
||||
})
|
||||
|
||||
if (!collectionConfig && !globalConfig) {
|
||||
@@ -88,10 +91,10 @@ export const Document = async ({
|
||||
}`
|
||||
|
||||
const collectionViews = await getViewsFromConfig({
|
||||
routeSegments: params.segments,
|
||||
collectionConfig,
|
||||
config,
|
||||
docPermissions,
|
||||
routeSegments: params.segments,
|
||||
})
|
||||
|
||||
CustomView = collectionViews?.CustomView
|
||||
@@ -99,11 +102,11 @@ export const Document = async ({
|
||||
|
||||
try {
|
||||
data = await payload.findByID({
|
||||
collection: collectionSlug,
|
||||
id,
|
||||
collection: collectionSlug,
|
||||
depth: 0,
|
||||
user,
|
||||
locale: locale.code,
|
||||
user,
|
||||
})
|
||||
} catch (error) {}
|
||||
|
||||
@@ -123,20 +126,20 @@ export const Document = async ({
|
||||
}`
|
||||
|
||||
const globalViews = await getViewsFromConfig({
|
||||
routeSegments: params.segments,
|
||||
globalConfig,
|
||||
config,
|
||||
docPermissions,
|
||||
globalConfig,
|
||||
routeSegments: params.segments,
|
||||
})
|
||||
|
||||
CustomView = globalViews?.CustomView
|
||||
DefaultView = globalViews?.DefaultView
|
||||
|
||||
data = await payload.findGlobal({
|
||||
slug: globalSlug,
|
||||
depth: 0,
|
||||
user,
|
||||
locale: locale.code,
|
||||
slug: globalSlug,
|
||||
user,
|
||||
})
|
||||
|
||||
preferencesKey = `global-${globalSlug}`
|
||||
@@ -145,12 +148,12 @@ export const Document = async ({
|
||||
const { docs: [{ value: docPreferences } = { value: null }] = [] } = (await payload.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
where: {
|
||||
key: {
|
||||
equals: preferencesKey,
|
||||
},
|
||||
},
|
||||
limit: 1,
|
||||
})) as any as { docs: { value: DocumentPreferences }[] }
|
||||
|
||||
const initialState = await buildStateFromSchema({
|
||||
@@ -176,24 +179,24 @@ export const Document = async ({
|
||||
action: `${action}?${queryString.stringify(formQueryParams)}`,
|
||||
apiURL,
|
||||
canAccessAdmin: permissions?.canAccessAdmin,
|
||||
collectionConfig,
|
||||
collectionSlug,
|
||||
globalSlug,
|
||||
config,
|
||||
data,
|
||||
hasSavePermission,
|
||||
isEditing,
|
||||
docPermissions,
|
||||
docPreferences,
|
||||
updatedAt: data?.updatedAt?.toString(),
|
||||
payload,
|
||||
config,
|
||||
searchParams,
|
||||
i18n,
|
||||
collectionConfig,
|
||||
globalConfig,
|
||||
params,
|
||||
permissions,
|
||||
user,
|
||||
globalSlug,
|
||||
hasSavePermission,
|
||||
i18n,
|
||||
initialState,
|
||||
isEditing,
|
||||
params,
|
||||
payload,
|
||||
permissions,
|
||||
searchParams,
|
||||
updatedAt: data?.updatedAt?.toString(),
|
||||
user,
|
||||
}
|
||||
|
||||
if (!DefaultView && !CustomView) {
|
||||
@@ -202,19 +205,19 @@ export const Document = async ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<HydrateClientUser user={user} permissions={permissions} />
|
||||
<HydrateClientUser permissions={permissions} user={user} />
|
||||
<SetDocumentInfo
|
||||
action={action}
|
||||
apiURL={apiURL}
|
||||
collectionSlug={collectionConfig?.slug}
|
||||
disableActions={false}
|
||||
docPermissions={docPermissions}
|
||||
docPreferences={docPreferences}
|
||||
globalSlug={globalConfig?.slug}
|
||||
hasSavePermission={hasSavePermission}
|
||||
id={id}
|
||||
initialData={data}
|
||||
initialState={initialState}
|
||||
docPermissions={docPermissions}
|
||||
docPreferences={docPreferences}
|
||||
apiURL={apiURL}
|
||||
action={action}
|
||||
hasSavePermission={hasSavePermission}
|
||||
disableActions={false}
|
||||
/>
|
||||
<EditDepthProvider depth={1} key={`${collectionSlug || globalSlug}-${locale}`}>
|
||||
<FormQueryParamsProvider formQueryParams={formQueryParams}>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
'use client'
|
||||
import React, { Fragment } from 'react'
|
||||
import { useComponentMap, useDocumentInfo } from '@payloadcms/ui'
|
||||
import React, { Fragment } from 'react'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { LoadingOverlay } from '../../../../ui/src/elements/Loading'
|
||||
|
||||
export const DefaultEditViewClient: React.FC = () => {
|
||||
const { id, getVersions, getDocPermissions, collectionSlug, globalSlug } = useDocumentInfo()
|
||||
const { id, collectionSlug, getDocPermissions, getVersions, globalSlug } = useDocumentInfo()
|
||||
|
||||
const { componentMap } = useComponentMap()
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react'
|
||||
import { ServerSideEditViewProps } from '../../../../ui/src/views/types'
|
||||
|
||||
import type { ServerSideEditViewProps } from '../../../../ui/src/views/types'
|
||||
|
||||
import { DefaultEditViewClient } from './index.client'
|
||||
|
||||
export const EditView: React.FC<ServerSideEditViewProps> = async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ServerSideEditViewProps } from '@payloadcms/ui'
|
||||
import { EditViewProps } from 'payload/config'
|
||||
import type { ServerSideEditViewProps } from '@payloadcms/ui'
|
||||
import type { EditViewProps } from 'payload/config'
|
||||
|
||||
export const sanitizedEditViewProps = (props: ServerSideEditViewProps) => {
|
||||
const clientSideProps = { ...props }
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
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 from 'react'
|
||||
|
||||
import { Button, Form, FormSubmit, Email, MinimalTemplate, Translation } from '@payloadcms/ui'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import Link from 'next/link'
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { Metadata } from 'next'
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
|
||||
const baseClass = 'forgot-password'
|
||||
|
||||
@@ -20,17 +21,17 @@ export const generateMetadata = async ({
|
||||
})
|
||||
|
||||
return meta({
|
||||
title: t('authentication:forgotPassword'),
|
||||
config,
|
||||
description: t('authentication:forgotPassword'),
|
||||
keywords: t('authentication:forgotPassword'),
|
||||
config,
|
||||
title: t('authentication:forgotPassword'),
|
||||
})
|
||||
}
|
||||
|
||||
export const ForgotPassword: React.FC<{
|
||||
config: Promise<SanitizedConfig>
|
||||
}> = async ({ config: configPromise }) => {
|
||||
const { config, user, i18n } = await initPage({ config: configPromise })
|
||||
const { config, i18n, user } = await initPage({ config: configPromise })
|
||||
|
||||
const {
|
||||
admin: { user: userSlug },
|
||||
@@ -55,11 +56,11 @@ export const ForgotPassword: React.FC<{
|
||||
<h1>{i18n.t('authentication:alreadyLoggedIn')}</h1>
|
||||
<p>
|
||||
<Translation
|
||||
t={i18n.t}
|
||||
i18nKey="authentication:loggedInChangePassword"
|
||||
elements={{
|
||||
'0': ({ children }) => <Link href={`${admin}/account`} children={children} />,
|
||||
'0': ({ children }) => <Link children={children} href={`${admin}/account`} />,
|
||||
}}
|
||||
i18nKey="authentication:loggedInChangePassword"
|
||||
t={i18n.t}
|
||||
/>
|
||||
</p>
|
||||
<br />
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import React, { Fragment } from 'react'
|
||||
import type { DefaultListViewProps } from '@payloadcms/ui'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import {
|
||||
RenderCustomComponent,
|
||||
DefaultList,
|
||||
HydrateClientUser,
|
||||
DefaultListViewProps,
|
||||
RenderCustomComponent,
|
||||
TableColumnsProvider,
|
||||
} from '@payloadcms/ui'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { ListPreferences } from '../../../../ui/src/views/List/types'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { ListPreferences } from '../../../../ui/src/views/List/types'
|
||||
|
||||
import { ListInfoProvider } from '../../../../ui/src/providers/ListInfo'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
|
||||
export const ListView = async ({
|
||||
collectionSlug,
|
||||
config: configPromise,
|
||||
searchParams,
|
||||
route,
|
||||
searchParams,
|
||||
}: {
|
||||
collectionSlug: string
|
||||
config: Promise<SanitizedConfig>
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
route
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}) => {
|
||||
const { config, payload, permissions, user, collectionConfig } = await initPage({
|
||||
const { collectionConfig, config, payload, permissions, user } = await initPage({
|
||||
collectionSlug,
|
||||
config: configPromise,
|
||||
redirectUnauthenticatedUser: true,
|
||||
collectionSlug,
|
||||
route,
|
||||
searchParams,
|
||||
})
|
||||
@@ -37,13 +40,13 @@ export const ListView = async ({
|
||||
listPreferences = (await payload
|
||||
.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
where: {
|
||||
key: {
|
||||
equals: `${collectionSlug}-list`,
|
||||
},
|
||||
},
|
||||
limit: 1,
|
||||
depth: 0,
|
||||
})
|
||||
?.then((res) => res?.docs?.[0]?.value)) as unknown as ListPreferences
|
||||
} catch (error) {}
|
||||
@@ -80,13 +83,13 @@ export const ListView = async ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<HydrateClientUser user={user} permissions={permissions} />
|
||||
<HydrateClientUser permissions={permissions} user={user} />
|
||||
<ListInfoProvider
|
||||
collectionSlug={collectionSlug}
|
||||
data={data}
|
||||
hasCreatePermission={permissions?.collections?.[collectionSlug]?.create?.permission}
|
||||
limit={limit}
|
||||
newDocumentURL={`${admin}/collections/${collectionSlug}/create`}
|
||||
collectionSlug={collectionSlug}
|
||||
>
|
||||
<TableColumnsProvider collectionSlug={collectionSlug} listPreferences={listPreferences}>
|
||||
<RenderCustomComponent
|
||||
|
||||
@@ -24,23 +24,24 @@ export const ToolbarControls: React.FC<EditViewProps> = () => {
|
||||
<div className={baseClass}>
|
||||
{breakpoints?.length > 0 && (
|
||||
<Popup
|
||||
className={`${baseClass}__breakpoint`}
|
||||
button={
|
||||
<>
|
||||
<React.Fragment>
|
||||
<span>
|
||||
{breakpoints.find((bp) => bp.name == breakpoint)?.label ?? customOption.label}
|
||||
</span>
|
||||
|
||||
<Chevron className={`${baseClass}__chevron`} />
|
||||
</>
|
||||
</React.Fragment>
|
||||
}
|
||||
className={`${baseClass}__breakpoint`}
|
||||
horizontalAlign="right"
|
||||
render={({ close }) => (
|
||||
<PopupList.ButtonGroup>
|
||||
<React.Fragment>
|
||||
{breakpoints.map((bp) => (
|
||||
<PopupList.Button
|
||||
key={bp.name}
|
||||
active={bp.name == breakpoint}
|
||||
key={bp.name}
|
||||
onClick={() => {
|
||||
setBreakpoint(bp.name)
|
||||
close()
|
||||
@@ -66,7 +67,6 @@ export const ToolbarControls: React.FC<EditViewProps> = () => {
|
||||
)}
|
||||
showScrollbar
|
||||
verticalAlign="bottom"
|
||||
horizontalAlign="right"
|
||||
/>
|
||||
)}
|
||||
<div className={`${baseClass}__device-size`}>
|
||||
@@ -77,21 +77,22 @@ export const ToolbarControls: React.FC<EditViewProps> = () => {
|
||||
<PreviewFrameSizeInput axis="y" />
|
||||
</div>
|
||||
<Popup
|
||||
className={`${baseClass}__zoom`}
|
||||
button={
|
||||
<>
|
||||
<React.Fragment>
|
||||
<span>{zoom * 100}%</span>
|
||||
|
||||
<Chevron className={`${baseClass}__chevron`} />
|
||||
</>
|
||||
</React.Fragment>
|
||||
}
|
||||
className={`${baseClass}__zoom`}
|
||||
horizontalAlign="right"
|
||||
render={({ close }) => (
|
||||
<PopupList.ButtonGroup>
|
||||
<React.Fragment>
|
||||
{zoomOptions.map((zoomValue) => (
|
||||
<PopupList.Button
|
||||
key={zoomValue}
|
||||
active={zoom * 100 == zoomValue}
|
||||
key={zoomValue}
|
||||
onClick={() => {
|
||||
setZoom(zoomValue / 100)
|
||||
close()
|
||||
@@ -105,7 +106,6 @@ export const ToolbarControls: React.FC<EditViewProps> = () => {
|
||||
)}
|
||||
showScrollbar
|
||||
verticalAlign="bottom"
|
||||
horizontalAlign="right"
|
||||
/>
|
||||
<a
|
||||
className={`${baseClass}__external`}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import React, { Fragment, useEffect } from 'react'
|
||||
import { useTranslation } from '@payloadcms/ui'
|
||||
import React, { Fragment, useEffect } from 'react'
|
||||
|
||||
import type { SanitizedCollectionConfig } from '../../../../collections/config/types'
|
||||
import type { LivePreviewConfig } from '../../../../exports/config'
|
||||
@@ -124,8 +124,8 @@ const PreviewView: React.FC<
|
||||
fields={fields}
|
||||
forceSidebarWrap
|
||||
hasSavePermission={hasSavePermission}
|
||||
permissions={permissions}
|
||||
i18n={i18n}
|
||||
permissions={permissions}
|
||||
/>
|
||||
</div>
|
||||
<LivePreview {...props} />
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import type { FormState } from '@payloadcms/ui'
|
||||
|
||||
import {
|
||||
Email,
|
||||
Form,
|
||||
FormLoadingOverlayToggle,
|
||||
FormState,
|
||||
FormSubmit,
|
||||
Password,
|
||||
useConfig,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
const baseClass = 'login__form'
|
||||
|
||||
@@ -33,13 +34,13 @@ export const LoginForm: React.FC<{
|
||||
const initialState: FormState = {
|
||||
email: {
|
||||
initialValue: prefillForm ? autoLogin.email : undefined,
|
||||
value: prefillForm ? autoLogin.email : undefined,
|
||||
valid: true,
|
||||
value: prefillForm ? autoLogin.email : undefined,
|
||||
},
|
||||
password: {
|
||||
initialValue: prefillForm ? autoLogin.password : undefined,
|
||||
value: prefillForm ? autoLogin.password : undefined,
|
||||
valid: true,
|
||||
value: prefillForm ? autoLogin.password : undefined,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,9 +50,9 @@ export const LoginForm: React.FC<{
|
||||
className={`${baseClass}__form`}
|
||||
disableSuccessStatus
|
||||
initialState={initialState}
|
||||
method="POST"
|
||||
redirect={`${admin}${searchParams?.redirect || ''}`}
|
||||
waitForAutocomplete
|
||||
method="POST"
|
||||
>
|
||||
<FormLoadingOverlayToggle action="loading" name="login-form" />
|
||||
<div className={`${baseClass}__inputWrap`}>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { MinimalTemplate } from '@payloadcms/ui'
|
||||
import { Logo } from '@payloadcms/ui/graphics'
|
||||
import { redirect } from 'next/navigation'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { Logo } from '@payloadcms/ui/graphics'
|
||||
import { MinimalTemplate } from '@payloadcms/ui'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { Metadata } from 'next'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { LoginForm } from './LoginForm'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'login'
|
||||
@@ -24,10 +24,10 @@ export const generateMetadata = async ({
|
||||
})
|
||||
|
||||
return meta({
|
||||
title: t('authentication:login'),
|
||||
config,
|
||||
description: `${t('authentication:login')}`,
|
||||
keywords: `${t('authentication:login')}`,
|
||||
config,
|
||||
title: t('authentication:login'),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ export const Login: React.FC<{
|
||||
config: Promise<SanitizedConfig>
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
}> = async ({ config: configPromise, searchParams }) => {
|
||||
const { config, user } = await initPage({ config: configPromise, searchParams, route: '/login' })
|
||||
const { config, user } = await initPage({ config: configPromise, route: '/login', searchParams })
|
||||
|
||||
const {
|
||||
admin: { components: { afterLogin, beforeLogin } = {}, user: userSlug },
|
||||
routes: { admin },
|
||||
collections,
|
||||
routes: { admin },
|
||||
} = config
|
||||
|
||||
if (user) {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
'use client'
|
||||
import React, { Fragment, useEffect } from 'react'
|
||||
import { useAuth } from '../../../../ui/src/providers/Auth'
|
||||
import { Button, useTranslation } from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import React, { Fragment, useEffect } from 'react'
|
||||
|
||||
import { useAuth } from '../../../../ui/src/providers/Auth'
|
||||
|
||||
export const LogoutClient: React.FC<{
|
||||
inactivity?: boolean
|
||||
adminRoute: string
|
||||
inactivity?: boolean
|
||||
redirect: string
|
||||
}> = (props) => {
|
||||
const { inactivity, adminRoute, redirect } = props
|
||||
const { adminRoute, inactivity, redirect } = props
|
||||
|
||||
const [isLoggingOut, setIsLoggingOut] = React.useState<boolean | undefined>(undefined)
|
||||
const { logOut } = useAuth()
|
||||
@@ -28,12 +29,12 @@ export const LogoutClient: React.FC<{
|
||||
{inactivity && <h2>{t('authentication:loggedOutInactivity')}</h2>}
|
||||
{!inactivity && <h2>{t('authentication:loggedOutSuccessfully')}</h2>}
|
||||
<Button
|
||||
Link={Link}
|
||||
buttonStyle="secondary"
|
||||
el="link"
|
||||
url={`${adminRoute}/login${
|
||||
redirect && redirect.length > 0 ? `?redirect=${encodeURIComponent(redirect)}` : ''
|
||||
}`}
|
||||
Link={Link}
|
||||
>
|
||||
{t('authentication:logBackIn')}
|
||||
</Button>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Button, MinimalTemplate } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import { MinimalTemplate, Button } from '@payloadcms/ui'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { Metadata } from 'next'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import { LogoutClient } from './LogoutClient'
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { LogoutClient } from './LogoutClient'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'logout'
|
||||
@@ -21,18 +21,18 @@ export const generateMetadata = async ({
|
||||
})
|
||||
|
||||
return meta({
|
||||
title: t('authentication:logout'),
|
||||
config,
|
||||
description: `${t('authentication:logoutUser')}`,
|
||||
keywords: `${t('authentication:logout')}`,
|
||||
config,
|
||||
title: t('authentication:logout'),
|
||||
})
|
||||
}
|
||||
|
||||
export const Logout: React.FC<{
|
||||
inactivity?: boolean
|
||||
config: Promise<SanitizedConfig>
|
||||
searchParams: { [key: string]: string[] | string }
|
||||
}> = async ({ searchParams, config: configPromise, inactivity }) => {
|
||||
inactivity?: boolean
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
}> = async ({ config: configPromise, inactivity, searchParams }) => {
|
||||
const config = await configPromise
|
||||
|
||||
const {
|
||||
@@ -43,8 +43,8 @@ export const Logout: React.FC<{
|
||||
<MinimalTemplate className={baseClass}>
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
<LogoutClient
|
||||
inactivity={inactivity}
|
||||
adminRoute={admin}
|
||||
inactivity={inactivity}
|
||||
redirect={searchParams.redirect as string}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import { Button, Gutter, useConfig, useStepNav, useTranslation } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import { Button, Gutter, useStepNav, useConfig, useTranslation } from '@payloadcms/ui'
|
||||
// import Meta from '../../utilities/Meta'
|
||||
import './index.scss'
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import React from 'react'
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import {
|
||||
MinimalTemplate,
|
||||
Button,
|
||||
ConfirmPassword,
|
||||
Form,
|
||||
FormSubmit,
|
||||
ConfirmPassword,
|
||||
HiddenInput,
|
||||
MinimalTemplate,
|
||||
Password,
|
||||
Translation,
|
||||
} from '@payloadcms/ui'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import Link from 'next/link'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { Metadata } from 'next'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
import React from 'react'
|
||||
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'reset-password'
|
||||
@@ -31,10 +31,10 @@ export const generateMetadata = async ({
|
||||
})
|
||||
|
||||
return meta({
|
||||
title: t('authentication:resetPassword'),
|
||||
config,
|
||||
description: t('authentication:resetPassword'),
|
||||
keywords: t('authentication:resetPassword'),
|
||||
config,
|
||||
title: t('authentication:resetPassword'),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export const ResetPassword: React.FC<{
|
||||
config: Promise<SanitizedConfig>
|
||||
token: string
|
||||
}> = async ({ config: configPromise, token }) => {
|
||||
const { config, user, i18n } = await initPage({ config: configPromise })
|
||||
const { config, i18n, user } = await initPage({ config: configPromise })
|
||||
|
||||
const {
|
||||
admin: { logoutRoute, user: userSlug },
|
||||
@@ -67,11 +67,11 @@ export const ResetPassword: React.FC<{
|
||||
<h1>{i18n.t('authentication:alreadyLoggedIn')}</h1>
|
||||
<p>
|
||||
<Translation
|
||||
t={i18n.t}
|
||||
i18nKey="authentication:loggedInChangePassword"
|
||||
elements={{
|
||||
'0': ({ children }) => <Link href={`${admin}/account`} children={children} />,
|
||||
'0': ({ children }) => <Link children={children} href={`${admin}/account`} />,
|
||||
}}
|
||||
i18nKey="authentication:loggedInChangePassword"
|
||||
t={i18n.t}
|
||||
/>
|
||||
</p>
|
||||
<br />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { redirect } from 'next/navigation'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
|
||||
export const RootPage = async ({ config: configPromise }: { config: Promise<SanitizedConfig> }) => {
|
||||
const config = await configPromise
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import { Button, useTranslation } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
export const UnauthorizedClient: React.FC<{ logoutRoute: string }> = ({ logoutRoute }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<React.Fragment>
|
||||
<h2>{t('error:unauthorized')}</h2>
|
||||
<p>{t('error:notAllowedToAccessPage')}</p>
|
||||
<br />
|
||||
<Button el="link" to={logoutRoute}>
|
||||
{t('authentication:logOut')}
|
||||
</Button>
|
||||
</>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React from 'react'
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { MinimalTemplate } from '@payloadcms/ui'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { Metadata } from 'next'
|
||||
import React from 'react'
|
||||
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { UnauthorizedClient } from './UnauthorizedClient'
|
||||
|
||||
export const generateMetadata = async ({
|
||||
@@ -17,10 +18,10 @@ export const generateMetadata = async ({
|
||||
})
|
||||
|
||||
return meta({
|
||||
title: t('error:unauthorized'),
|
||||
config,
|
||||
description: t('error:unauthorized'),
|
||||
keywords: t('error:unauthorized'),
|
||||
config,
|
||||
title: t('error:unauthorized'),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { Button, Logo, MinimalTemplate } from '@payloadcms/ui'
|
||||
import { redirect } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import { Button, MinimalTemplate, Logo } from '@payloadcms/ui'
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { SanitizedConfig } from 'payload/types'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { Metadata } from 'next'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import { getNextT } from '../../utilities/getNextT'
|
||||
|
||||
import { initPage } from '../../utilities/initPage'
|
||||
import { meta } from '../../utilities/meta'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'verify'
|
||||
@@ -22,10 +22,10 @@ export const generateMetadata = async ({
|
||||
})
|
||||
|
||||
return meta({
|
||||
config,
|
||||
description: t('authentication:verifyUser'),
|
||||
keywords: t('authentication:verify'),
|
||||
title: t('authentication:verify'),
|
||||
config,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export const Verify: React.FC<{
|
||||
config: configPromise,
|
||||
// token
|
||||
}) => {
|
||||
const { config, user, i18n } = await initPage({ config: configPromise })
|
||||
const { config, i18n, user } = await initPage({ config: configPromise })
|
||||
|
||||
const {
|
||||
admin: { user: userSlug },
|
||||
@@ -44,7 +44,7 @@ export const Verify: React.FC<{
|
||||
// serverURL,
|
||||
} = config
|
||||
|
||||
let verifyResult = null
|
||||
const verifyResult = null
|
||||
// const [verifyResult, setVerifyResult] = useState<Response | null>(null)
|
||||
|
||||
// useEffect(() => {
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
import type { FieldMap, StepNavItem } from '@payloadcms/ui'
|
||||
import type { FieldAffectingData, SanitizedCollectionConfig } from 'payload/types'
|
||||
import type React from 'react'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import {
|
||||
FieldMap,
|
||||
StepNavItem,
|
||||
formatDate,
|
||||
useConfig,
|
||||
useLocale,
|
||||
useStepNav,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import { FieldAffectingData, SanitizedCollectionConfig } from 'payload/types'
|
||||
import React, { useEffect } from 'react'
|
||||
import { formatDate, useConfig, useLocale, useStepNav, useTranslation } from '@payloadcms/ui'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export const SetStepNav: React.FC<{
|
||||
collectionSlug?: string
|
||||
globalSlug?: string
|
||||
mostRecentDoc: any
|
||||
doc: any
|
||||
id?: string | number
|
||||
fieldMap: FieldMap
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
}> = ({ collectionSlug, globalSlug, mostRecentDoc, doc, id, fieldMap, collectionConfig }) => {
|
||||
collectionSlug?: string
|
||||
doc: any
|
||||
fieldMap: FieldMap
|
||||
globalSlug?: string
|
||||
id?: number | string
|
||||
mostRecentDoc: any
|
||||
}> = ({ id, collectionConfig, collectionSlug, doc, fieldMap, globalSlug, mostRecentDoc }) => {
|
||||
const config = useConfig()
|
||||
const { setStepNav } = useStepNav()
|
||||
const { i18n, t } = useTranslation()
|
||||
@@ -42,7 +37,7 @@ export const SetStepNav: React.FC<{
|
||||
if (mostRecentDoc) {
|
||||
if (useAsTitle !== 'id') {
|
||||
const titleField = fieldMap.find(
|
||||
({ isFieldAffectingData, name: fieldName }) =>
|
||||
({ name: fieldName, isFieldAffectingData }) =>
|
||||
isFieldAffectingData && fieldName === useAsTitle,
|
||||
) as FieldAffectingData
|
||||
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
'use client'
|
||||
import React, { useState } from 'react'
|
||||
import type { CompareOption, DefaultVersionsViewProps } from './types'
|
||||
import type { Option } from '@payloadcms/ui'
|
||||
|
||||
import {
|
||||
Gutter,
|
||||
Option,
|
||||
formatDate,
|
||||
useComponentMap,
|
||||
useConfig,
|
||||
usePayloadAPI,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import Restore from '../Restore'
|
||||
import { mostRecentVersionOption } from '../shared'
|
||||
import diffComponents from '../RenderFieldsToDiff/fields'
|
||||
import RenderFieldsToDiff from '../RenderFieldsToDiff'
|
||||
import { SetStepNav } from './SetStepNav'
|
||||
import { SelectLocales } from '../SelectLocales'
|
||||
import { SelectComparison } from '../SelectComparison'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
import type { CompareOption, DefaultVersionsViewProps } from './types'
|
||||
|
||||
import RenderFieldsToDiff from '../RenderFieldsToDiff'
|
||||
import diffComponents from '../RenderFieldsToDiff/fields'
|
||||
import Restore from '../Restore'
|
||||
import { SelectComparison } from '../SelectComparison'
|
||||
import { SelectLocales } from '../SelectLocales'
|
||||
import { mostRecentVersionOption } from '../shared'
|
||||
import { SetStepNav } from './SetStepNav'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'view-version'
|
||||
|
||||
export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
id,
|
||||
collectionSlug,
|
||||
doc,
|
||||
mostRecentDoc,
|
||||
publishedDoc,
|
||||
docPermissions,
|
||||
globalSlug,
|
||||
initialComparisonDoc,
|
||||
localeOptions,
|
||||
docPermissions,
|
||||
collectionSlug,
|
||||
globalSlug,
|
||||
id,
|
||||
mostRecentDoc,
|
||||
publishedDoc,
|
||||
versionID,
|
||||
}) => {
|
||||
const config = useConfig()
|
||||
@@ -53,8 +55,8 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
|
||||
const {
|
||||
admin: { dateFormat },
|
||||
routes: { api: apiRoute },
|
||||
localization,
|
||||
routes: { api: apiRoute },
|
||||
serverURL,
|
||||
} = config
|
||||
|
||||
@@ -86,29 +88,29 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
: `${compareBaseURL}/${compareValue.value}`
|
||||
|
||||
const [{ data: currentComparisonDoc }] = usePayloadAPI(compareFetchURL, {
|
||||
initialParams: { depth: 1, draft: 'true', locale: '*' },
|
||||
initialData: initialComparisonDoc,
|
||||
initialParams: { depth: 1, draft: 'true', locale: '*' },
|
||||
})
|
||||
|
||||
const comparison =
|
||||
compareValue?.value === 'mostRecent'
|
||||
? mostRecentDoc
|
||||
: compareValue?.value === 'published'
|
||||
? publishedDoc
|
||||
: currentComparisonDoc?.version // the `version` key is only present on `versions` documents
|
||||
? publishedDoc
|
||||
: currentComparisonDoc?.version // the `version` key is only present on `versions` documents
|
||||
|
||||
const canUpdate = docPermissions?.update?.permission
|
||||
|
||||
return (
|
||||
<main className={baseClass}>
|
||||
<SetStepNav
|
||||
collectionSlug={collectionSlug}
|
||||
globalSlug={globalSlug}
|
||||
mostRecentDoc={mostRecentDoc}
|
||||
doc={doc}
|
||||
id={id}
|
||||
fieldMap={fieldMap}
|
||||
collectionConfig={collectionConfig}
|
||||
collectionSlug={collectionSlug}
|
||||
doc={doc}
|
||||
fieldMap={fieldMap}
|
||||
globalSlug={globalSlug}
|
||||
id={id}
|
||||
mostRecentDoc={mostRecentDoc}
|
||||
/>
|
||||
<Gutter className={`${baseClass}__wrap`}>
|
||||
<div className={`${baseClass}__header-wrap`}>
|
||||
@@ -148,16 +150,16 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
{doc?.version && (
|
||||
<RenderFieldsToDiff
|
||||
comparison={comparison}
|
||||
fieldPermissions={docPermissions?.fields}
|
||||
diffComponents={diffComponents}
|
||||
fieldMap={fieldMap}
|
||||
fieldPermissions={docPermissions?.fields}
|
||||
i18n={i18n}
|
||||
locales={
|
||||
locales
|
||||
? locales.map(({ label }) => (typeof label === 'string' ? label : undefined))
|
||||
: []
|
||||
}
|
||||
version={doc?.version}
|
||||
i18n={i18n}
|
||||
diffComponents={diffComponents}
|
||||
/>
|
||||
)}
|
||||
</Gutter>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Option } from '@payloadcms/ui'
|
||||
import { CollectionPermission, GlobalPermission, Permissions, User } from 'payload/auth'
|
||||
|
||||
import { Document, SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { Option } from '@payloadcms/ui'
|
||||
import type { CollectionPermission, GlobalPermission, Permissions, User } from 'payload/auth'
|
||||
import type { Document, SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
export type CompareOption = {
|
||||
label: string
|
||||
@@ -11,16 +10,16 @@ export type CompareOption = {
|
||||
}
|
||||
|
||||
export type DefaultVersionsViewProps = {
|
||||
collectionSlug?: SanitizedCollectionConfig['slug']
|
||||
doc: Document
|
||||
mostRecentDoc: Document
|
||||
publishedDoc: Document
|
||||
docPermissions: CollectionPermission | GlobalPermission
|
||||
globalSlug?: SanitizedCollectionConfig['slug']
|
||||
id?: number | string
|
||||
initialComparisonDoc: Document
|
||||
localeOptions: Option[]
|
||||
user: User
|
||||
mostRecentDoc: Document
|
||||
permissions: Permissions
|
||||
id?: string | number
|
||||
publishedDoc: Document
|
||||
user: User
|
||||
versionID?: string
|
||||
docPermissions: CollectionPermission | GlobalPermission
|
||||
collectionSlug?: SanitizedCollectionConfig['slug']
|
||||
globalSlug?: SanitizedCollectionConfig['slug']
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import type { MappedField } from '@payloadcms/ui'
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { getUniqueListBy } from 'payload/utilities'
|
||||
import React from 'react'
|
||||
|
||||
import type { Field } from 'payload/types'
|
||||
import type { Props } from '../types'
|
||||
|
||||
import RenderFieldsToDiff from '../..'
|
||||
import { getUniqueListBy } from 'payload/utilities'
|
||||
import Label from '../../Label'
|
||||
import { MappedField } from '@payloadcms/ui'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'iterable-diff'
|
||||
|
||||
const Iterable: React.FC<Props> = ({
|
||||
comparison,
|
||||
diffComponents,
|
||||
field,
|
||||
i18n,
|
||||
locale,
|
||||
locales,
|
||||
permissions,
|
||||
version,
|
||||
i18n,
|
||||
diffComponents,
|
||||
}) => {
|
||||
const versionRowCount = Array.isArray(version) ? version.length : 0
|
||||
const comparisonRowCount = Array.isArray(comparison) ? comparison.length : 0
|
||||
@@ -80,12 +80,12 @@ const Iterable: React.FC<Props> = ({
|
||||
<div className={`${baseClass}__wrap`} key={i}>
|
||||
<RenderFieldsToDiff
|
||||
comparison={comparisonRow}
|
||||
diffComponents={diffComponents}
|
||||
fieldMap={subFields}
|
||||
fieldPermissions={permissions}
|
||||
i18n={i18n}
|
||||
locales={locales}
|
||||
version={versionRow}
|
||||
i18n={i18n}
|
||||
diffComponents={diffComponents}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import React from 'react'
|
||||
|
||||
import type { Props } from '../types'
|
||||
|
||||
@@ -11,15 +11,15 @@ const baseClass = 'nested-diff'
|
||||
|
||||
const Nested: React.FC<Props> = ({
|
||||
comparison,
|
||||
diffComponents,
|
||||
disableGutter = false,
|
||||
field,
|
||||
fieldMap,
|
||||
i18n,
|
||||
locale,
|
||||
locales,
|
||||
permissions,
|
||||
version,
|
||||
i18n,
|
||||
fieldMap,
|
||||
diffComponents,
|
||||
}) => {
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
@@ -36,12 +36,12 @@ const Nested: React.FC<Props> = ({
|
||||
>
|
||||
<RenderFieldsToDiff
|
||||
comparison={comparison}
|
||||
diffComponents={diffComponents}
|
||||
fieldMap={fieldMap}
|
||||
fieldPermissions={permissions}
|
||||
i18n={i18n}
|
||||
locales={locales}
|
||||
version={version}
|
||||
i18n={i18n}
|
||||
diffComponents={diffComponents}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react'
|
||||
import type { RelationshipField, SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { fieldAffectsData, fieldIsPresentationalOnly } from 'payload/types'
|
||||
import React from 'react'
|
||||
import ReactDiffViewer from 'react-diff-viewer-continued'
|
||||
|
||||
import type { RelationshipField, SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { Props } from '../types'
|
||||
|
||||
import { fieldAffectsData, fieldIsPresentationalOnly } from 'payload/types'
|
||||
import Label from '../../Label'
|
||||
import { diffStyles } from '../styles'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'relationship-diff'
|
||||
@@ -68,9 +68,9 @@ const generateLabelFromValue = (
|
||||
const Relationship: React.FC<Props & { field: RelationshipField }> = ({
|
||||
comparison,
|
||||
field,
|
||||
version,
|
||||
i18n,
|
||||
locale,
|
||||
version,
|
||||
}) => {
|
||||
let placeholder = ''
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer-continued'
|
||||
export const DiffViewer: React.FC<{
|
||||
comparisonToRender: string
|
||||
diffMethod: string
|
||||
diffStyles: any
|
||||
placeholder: string
|
||||
versionToRender: string
|
||||
diffStyles: any
|
||||
}> = ({ comparisonToRender, diffMethod, placeholder, versionToRender, diffStyles }) => {
|
||||
}> = ({ comparisonToRender, diffMethod, diffStyles, placeholder, versionToRender }) => {
|
||||
return (
|
||||
<ReactDiffViewer
|
||||
compareMethod={DiffMethod[diffMethod]}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { getTranslation, I18n } from '@payloadcms/translations'
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { OptionObject, SelectField } from 'payload/types'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import React from 'react'
|
||||
|
||||
import type { OptionObject, SelectField } from 'payload/types'
|
||||
import type { Props } from '../types'
|
||||
|
||||
import Label from '../../Label'
|
||||
import { diffStyles } from '../styles'
|
||||
import { DiffViewer } from './DiffViewer'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'select-diff'
|
||||
@@ -42,7 +44,7 @@ const getTranslatedOptions = (
|
||||
return typeof options === 'string' ? options : getTranslation(options.label, i18n)
|
||||
}
|
||||
|
||||
const Select: React.FC<Props> = ({ comparison, diffMethod, field, locale, version, i18n }) => {
|
||||
const Select: React.FC<Props> = ({ comparison, diffMethod, field, i18n, locale, version }) => {
|
||||
let placeholder = ''
|
||||
|
||||
if (version === comparison) placeholder = `[${i18n.t('general:noValue')}]`
|
||||
@@ -64,11 +66,11 @@ const Select: React.FC<Props> = ({ comparison, diffMethod, field, locale, versio
|
||||
{getTranslation(field.label || '', i18n)}
|
||||
</Label>
|
||||
<DiffViewer
|
||||
diffMethod={diffMethod}
|
||||
versionToRender={versionToRender}
|
||||
comparisonToRender={comparisonToRender}
|
||||
placeholder={placeholder}
|
||||
diffMethod={diffMethod}
|
||||
diffStyles={diffStyles}
|
||||
placeholder={placeholder}
|
||||
versionToRender={versionToRender}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -9,13 +9,13 @@ const baseClass = 'tabs-diff'
|
||||
|
||||
const Tabs: React.FC<Props> = ({
|
||||
comparison,
|
||||
diffComponents,
|
||||
field,
|
||||
i18n,
|
||||
locale,
|
||||
locales,
|
||||
permissions,
|
||||
version,
|
||||
i18n,
|
||||
locale,
|
||||
diffComponents,
|
||||
}) => {
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
@@ -25,15 +25,15 @@ const Tabs: React.FC<Props> = ({
|
||||
return (
|
||||
<Nested
|
||||
comparison={comparison?.[tab.name]}
|
||||
diffComponents={diffComponents}
|
||||
field={field}
|
||||
fieldMap={tab.subfields}
|
||||
i18n={i18n}
|
||||
key={i}
|
||||
locale={locale}
|
||||
locales={locales}
|
||||
permissions={permissions}
|
||||
version={version?.[tab.name]}
|
||||
i18n={i18n}
|
||||
locale={locale}
|
||||
field={field}
|
||||
diffComponents={diffComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -41,13 +41,13 @@ const Tabs: React.FC<Props> = ({
|
||||
return (
|
||||
<RenderFieldsToDiff
|
||||
comparison={comparison}
|
||||
diffComponents={diffComponents}
|
||||
fieldMap={tab.subfields}
|
||||
fieldPermissions={permissions}
|
||||
i18n={i18n}
|
||||
key={i}
|
||||
locales={locales}
|
||||
version={version}
|
||||
i18n={i18n}
|
||||
diffComponents={diffComponents}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -5,10 +5,10 @@ import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer-continued'
|
||||
export const DiffViewer: React.FC<{
|
||||
comparisonToRender: string
|
||||
diffMethod: string
|
||||
diffStyles: any
|
||||
placeholder: string
|
||||
versionToRender: string
|
||||
diffStyles: any
|
||||
}> = ({ comparisonToRender, diffMethod, placeholder, versionToRender, diffStyles }) => {
|
||||
}> = ({ comparisonToRender, diffMethod, diffStyles, placeholder, versionToRender }) => {
|
||||
return (
|
||||
<ReactDiffViewer
|
||||
compareMethod={DiffMethod[diffMethod]}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import React from 'react'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import React from 'react'
|
||||
|
||||
import type { Props } from '../types'
|
||||
|
||||
import Label from '../../Label'
|
||||
import { diffStyles } from '../styles'
|
||||
import { DiffViewer } from './DiffViewer'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'text-diff'
|
||||
@@ -15,10 +14,10 @@ const Text: React.FC<Props> = ({
|
||||
comparison,
|
||||
diffMethod,
|
||||
field,
|
||||
i18n,
|
||||
isRichText = false,
|
||||
locale,
|
||||
version,
|
||||
i18n,
|
||||
}) => {
|
||||
let placeholder = ''
|
||||
|
||||
@@ -41,9 +40,9 @@ const Text: React.FC<Props> = ({
|
||||
<DiffViewer
|
||||
comparisonToRender={comparisonToRender}
|
||||
diffMethod={diffMethod}
|
||||
diffStyles={diffStyles}
|
||||
placeholder={placeholder}
|
||||
versionToRender={versionToRender}
|
||||
diffStyles={diffStyles}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { FieldMap, MappedField } from '@payloadcms/ui'
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
import type React from 'react'
|
||||
import type { DiffMethod } from 'react-diff-viewer-continued'
|
||||
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
import { FieldMap, MappedField } from '@payloadcms/ui'
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
|
||||
export type DiffComponents = Record<string, React.FC<Props>>
|
||||
|
||||
export type Props = {
|
||||
comparison: any
|
||||
diffComponents: DiffComponents
|
||||
diffMethod?: DiffMethod
|
||||
disableGutter?: boolean
|
||||
field: MappedField
|
||||
fieldMap: FieldMap
|
||||
i18n: I18n
|
||||
isRichText?: boolean
|
||||
locale?: string
|
||||
locales?: string[]
|
||||
permissions?: Record<string, FieldPermissions>
|
||||
version: any
|
||||
fieldMap: FieldMap
|
||||
i18n: I18n
|
||||
diffComponents: DiffComponents
|
||||
}
|
||||
|
||||
@@ -3,23 +3,22 @@ import type { DiffMethod } from 'react-diff-viewer-continued'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import type { Props, FieldDiffProps } from './types'
|
||||
import type { FieldDiffProps, Props } from './types'
|
||||
|
||||
import Nested from './fields/Nested'
|
||||
import { diffMethods } from './fields/diffMethods'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'render-field-diffs'
|
||||
|
||||
const RenderFieldsToDiff: React.FC<Props> = ({
|
||||
comparison,
|
||||
fieldPermissions,
|
||||
diffComponents,
|
||||
fieldMap,
|
||||
fieldPermissions,
|
||||
i18n,
|
||||
locales,
|
||||
version,
|
||||
i18n,
|
||||
diffComponents,
|
||||
}) => {
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
@@ -50,15 +49,15 @@ const RenderFieldsToDiff: React.FC<Props> = ({
|
||||
if (hasPermission === false) return null
|
||||
|
||||
const baseCellProps: FieldDiffProps = {
|
||||
comparison: comparisonValue,
|
||||
diffComponents,
|
||||
diffMethod,
|
||||
field,
|
||||
isRichText,
|
||||
locales: locales,
|
||||
fieldMap: 'subfields' in field ? field.subfields : fieldMap,
|
||||
fieldPermissions: subFieldPermissions,
|
||||
i18n,
|
||||
fieldMap: 'subfields' in field ? field.subfields : fieldMap,
|
||||
diffComponents,
|
||||
comparison: comparisonValue,
|
||||
isRichText,
|
||||
locales: locales,
|
||||
version: versionValue,
|
||||
}
|
||||
|
||||
@@ -71,8 +70,8 @@ const RenderFieldsToDiff: React.FC<Props> = ({
|
||||
|
||||
const cellProps = {
|
||||
...baseCellProps,
|
||||
version: versionLocaleValue,
|
||||
comparison: comparisonLocaleValue,
|
||||
version: versionLocaleValue,
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -100,13 +99,13 @@ const RenderFieldsToDiff: React.FC<Props> = ({
|
||||
return (
|
||||
<Tabs
|
||||
comparison={comparison}
|
||||
diffComponents={diffComponents}
|
||||
field={field}
|
||||
fieldMap={field.subfields}
|
||||
i18n={i18n}
|
||||
key={i}
|
||||
locales={locales}
|
||||
version={version}
|
||||
i18n={i18n}
|
||||
field={field}
|
||||
fieldMap={field.subfields}
|
||||
diffComponents={diffComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -116,15 +115,15 @@ const RenderFieldsToDiff: React.FC<Props> = ({
|
||||
return (
|
||||
<Nested
|
||||
comparison={comparison}
|
||||
diffComponents={diffComponents}
|
||||
disableGutter
|
||||
field={field}
|
||||
fieldMap={field.subfields}
|
||||
i18n={i18n}
|
||||
key={i}
|
||||
locales={locales}
|
||||
permissions={fieldPermissions}
|
||||
version={version}
|
||||
i18n={i18n}
|
||||
diffComponents={diffComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
import { FieldMap, MappedField } from '@payloadcms/ui'
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import { DiffComponents } from './fields/types'
|
||||
import type { FieldMap, MappedField } from '@payloadcms/ui'
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
import type { DiffMethod } from 'react-diff-viewer-continued'
|
||||
|
||||
import type { DiffComponents } from './fields/types'
|
||||
|
||||
export type Props = {
|
||||
comparison: Record<string, any>
|
||||
fieldPermissions: Record<string, FieldPermissions>
|
||||
diffComponents: DiffComponents
|
||||
fieldMap: FieldMap
|
||||
fieldPermissions: Record<string, FieldPermissions>
|
||||
i18n: I18n
|
||||
locales: string[]
|
||||
version: Record<string, any>
|
||||
i18n: I18n
|
||||
diffComponents: DiffComponents
|
||||
}
|
||||
|
||||
export type FieldDiffProps = Props & {
|
||||
field: MappedField
|
||||
diffMethod: DiffMethod
|
||||
field: MappedField
|
||||
isRichText: boolean
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import { Modal, useModal } from '@faceless-ui/modal'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { Button, MinimalTemplate, Pill, useConfig, useTranslation } from '@payloadcms/ui'
|
||||
import React, { Fragment, useCallback, useState } from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import type { Props } from './types'
|
||||
|
||||
import { Button, MinimalTemplate, Pill, useConfig, useTranslation } from '@payloadcms/ui'
|
||||
// import { requests } from '../../../../api'
|
||||
import './index.scss'
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ export type Props = {
|
||||
collectionSlug?: SanitizedCollectionConfig['slug']
|
||||
globalSlug?: SanitizedGlobalConfig['slug']
|
||||
label: SanitizedCollectionConfig['labels']['singular'] | SanitizedGlobalConfig['label']
|
||||
originalDocID: string | number
|
||||
originalDocID: number | string
|
||||
versionDate: string
|
||||
versionID: string
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
'use client'
|
||||
import qs from 'qs'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { useTranslation } from '@payloadcms/ui'
|
||||
|
||||
import type { PaginatedDocs } from 'payload/database'
|
||||
import type { Where } from 'payload/types'
|
||||
|
||||
import { useTranslation } from '@payloadcms/ui'
|
||||
import { ReactSelect, fieldBaseClass, formatDate, useConfig } from '@payloadcms/ui'
|
||||
import qs from 'qs'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import type { Props } from './types'
|
||||
|
||||
import { formatDate, ReactSelect, fieldBaseClass, useConfig } from '@payloadcms/ui'
|
||||
import { mostRecentVersionOption, publishedVersionOption } from '../shared'
|
||||
import './index.scss'
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { PaginatedDocs } from 'payload/database'
|
||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
import type { CompareOption } from '../Default/types'
|
||||
|
||||
export type Props = {
|
||||
baseURL: string
|
||||
onChange: (val: CompareOption) => void
|
||||
parentID?: string | number
|
||||
parentID?: number | string
|
||||
publishedDoc: any
|
||||
value: CompareOption
|
||||
versionID: string
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from '@payloadcms/ui'
|
||||
import { ReactSelect, useLocale } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
import type { Props } from './types'
|
||||
|
||||
import { ReactSelect, useLocale } from '@payloadcms/ui'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'select-version-locales'
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import type { Option, ServerSideEditViewProps } from '@payloadcms/ui'
|
||||
import type { CollectionPermission, GlobalPermission } from 'payload/auth'
|
||||
import type { Document } from 'payload/types'
|
||||
|
||||
import { notFound } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import { DefaultVersionView } from './Default'
|
||||
import { Document } from 'payload/types'
|
||||
import type { Option, ServerSideEditViewProps } from '@payloadcms/ui'
|
||||
import { CollectionPermission, GlobalPermission } from 'payload/auth'
|
||||
import { notFound } from 'next/navigation'
|
||||
|
||||
export const VersionView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
const { config, permissions, payload, user, params } = props
|
||||
const { config, params, payload, permissions, user } = props
|
||||
|
||||
const versionID = params.segments[2]
|
||||
|
||||
@@ -33,23 +34,23 @@ export const VersionView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
|
||||
try {
|
||||
doc = await payload.findVersionByID({
|
||||
collection: slug,
|
||||
id: versionID,
|
||||
collection: slug,
|
||||
depth: 1,
|
||||
locale: '*',
|
||||
})
|
||||
|
||||
publishedDoc = await payload.findByID({
|
||||
collection: slug,
|
||||
id,
|
||||
collection: slug,
|
||||
depth: 1,
|
||||
draft: false,
|
||||
locale: '*',
|
||||
})
|
||||
|
||||
mostRecentDoc = await payload.findByID({
|
||||
collection: slug,
|
||||
id,
|
||||
collection: slug,
|
||||
depth: 1,
|
||||
draft: true,
|
||||
locale: '*',
|
||||
@@ -65,24 +66,24 @@ export const VersionView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
|
||||
try {
|
||||
doc = payload.findGlobalVersionByID({
|
||||
slug,
|
||||
id: versionID,
|
||||
depth: 1,
|
||||
locale: '*',
|
||||
slug,
|
||||
})
|
||||
|
||||
publishedDoc = payload.findGlobal({
|
||||
slug,
|
||||
depth: 1,
|
||||
draft: false,
|
||||
locale: '*',
|
||||
slug,
|
||||
})
|
||||
|
||||
mostRecentDoc = payload.findGlobal({
|
||||
slug,
|
||||
depth: 1,
|
||||
draft: true,
|
||||
locale: '*',
|
||||
slug,
|
||||
})
|
||||
} catch (error) {
|
||||
return notFound()
|
||||
@@ -104,17 +105,17 @@ export const VersionView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
return (
|
||||
<DefaultVersionView
|
||||
collectionSlug={collectionSlug}
|
||||
globalSlug={globalSlug}
|
||||
initialComparisonDoc={mostRecentDoc}
|
||||
doc={doc}
|
||||
docPermissions={docPermissions}
|
||||
globalSlug={globalSlug}
|
||||
id={id}
|
||||
initialComparisonDoc={mostRecentDoc}
|
||||
localeOptions={localeOptions}
|
||||
mostRecentDoc={mostRecentDoc}
|
||||
id={id}
|
||||
permissions={permissions}
|
||||
publishedDoc={publishedDoc}
|
||||
user={user}
|
||||
versionID={versionID}
|
||||
docPermissions={docPermissions}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { Column } from '@payloadcms/ui'
|
||||
import type {
|
||||
SanitizedCollectionConfig,
|
||||
SanitizedConfig,
|
||||
SanitizedGlobalConfig,
|
||||
} from 'payload/types'
|
||||
|
||||
import type { Column } from '@payloadcms/ui'
|
||||
import { SortColumn } from '@payloadcms/ui'
|
||||
import { I18n } from '@payloadcms/translations'
|
||||
import React from 'react'
|
||||
|
||||
import { AutosaveCell } from './cells/AutosaveCell'
|
||||
import { CreatedAtCell } from './cells/CreatedAt'
|
||||
import { IDCell } from './cells/ID'
|
||||
import { AutosaveCell } from './cells/AutosaveCell'
|
||||
|
||||
export const buildVersionColumns = ({
|
||||
config,
|
||||
collectionConfig,
|
||||
globalConfig,
|
||||
config,
|
||||
docID,
|
||||
globalConfig,
|
||||
i18n: { t },
|
||||
i18n,
|
||||
}: {
|
||||
config: SanitizedConfig
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
config: SanitizedConfig
|
||||
docID?: number | string
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
docID?: string | number
|
||||
i18n: I18n
|
||||
}): Column[] => [
|
||||
{
|
||||
@@ -32,14 +32,14 @@ export const buildVersionColumns = ({
|
||||
accessor: 'updatedAt',
|
||||
active: true,
|
||||
components: {
|
||||
Heading: <SortColumn label={t('general:updatedAt')} name="updatedAt" />,
|
||||
Cell: (
|
||||
<CreatedAtCell
|
||||
docID={docID}
|
||||
collectionSlug={collectionConfig?.slug}
|
||||
docID={docID}
|
||||
globalSlug={globalConfig?.slug}
|
||||
/>
|
||||
),
|
||||
Heading: <SortColumn label={t('general:updatedAt')} name="updatedAt" />,
|
||||
},
|
||||
label: '',
|
||||
},
|
||||
@@ -48,8 +48,8 @@ export const buildVersionColumns = ({
|
||||
accessor: 'id',
|
||||
active: true,
|
||||
components: {
|
||||
Heading: <SortColumn disable label={t('version:versionID')} name="id" />,
|
||||
Cell: <IDCell />,
|
||||
Heading: <SortColumn disable label={t('version:versionID')} name="id" />,
|
||||
},
|
||||
label: '',
|
||||
},
|
||||
@@ -58,8 +58,8 @@ export const buildVersionColumns = ({
|
||||
accessor: 'autosave',
|
||||
active: true,
|
||||
components: {
|
||||
Heading: <SortColumn disable label={t('version:type')} name="autosave" />,
|
||||
Cell: <AutosaveCell />,
|
||||
Heading: <SortColumn disable label={t('version:type')} name="autosave" />,
|
||||
},
|
||||
label: '',
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import { Pill, useTableCell, useTranslation } from '@payloadcms/ui'
|
||||
import React, { Fragment } from 'react'
|
||||
import { useTranslation, useTableCell, Pill } from '@payloadcms/ui'
|
||||
|
||||
export const AutosaveCell: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import { formatDate, useConfig, useTranslation, useTableCell } from '@payloadcms/ui'
|
||||
import { formatDate, useConfig, useTableCell, useTranslation } from '@payloadcms/ui'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
type CreatedAtCellProps = {
|
||||
collectionSlug?: string
|
||||
docID?: number | string
|
||||
globalSlug?: string
|
||||
docID?: string | number
|
||||
}
|
||||
|
||||
export const CreatedAtCell: React.FC<CreatedAtCellProps> = ({
|
||||
collectionSlug,
|
||||
globalSlug,
|
||||
docID,
|
||||
globalSlug,
|
||||
}) => {
|
||||
const {
|
||||
routes: { admin },
|
||||
admin: { dateFormat },
|
||||
routes: { admin },
|
||||
} = useConfig()
|
||||
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import React, { Fragment } from 'react'
|
||||
import { useTableCell } from '@payloadcms/ui'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
export const IDCell: React.FC = () => {
|
||||
const { cellData } = useTableCell()
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
'use client'
|
||||
import type { Column } from '@payloadcms/ui'
|
||||
import type { PaginatedDocs } from 'payload/database'
|
||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
||||
|
||||
import {
|
||||
Column,
|
||||
LoadingOverlayToggle,
|
||||
Pagination,
|
||||
PerPage,
|
||||
@@ -9,21 +12,19 @@ import {
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { PaginatedDocs } from 'payload/database'
|
||||
import { SanitizedCollectionConfig } from 'payload/types'
|
||||
import React, { Fragment, useEffect, useRef } from 'react'
|
||||
|
||||
export const VersionsViewClient: React.FC<{
|
||||
initialData: PaginatedDocs
|
||||
columns: Column[]
|
||||
baseClass: string
|
||||
fetchURL: string
|
||||
collectionSlug?: string
|
||||
columns: Column[]
|
||||
fetchURL: string
|
||||
globalSlug?: string
|
||||
id?: string | number
|
||||
id?: number | string
|
||||
initialData: PaginatedDocs
|
||||
paginationLimits?: SanitizedCollectionConfig['admin']['pagination']['limits']
|
||||
}> = (props) => {
|
||||
const { initialData, columns, baseClass, collectionSlug, fetchURL, id, paginationLimits } = props
|
||||
const { id, baseClass, collectionSlug, columns, fetchURL, initialData, paginationLimits } = props
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const limit = searchParams.get('limit')
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { ServerSideEditViewProps } from '@payloadcms/ui'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { Gutter, SetDocumentStepNav as SetStepNav } from '@payloadcms/ui'
|
||||
import { notFound } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import { Gutter, SetDocumentStepNav as SetStepNav, ServerSideEditViewProps } from '@payloadcms/ui'
|
||||
import { buildVersionColumns } from './buildColumns'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { VersionsViewClient } from './index.client'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
export const baseClass = 'versions'
|
||||
|
||||
export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) => {
|
||||
const { user, payload, config, searchParams, i18n } = props
|
||||
const { config, i18n, payload, searchParams, user } = props
|
||||
|
||||
const id = 'id' in props ? props.id : undefined
|
||||
const collectionConfig = 'collectionConfig' in props && props?.collectionConfig
|
||||
@@ -37,10 +38,10 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
versionsData = await payload.findVersions({
|
||||
collection: collectionSlug,
|
||||
depth: 0,
|
||||
user,
|
||||
limit: limit ? parseInt(limit?.toString(), 10) : undefined,
|
||||
page: page ? parseInt(page.toString(), 10) : undefined,
|
||||
sort: sort as string,
|
||||
limit: limit ? parseInt(limit?.toString(), 10) : undefined,
|
||||
user,
|
||||
where: {
|
||||
parent: {
|
||||
equals: id,
|
||||
@@ -59,11 +60,11 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
if (globalSlug) {
|
||||
try {
|
||||
versionsData = await payload.findGlobalVersions({
|
||||
slug: globalSlug,
|
||||
depth: 0,
|
||||
user,
|
||||
page: page ? parseInt(page as string, 10) : undefined,
|
||||
slug: globalSlug,
|
||||
sort: sort as string,
|
||||
user,
|
||||
where: {
|
||||
parent: {
|
||||
equals: id,
|
||||
@@ -84,18 +85,18 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
}
|
||||
|
||||
const columns = buildVersionColumns({
|
||||
config,
|
||||
collectionConfig,
|
||||
globalConfig,
|
||||
config,
|
||||
docID: id,
|
||||
globalConfig,
|
||||
i18n,
|
||||
})
|
||||
|
||||
const fetchURL = collectionSlug
|
||||
? `${serverURL}${apiRoute}/${collectionSlug}/versions`
|
||||
: globalSlug
|
||||
? `${serverURL}${apiRoute}/globals/${globalSlug}/versions`
|
||||
: ''
|
||||
? `${serverURL}${apiRoute}/globals/${globalSlug}/versions`
|
||||
: ''
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -110,13 +111,13 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
|
||||
<main className={baseClass}>
|
||||
<Gutter className={`${baseClass}__wrap`}>
|
||||
<VersionsViewClient
|
||||
initialData={versionsData}
|
||||
columns={columns}
|
||||
fetchURL={fetchURL}
|
||||
baseClass={baseClass}
|
||||
collectionSlug={collectionSlug}
|
||||
columns={columns}
|
||||
fetchURL={fetchURL}
|
||||
globalSlug={globalSlug}
|
||||
id={id}
|
||||
initialData={versionsData}
|
||||
paginationLimits={collectionConfig?.admin?.pagination?.limits}
|
||||
/>
|
||||
</Gutter>
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { User } from 'payload/auth'
|
||||
import type { PaginatedDocs } from 'payload/database'
|
||||
import type {
|
||||
SanitizedCollectionConfig,
|
||||
SanitizedConfig,
|
||||
SanitizedGlobalConfig,
|
||||
} from 'payload/types'
|
||||
import type { PaginatedDocs } from 'payload/database'
|
||||
import { User } from 'payload/auth'
|
||||
import { I18n } from '@payloadcms/translations'
|
||||
|
||||
export type DefaultVersionsViewProps = {
|
||||
canAccessAdmin: boolean
|
||||
config: SanitizedConfig
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
config: SanitizedConfig
|
||||
data: Document
|
||||
versionsData: PaginatedDocs<Document>
|
||||
editURL: string
|
||||
entityLabel: string
|
||||
id: string | number
|
||||
user: User
|
||||
limit: number
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
i18n: I18n
|
||||
id: number | string
|
||||
limit: number
|
||||
user: User
|
||||
versionsData: PaginatedDocs<Document>
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { GraphQLError } from 'graphql'
|
||||
import httpStatus from 'http-status'
|
||||
import { configToSchema } from '@payloadcms/graphql'
|
||||
import type { Payload, CollectionAfterErrorHook, SanitizedConfig } from 'payload/types'
|
||||
import type { GraphQLFormattedError } from 'graphql'
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest'
|
||||
import type { GraphQLError } from 'graphql'
|
||||
import type { CollectionAfterErrorHook, Payload, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { configToSchema } from '@payloadcms/graphql'
|
||||
import { createHandler } from 'graphql-http/lib/use/fetch'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest'
|
||||
|
||||
const handleError = async (
|
||||
payload: Payload,
|
||||
@@ -75,8 +77,8 @@ export const POST =
|
||||
(config: Promise<SanitizedConfig> | SanitizedConfig) => async (request: Request) => {
|
||||
const originalRequest = request.clone()
|
||||
const req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
request,
|
||||
})
|
||||
const { schema, validationRules } = await getGraphql(config)
|
||||
|
||||
@@ -87,7 +89,7 @@ export const POST =
|
||||
|
||||
const headers = {}
|
||||
const apiResponse = await createHandler({
|
||||
context: { req, headers },
|
||||
context: { headers, req },
|
||||
onOperation: async (request, args, result) => {
|
||||
const response =
|
||||
typeof payload.extensions === 'function'
|
||||
@@ -113,12 +115,12 @@ export const POST =
|
||||
})(originalRequest)
|
||||
|
||||
const resHeaders = new Headers(apiResponse.headers)
|
||||
for (let key in headers) {
|
||||
for (const key in headers) {
|
||||
resHeaders.append(key, headers[key])
|
||||
}
|
||||
|
||||
return new Response(apiResponse.body, {
|
||||
status: apiResponse.status,
|
||||
headers: new Headers(resHeaders),
|
||||
status: apiResponse.status,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { renderPlaygroundPage } from 'graphql-playground-html'
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { renderPlaygroundPage } from 'graphql-playground-html'
|
||||
|
||||
import { createPayloadRequest } from '../../utilities/createPayloadRequest'
|
||||
|
||||
export const GET = (config: Promise<SanitizedConfig>) => async (request: Request) => {
|
||||
const req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
request,
|
||||
})
|
||||
|
||||
if (
|
||||
@@ -16,16 +18,16 @@ export const GET = (config: Promise<SanitizedConfig>) => async (request: Request
|
||||
) {
|
||||
return new Response(
|
||||
renderPlaygroundPage({
|
||||
endpoint: `${req.payload.config.routes.api}${req.payload.config.routes.graphQL}`,
|
||||
settings: {
|
||||
'request.credentials': 'include',
|
||||
},
|
||||
endpoint: `${req.payload.config.routes.api}${req.payload.config.routes.graphQL}`,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'text/html',
|
||||
},
|
||||
status: 200,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export { GRAPHQL_PLAYGROUND_GET, GRAPHQL_POST } from './graphql'
|
||||
|
||||
export {
|
||||
GET as REST_GET,
|
||||
POST as REST_POST,
|
||||
DELETE as REST_DELETE,
|
||||
GET as REST_GET,
|
||||
PATCH as REST_PATCH,
|
||||
POST as REST_POST,
|
||||
} from './rest'
|
||||
|
||||
export { GET as GET_STATIC_FILE } from './rest/[collection]/file/[filename]/route'
|
||||
|
||||
export { GRAPHQL_POST, GRAPHQL_PLAYGROUND_GET } from './graphql'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Collection, PayloadRequest } from 'payload/types'
|
||||
import { APIError } from 'payload/errors'
|
||||
|
||||
import httpStatus from 'http-status'
|
||||
import { APIError } from 'payload/errors'
|
||||
|
||||
export type ErrorResponse = { data?: any; errors: unknown[]; stack?: string }
|
||||
|
||||
@@ -58,13 +59,13 @@ const formatErrors = (incoming: { [key: string]: unknown } | APIError | Error):
|
||||
}
|
||||
|
||||
export const RouteError = async ({
|
||||
req,
|
||||
err,
|
||||
collection,
|
||||
err,
|
||||
req,
|
||||
}: {
|
||||
req: PayloadRequest
|
||||
err: APIError
|
||||
collection?: Collection
|
||||
err: APIError
|
||||
req: PayloadRequest
|
||||
}) => {
|
||||
if (!req?.payload) {
|
||||
return Response.json(
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
import path from 'path'
|
||||
import { streamFile } from '../../../../../next-stream-file'
|
||||
import fsPromises from 'fs/promises'
|
||||
import type { Collection, PayloadRequest, SanitizedConfig, Where } from 'payload/types'
|
||||
|
||||
import fsPromises from 'fs/promises'
|
||||
import httpStatus from 'http-status'
|
||||
import path from 'path'
|
||||
import { executeAccess } from 'payload/auth'
|
||||
import { APIError, Forbidden } from 'payload/errors'
|
||||
import { RouteError } from '../../../RouteError'
|
||||
|
||||
import { streamFile } from '../../../../../next-stream-file'
|
||||
import { createPayloadRequest } from '../../../../../utilities/createPayloadRequest'
|
||||
import httpStatus from 'http-status'
|
||||
import { RouteError } from '../../../RouteError'
|
||||
import { endpointsAreDisabled } from '../../../checkEndpoints'
|
||||
|
||||
async function checkFileAccess({
|
||||
req,
|
||||
filename,
|
||||
collection,
|
||||
filename,
|
||||
req,
|
||||
}: {
|
||||
req: PayloadRequest
|
||||
filename: string
|
||||
collection: Collection
|
||||
filename: string
|
||||
req: PayloadRequest
|
||||
}) {
|
||||
const { config } = collection
|
||||
const disableEndpoints = endpointsAreDisabled({ request: req, endpoints: config.endpoints })
|
||||
const disableEndpoints = endpointsAreDisabled({ endpoints: config.endpoints, request: req })
|
||||
if (disableEndpoints) return disableEndpoints
|
||||
|
||||
const accessResult = await executeAccess({ isReadingStaticFile: true, req }, config.access.read)
|
||||
@@ -71,9 +73,9 @@ export const GET =
|
||||
|
||||
try {
|
||||
req = await createPayloadRequest({
|
||||
request,
|
||||
config,
|
||||
params: { collection: collectionSlug },
|
||||
request,
|
||||
})
|
||||
collection = req.payload.collections?.[collectionSlug]
|
||||
|
||||
@@ -96,9 +98,9 @@ export const GET =
|
||||
}
|
||||
|
||||
await checkFileAccess({
|
||||
req,
|
||||
filename,
|
||||
collection,
|
||||
filename,
|
||||
req,
|
||||
})
|
||||
|
||||
const fileDir = collection.config.upload?.staticDir || collection.config.slug
|
||||
@@ -106,16 +108,16 @@ export const GET =
|
||||
const stats = await fsPromises.stat(filePath)
|
||||
const data = streamFile(filePath)
|
||||
return new Response(data, {
|
||||
status: httpStatus.OK,
|
||||
headers: new Headers({
|
||||
'content-length': stats.size + '',
|
||||
}),
|
||||
status: httpStatus.OK,
|
||||
})
|
||||
} catch (error) {
|
||||
return RouteError({
|
||||
req,
|
||||
collection,
|
||||
err: error,
|
||||
req,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import httpStatus from 'http-status'
|
||||
import { accessOperation } from 'payload/operations'
|
||||
import { BaseRouteHandler } from '../types'
|
||||
|
||||
import type { BaseRouteHandler } from '../types'
|
||||
|
||||
export const access: BaseRouteHandler = async ({ req }) => {
|
||||
const results = await accessOperation({
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { forgotPasswordOperation } from 'payload/operations'
|
||||
import httpStatus from 'http-status'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { forgotPasswordOperation } from 'payload/operations'
|
||||
|
||||
export const forgotPassword: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const forgotPassword: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
await forgotPasswordOperation({
|
||||
collection,
|
||||
data: {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { initOperation } from 'payload/operations'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const init: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const init: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const initialized = await initOperation({
|
||||
collection: collection.config.slug,
|
||||
req,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import httpStatus from 'http-status'
|
||||
import { generatePayloadCookie } from 'payload/auth'
|
||||
import { loginOperation } from 'payload/operations'
|
||||
import { isNumber } from 'payload/utilities'
|
||||
import { generatePayloadCookie } from 'payload/auth'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const login: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const login: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const { searchParams } = req
|
||||
const depth = searchParams.get('depth')
|
||||
|
||||
@@ -19,9 +20,9 @@ export const login: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
})
|
||||
|
||||
const cookie = generatePayloadCookie({
|
||||
token: result.token,
|
||||
payload: req.payload,
|
||||
collectionConfig: collection.config,
|
||||
payload: req.payload,
|
||||
token: result.token,
|
||||
})
|
||||
|
||||
if (collection.config.auth.removeTokenFromResponses) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import httpStatus from 'http-status'
|
||||
import { logoutOperation } from 'payload/operations'
|
||||
import { generateExpiredPayloadCookie } from 'payload/auth'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { logoutOperation } from 'payload/operations'
|
||||
|
||||
export const logout: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const logout: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const result = logoutOperation({
|
||||
collection,
|
||||
req,
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import httpStatus from 'http-status'
|
||||
import { meOperation } from 'payload/operations'
|
||||
import { extractJWT } from 'payload/auth'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { meOperation } from 'payload/operations'
|
||||
|
||||
export const me: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const me: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const currentToken = extractJWT(req)
|
||||
|
||||
const result = await meOperation({
|
||||
collection,
|
||||
req,
|
||||
currentToken,
|
||||
req,
|
||||
})
|
||||
|
||||
if (collection.config.auth.removeTokenFromResponses) {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { extractJWT } from 'payload/auth'
|
||||
import { refreshOperation } from 'payload/operations'
|
||||
import httpStatus from 'http-status'
|
||||
import { extractJWT } from 'payload/auth'
|
||||
import { generatePayloadCookie } from 'payload/auth'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { refreshOperation } from 'payload/operations'
|
||||
|
||||
export const refresh: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const refresh: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const token = typeof req.data?.token === 'string' ? req.data.token : extractJWT(req)
|
||||
|
||||
if (!token) {
|
||||
@@ -20,15 +21,15 @@ export const refresh: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
}
|
||||
|
||||
const result = await refreshOperation({
|
||||
token,
|
||||
req,
|
||||
collection,
|
||||
req,
|
||||
token,
|
||||
})
|
||||
|
||||
const cookie = generatePayloadCookie({
|
||||
token: result.refreshedToken,
|
||||
payload: req.payload,
|
||||
collectionConfig: collection.config,
|
||||
payload: req.payload,
|
||||
token: result.refreshedToken,
|
||||
})
|
||||
|
||||
if (collection.config.auth.removeTokenFromResponses) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import httpStatus from 'http-status'
|
||||
import { registerFirstUserOperation } from 'payload/operations'
|
||||
import { generatePayloadCookie } from 'payload/auth'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { registerFirstUserOperation } from 'payload/operations'
|
||||
|
||||
export const registerFirstUser: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const registerFirstUser: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const result = await registerFirstUserOperation({
|
||||
collection,
|
||||
data: {
|
||||
@@ -14,9 +15,9 @@ export const registerFirstUser: CollectionRouteHandler = async ({ req, collectio
|
||||
})
|
||||
|
||||
const cookie = generatePayloadCookie({
|
||||
token: result.token,
|
||||
payload: req.payload,
|
||||
collectionConfig: collection.config,
|
||||
payload: req.payload,
|
||||
token: result.token,
|
||||
})
|
||||
|
||||
return Response.json(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import { resetPasswordOperation } from 'payload/operations'
|
||||
import { generatePayloadCookie } from 'payload/auth'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { resetPasswordOperation } from 'payload/operations'
|
||||
|
||||
export const resetPassword: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const resetPassword: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const { searchParams } = req
|
||||
const depth = searchParams.get('depth')
|
||||
|
||||
@@ -19,9 +19,9 @@ export const resetPassword: CollectionRouteHandler = async ({ req, collection })
|
||||
})
|
||||
|
||||
const cookie = generatePayloadCookie({
|
||||
token: result.token,
|
||||
payload: req.payload,
|
||||
collectionConfig: collection.config,
|
||||
payload: req.payload,
|
||||
token: result.token,
|
||||
})
|
||||
|
||||
if (collection.config.auth.removeTokenFromResponses) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import { unlockOperation } from 'payload/operations'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const unlock: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const unlock: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
await unlockOperation({
|
||||
collection,
|
||||
data: { email: req.data.email as string },
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import { verifyEmailOperation } from 'payload/operations'
|
||||
import { CollectionRouteHandlerWithID } from '../types'
|
||||
|
||||
export const verifyEmail: CollectionRouteHandlerWithID = async ({ req, id, collection }) => {
|
||||
import type { CollectionRouteHandlerWithID } from '../types'
|
||||
|
||||
export const verifyEmail: CollectionRouteHandlerWithID = async ({ id, collection, req }) => {
|
||||
await verifyEmailOperation({
|
||||
collection,
|
||||
req,
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import httpStatus from 'http-status'
|
||||
import type { BuildFormStateArgs, FieldSchemaMap } from '@payloadcms/ui'
|
||||
import type { Field, PayloadRequest, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import {
|
||||
BuildFormStateArgs,
|
||||
FieldSchemaMap,
|
||||
buildFieldSchemaMap,
|
||||
buildStateFromSchema,
|
||||
reduceFieldsToValues,
|
||||
} from '@payloadcms/ui'
|
||||
import { Field, PayloadRequest, SanitizedConfig } from 'payload/types'
|
||||
import { buildFieldSchemaMap, buildStateFromSchema, reduceFieldsToValues } from '@payloadcms/ui'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
let cached = global._payload_fieldSchemaMap
|
||||
|
||||
@@ -27,7 +22,7 @@ export const getFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
|
||||
}
|
||||
|
||||
export const buildFormState = async ({ req }: { req: PayloadRequest }) => {
|
||||
const { data: reqData, user, t, locale } = req
|
||||
const { data: reqData, locale, t, user } = req
|
||||
|
||||
// TODO: run ADMIN access control for user
|
||||
|
||||
@@ -35,10 +30,10 @@ export const buildFormState = async ({ req }: { req: PayloadRequest }) => {
|
||||
|
||||
const {
|
||||
id,
|
||||
operation,
|
||||
data: incomingData,
|
||||
docPreferences,
|
||||
formState,
|
||||
data: incomingData,
|
||||
operation,
|
||||
schemaPath,
|
||||
} = reqData as BuildFormStateArgs
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ import httpStatus from 'http-status'
|
||||
import { CollectionConfig, GlobalConfig } from 'payload/types'
|
||||
|
||||
export const endpointsAreDisabled = ({
|
||||
request,
|
||||
endpoints,
|
||||
request,
|
||||
}: {
|
||||
endpoints: false | unknown[]
|
||||
request: Partial<Request>
|
||||
endpoints: unknown[] | false
|
||||
}) => {
|
||||
if (!endpoints) {
|
||||
return Response.json(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import { isNumber } from 'payload/utilities'
|
||||
import { createOperation } from 'payload/operations'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { isNumber } from 'payload/utilities'
|
||||
|
||||
export const create: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const create: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const { searchParams } = req
|
||||
const autosave = searchParams.get('autosave') === 'true'
|
||||
const draft = searchParams.get('draft') === 'true'
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import type { Where } from 'payload/types'
|
||||
import { isNumber } from 'payload/utilities'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import httpStatus from 'http-status'
|
||||
import { deleteOperation } from 'payload/operations'
|
||||
import { CollectionRouteHandler } from '../types'
|
||||
import { isNumber } from 'payload/utilities'
|
||||
import qs from 'qs'
|
||||
|
||||
export const deleteDoc: CollectionRouteHandler = async ({ req, collection }) => {
|
||||
import type { CollectionRouteHandler } from '../types'
|
||||
|
||||
export const deleteDoc: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const { searchParams } = req
|
||||
|
||||
// parse using `qs` to handle `where` queries
|
||||
const { where, depth } = qs.parse(searchParams.toString()) as {
|
||||
where?: Where
|
||||
const { depth, where } = qs.parse(searchParams.toString()) as {
|
||||
depth?: string
|
||||
where?: Where
|
||||
}
|
||||
|
||||
const result = await deleteOperation({
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import { isNumber } from 'payload/utilities'
|
||||
import { deleteByIDOperation } from 'payload/operations'
|
||||
import { CollectionRouteHandlerWithID } from '../types'
|
||||
import { isNumber } from 'payload/utilities'
|
||||
|
||||
export const deleteByID: CollectionRouteHandlerWithID = async ({ req, collection, id }) => {
|
||||
import type { CollectionRouteHandlerWithID } from '../types'
|
||||
|
||||
export const deleteByID: CollectionRouteHandlerWithID = async ({ id, collection, req }) => {
|
||||
const { searchParams } = req
|
||||
const depth = searchParams.get('depth')
|
||||
const doc = await deleteByIDOperation({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user