Compare commits
11 Commits
v3.0.0-alp
...
v3.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca832a01cb | ||
|
|
aaa2b204ba | ||
|
|
78bf9e5993 | ||
|
|
8be0296fc1 | ||
|
|
26cd741c04 | ||
|
|
bf655b3327 | ||
|
|
1793b37adc | ||
|
|
d0ffe85abb | ||
|
|
f9f7dcfc58 | ||
|
|
f06257e7ff | ||
|
|
e490f0bce6 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"private": true,
|
||||
"workspaces:": [
|
||||
"packages/*"
|
||||
@@ -9,7 +9,7 @@
|
||||
"build": "pnpm run build:core",
|
||||
"build:all": "turbo build",
|
||||
"build:core": "turbo build --filter \"!@payloadcms/plugin-*\"",
|
||||
"build:plugins": "turbo build --filter \"@payloadcms/plugin-*\"",
|
||||
"build:plugins": "turbo build --filter \"@payloadcms/plugin-*\" --filter \"!@payloadcms/plugin-search\"",
|
||||
"build:app": "next build",
|
||||
"build:create-payload-app": "turbo build --filter create-payload-app",
|
||||
"build:db-mongodb": "turbo build --filter db-mongodb",
|
||||
@@ -129,6 +129,7 @@
|
||||
"read-stream": "^2.1.1",
|
||||
"rimraf": "3.0.2",
|
||||
"semver": "^7.5.4",
|
||||
"sharp": "0.32.6",
|
||||
"shelljs": "0.8.5",
|
||||
"simple-git": "^3.20.0",
|
||||
"slash": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"description": "The officially supported MongoDB database adapter for Payload - Update 2",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "0.7.0",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.d.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "commonjs"
|
||||
"type": "es6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.d.ts",
|
||||
"bin": {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { getRequestLanguage } from '../../utilities/getRequestLanguage'
|
||||
import { DefaultEditView } from '../../views/Edit/Default'
|
||||
import { DefaultListView } from '../../views/List/Default'
|
||||
import { DefaultCell } from '../../views/List/Default/Cell'
|
||||
import { getPayload } from '../../utilities/getPayload'
|
||||
|
||||
export const metadata = {
|
||||
description: 'Generated by Next.js',
|
||||
@@ -34,7 +35,13 @@ export const RootLayout = async ({
|
||||
const clientConfig = await createClientConfig(config)
|
||||
|
||||
const headers = getHeaders()
|
||||
const cookies = parseCookies(headers)
|
||||
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
|
||||
const { cookies, user, permissions } = await auth({
|
||||
payload,
|
||||
headers,
|
||||
})
|
||||
|
||||
const lang =
|
||||
getRequestLanguage({
|
||||
@@ -56,6 +63,7 @@ export const RootLayout = async ({
|
||||
DefaultEditView,
|
||||
DefaultListView,
|
||||
config,
|
||||
permissions: permissions,
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,7 @@ export const getPayload = async (options: InitOptions): Promise<Payload> => {
|
||||
const config = await options.config
|
||||
|
||||
if (cached.reload) {
|
||||
cached.reload = false
|
||||
if (typeof cached.payload.db.destroy === 'function') {
|
||||
await cached.payload.db.destroy()
|
||||
}
|
||||
@@ -32,7 +33,6 @@ export const getPayload = async (options: InitOptions): Promise<Payload> => {
|
||||
|
||||
await cached.payload.db.init()
|
||||
await cached.payload.db.connect({ hotReload: true })
|
||||
cached.reload = false
|
||||
}
|
||||
|
||||
return cached.payload
|
||||
@@ -49,7 +49,7 @@ export const getPayload = async (options: InitOptions): Promise<Payload> => {
|
||||
try {
|
||||
const ws = new WebSocket('ws://localhost:3000/_next/webpack-hmr')
|
||||
|
||||
ws.onmessage = async (event) => {
|
||||
ws.onmessage = (event) => {
|
||||
if (typeof event.data === 'string') {
|
||||
const data = JSON.parse(event.data)
|
||||
|
||||
|
||||
@@ -10,5 +10,10 @@ export const CreateFirstUserFields: React.FC<{
|
||||
|
||||
const fieldMap = getFieldMap({ collectionSlug: userSlug })
|
||||
|
||||
return <RenderFields fieldMap={[...(fieldMap || []), ...(createFirstUserFieldMap || [])]} />
|
||||
return (
|
||||
<RenderFields
|
||||
fieldMap={[...(fieldMap || []), ...(createFirstUserFieldMap || [])]}
|
||||
operation="create"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,10 +48,8 @@ export const CreateFirstUser: React.FC<AdminViewProps> = async ({ initPageResult
|
||||
|
||||
const createFirstUserFieldMap = mapFields({
|
||||
fieldSchema: fields,
|
||||
operation: 'create',
|
||||
config,
|
||||
parentPath: userSlug,
|
||||
permissions: {},
|
||||
})
|
||||
|
||||
const formState = await buildStateFromSchema({
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import React, { Fragment, useEffect, useState } from 'react'
|
||||
|
||||
import './index.scss'
|
||||
import { Permissions } from 'payload/auth'
|
||||
|
||||
const baseClass = 'dashboard'
|
||||
|
||||
@@ -22,7 +23,8 @@ export const DefaultDashboardClient: React.FC<{
|
||||
Link: React.ComponentType
|
||||
visibleCollections: string[]
|
||||
visibleGlobals: string[]
|
||||
}> = ({ Link, visibleCollections, visibleGlobals }) => {
|
||||
permissions: Permissions
|
||||
}> = ({ Link, visibleCollections, visibleGlobals, permissions }) => {
|
||||
const config = useConfig()
|
||||
|
||||
const {
|
||||
@@ -31,7 +33,7 @@ export const DefaultDashboardClient: React.FC<{
|
||||
routes: { admin },
|
||||
} = config
|
||||
|
||||
const { permissions, user } = useAuth()
|
||||
const { user } = useAuth()
|
||||
|
||||
const { i18n, t } = useTranslation()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import React from 'react'
|
||||
|
||||
import { DefaultDashboardClient } from './index.client'
|
||||
import './index.scss'
|
||||
import { Permissions } from 'payload/auth'
|
||||
|
||||
const baseClass = 'dashboard'
|
||||
|
||||
@@ -13,6 +14,7 @@ export type DashboardProps = {
|
||||
config: SanitizedConfig
|
||||
visibleCollections: string[]
|
||||
visibleGlobals: string[]
|
||||
permissions: Permissions
|
||||
}
|
||||
|
||||
export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
||||
@@ -25,6 +27,7 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
||||
},
|
||||
visibleCollections,
|
||||
visibleGlobals,
|
||||
permissions,
|
||||
} = props
|
||||
|
||||
return (
|
||||
@@ -38,6 +41,7 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
||||
Link={Link}
|
||||
visibleCollections={visibleCollections}
|
||||
visibleGlobals={visibleGlobals}
|
||||
permissions={permissions}
|
||||
/>
|
||||
{Array.isArray(afterDashboard) &&
|
||||
afterDashboard.map((Component, i) => <Component key={i} />)}
|
||||
|
||||
@@ -43,6 +43,7 @@ export const Dashboard: React.FC<AdminViewProps> = ({
|
||||
config,
|
||||
visibleCollections,
|
||||
visibleGlobals,
|
||||
permissions,
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -38,8 +38,6 @@ export const getViewsFromConfig = async ({
|
||||
let DefaultView: EditViewComponent = null
|
||||
let CustomView: EditViewComponent = null
|
||||
|
||||
const [entityType, entitySlug, createOrID, tabViewName, segmentFive] = routeSegments
|
||||
|
||||
const views =
|
||||
(collectionConfig && collectionConfig?.admin?.components?.views) ||
|
||||
(globalConfig && globalConfig?.admin?.components?.views)
|
||||
@@ -51,6 +49,9 @@ export const getViewsFromConfig = async ({
|
||||
config?.admin?.livePreview?.globals?.includes(globalConfig?.slug)
|
||||
|
||||
if (collectionConfig) {
|
||||
const [collectionEntity, collectionSlug, createOrID, nestedViewSlug, segmentFive] =
|
||||
routeSegments
|
||||
|
||||
const {
|
||||
admin: { hidden },
|
||||
} = collectionConfig
|
||||
@@ -60,7 +61,7 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
|
||||
// `../:id`, or `../create`
|
||||
if (!tabViewName) {
|
||||
if (!nestedViewSlug) {
|
||||
switch (createOrID) {
|
||||
case 'create': {
|
||||
if ('create' in docPermissions && docPermissions?.create?.permission) {
|
||||
@@ -79,10 +80,10 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
}
|
||||
|
||||
if (tabViewName) {
|
||||
if (nestedViewSlug) {
|
||||
// `../:id/versions/:version`, etc
|
||||
if (segmentFive) {
|
||||
if (tabViewName === 'versions') {
|
||||
if (nestedViewSlug === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = getCustomViewByKey(views, 'Version')
|
||||
DefaultView = DefaultVersionView
|
||||
@@ -92,7 +93,7 @@ export const getViewsFromConfig = async ({
|
||||
|
||||
// `../:id/api`, `../:id/preview`, `../:id/versions`, etc
|
||||
if (routeSegments?.length === 4) {
|
||||
switch (tabViewName) {
|
||||
switch (nestedViewSlug) {
|
||||
case 'api': {
|
||||
if (collectionConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = getCustomViewByKey(views, 'API')
|
||||
@@ -117,7 +118,7 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
|
||||
default: {
|
||||
const path = `/${tabViewName}`
|
||||
const path = `/${nestedViewSlug}`
|
||||
CustomView = getCustomViewByPath(views, path)
|
||||
break
|
||||
}
|
||||
@@ -127,6 +128,8 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
|
||||
if (globalConfig) {
|
||||
const [globalEntity, globalSlug, nestedViewSlug] = routeSegments
|
||||
|
||||
const {
|
||||
admin: { hidden },
|
||||
} = globalConfig
|
||||
@@ -135,14 +138,14 @@ export const getViewsFromConfig = async ({
|
||||
return null
|
||||
}
|
||||
|
||||
if (!routeSegments?.length) {
|
||||
if (routeSegments?.length === 2) {
|
||||
if (docPermissions?.read?.permission) {
|
||||
CustomView = getCustomViewByKey(views, 'Default')
|
||||
DefaultView = DefaultEditView
|
||||
}
|
||||
} else if (routeSegments?.length === 1) {
|
||||
} else if (routeSegments?.length === 3) {
|
||||
// `../:slug/api`, `../:slug/preview`, `../:slug/versions`, etc
|
||||
switch (tabViewName) {
|
||||
switch (nestedViewSlug) {
|
||||
case 'api': {
|
||||
if (globalConfig?.admin?.hideAPIURL !== true) {
|
||||
CustomView = getCustomViewByKey(views, 'API')
|
||||
@@ -176,7 +179,7 @@ export const getViewsFromConfig = async ({
|
||||
}
|
||||
} else if (routeSegments?.length === 2) {
|
||||
// `../:slug/versions/:version`, etc
|
||||
if (tabViewName === 'versions') {
|
||||
if (nestedViewSlug === 'versions') {
|
||||
if (docPermissions?.readVersions?.permission) {
|
||||
CustomView = getCustomViewByKey(views, 'Version')
|
||||
DefaultView = DefaultVersionView
|
||||
|
||||
@@ -59,7 +59,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
const segments = Array.isArray(params?.segments) ? params.segments : []
|
||||
const [entityType, entitySlug, createOrID] = segments
|
||||
const collectionSlug = entityType === 'collections' ? entitySlug : undefined
|
||||
const globalSlug = entitySlug === 'globals' ? entitySlug : undefined
|
||||
const globalSlug = entityType === 'globals' ? entitySlug : undefined
|
||||
const isCreating = createOrID === 'create'
|
||||
const id = (collectionSlug && !isCreating && createOrID) || undefined
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ export const DefaultEditView: React.FC = () => {
|
||||
|
||||
const globalConfig = globalSlug && globals.find((global) => global.slug === globalSlug)
|
||||
|
||||
const [schemaPath] = React.useState(collectionConfig?.slug || globalConfig?.slug)
|
||||
const schemaPath = collectionConfig?.slug || globalConfig?.slug
|
||||
|
||||
const fieldMap = getFieldMap({
|
||||
collectionSlug: collectionConfig?.slug,
|
||||
@@ -158,17 +158,6 @@ export const DefaultEditView: React.FC = () => {
|
||||
}`}
|
||||
type="withoutNav"
|
||||
/>
|
||||
{/* <Meta
|
||||
description={`${isEditing ? t('general:editing') : t('general:creating')} - ${getTranslation(
|
||||
collection.labels.singular,
|
||||
i18n,
|
||||
)}`}
|
||||
keywords={`${getTranslation(collection.labels.singular, i18n)}, Payload, CMS`}
|
||||
title={`${isEditing ? t('general:editing') : t('general:creating')} - ${getTranslation(
|
||||
collection.labels.singular,
|
||||
i18n,
|
||||
)}`}
|
||||
/> */}
|
||||
{BeforeDocument}
|
||||
{preventLeaveWithoutSaving && <LeaveWithoutSaving />}
|
||||
<SetStepNav
|
||||
|
||||
@@ -16,9 +16,11 @@ import { useCallback } from 'react'
|
||||
export const EditViewClient: React.FC<EditViewProps> = () => {
|
||||
const { id, collectionSlug, getDocPermissions, getVersions, globalSlug, setDocumentInfo } =
|
||||
useDocumentInfo()
|
||||
|
||||
const {
|
||||
routes: { admin: adminRoute },
|
||||
} = useConfig()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const { getComponentMap } = useComponentMap()
|
||||
@@ -32,8 +34,8 @@ export const EditViewClient: React.FC<EditViewProps> = () => {
|
||||
|
||||
const onSave = useCallback(
|
||||
async (json: { doc }) => {
|
||||
getVersions()
|
||||
getDocPermissions()
|
||||
void getVersions()
|
||||
void getDocPermissions()
|
||||
|
||||
if (!isEditing) {
|
||||
router.push(`${adminRoute}/collections/${collectionSlug}/${json?.doc?.id}`)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -65,8 +65,7 @@
|
||||
"probe-image-size": "6.0.0",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"scheduler": "0.23.0",
|
||||
"scmp": "2.1.0",
|
||||
"sharp": "0.32.6"
|
||||
"scmp": "2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@monaco-editor/react": "4.5.1",
|
||||
@@ -113,7 +112,8 @@
|
||||
"release-it": "17.1.1",
|
||||
"rimraf": "3.0.2",
|
||||
"serve-static": "1.15.0",
|
||||
"ts-essentials": "7.0.3"
|
||||
"ts-essentials": "7.0.3",
|
||||
"sharp": "0.32.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
|
||||
@@ -125,6 +125,7 @@ export const createClientConfig = async (
|
||||
delete clientConfig.db
|
||||
delete clientConfig.editor
|
||||
delete clientConfig.plugins
|
||||
delete clientConfig.sharp
|
||||
|
||||
'localization' in clientConfig &&
|
||||
clientConfig.localization &&
|
||||
|
||||
@@ -177,6 +177,7 @@ export default joi.object({
|
||||
|
||||
return value
|
||||
}),
|
||||
sharp: joi.any(),
|
||||
telemetry: joi.boolean(),
|
||||
typescript: joi.object({
|
||||
declare: joi.boolean(),
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { Transporter } from 'nodemailer'
|
||||
import type SMTPConnection from 'nodemailer/lib/smtp-connection'
|
||||
import type { DestinationStream, LoggerOptions } from 'pino'
|
||||
import type React from 'react'
|
||||
import type { default as sharp } from 'sharp'
|
||||
import type { DeepRequired } from 'ts-essentials'
|
||||
|
||||
import type { Payload } from '..'
|
||||
@@ -359,6 +360,23 @@ export type LocalizationConfig = Prettify<
|
||||
LocalizationConfigWithLabels | LocalizationConfigWithNoLabels
|
||||
>
|
||||
|
||||
export type SharpDependency = (
|
||||
input?:
|
||||
| ArrayBuffer
|
||||
| Buffer
|
||||
| Float32Array
|
||||
| Float64Array
|
||||
| Int8Array
|
||||
| Int16Array
|
||||
| Int32Array
|
||||
| Uint8Array
|
||||
| Uint8ClampedArray
|
||||
| Uint16Array
|
||||
| Uint32Array
|
||||
| string,
|
||||
options?: sharp.SharpOptions,
|
||||
) => sharp.Sharp
|
||||
|
||||
/**
|
||||
* This is the central configuration
|
||||
*
|
||||
@@ -635,6 +653,11 @@ export type Config = {
|
||||
* @see https://payloadcms.com/docs/configuration/overview#options
|
||||
*/
|
||||
serverURL?: string
|
||||
/**
|
||||
* Pass in a local copy of Sharp if you'd like to use it.
|
||||
*
|
||||
*/
|
||||
sharp?: SharpDependency
|
||||
/** Send anonymous telemetry data about general usage. */
|
||||
telemetry?: boolean
|
||||
/** Control how typescript interfaces are generated from your collections. */
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import sharp from 'sharp'
|
||||
|
||||
export const percentToPixel = (value, dimension) => {
|
||||
return Math.floor((parseFloat(value) / 100) * dimension)
|
||||
}
|
||||
|
||||
export default async function cropImage({ cropData, dimensions, file }) {
|
||||
export default async function cropImage({ cropData, dimensions, file, sharp }) {
|
||||
try {
|
||||
const { height, width, x, y } = cropData
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { fromBuffer } from 'file-type'
|
||||
import fs from 'fs'
|
||||
import mkdirp from 'mkdirp'
|
||||
import sanitize from 'sanitize-filename'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import type { Collection } from '../collections/config/types'
|
||||
import type { SanitizedConfig } from '../config/types'
|
||||
@@ -49,6 +48,8 @@ export const generateFileData = async <T>({
|
||||
}
|
||||
}
|
||||
|
||||
const { sharp } = req.payload.config
|
||||
|
||||
let file = req.file
|
||||
|
||||
const { searchParams } = req
|
||||
@@ -113,7 +114,7 @@ export const generateFileData = async <T>({
|
||||
|
||||
if (fileIsAnimated) sharpOptions.animated = true
|
||||
|
||||
if (fileHasAdjustments) {
|
||||
if (fileHasAdjustments && sharp) {
|
||||
if (file.tempFilePath) {
|
||||
sharpFile = sharp(file.tempFilePath, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081
|
||||
} else {
|
||||
@@ -180,8 +181,8 @@ export const generateFileData = async <T>({
|
||||
fileData.filename = fsSafeName
|
||||
let fileForResize = file
|
||||
|
||||
if (cropData) {
|
||||
const { data: croppedImage, info } = await cropImage({ cropData, dimensions, file })
|
||||
if (cropData && sharp) {
|
||||
const { data: croppedImage, info } = await cropImage({ cropData, dimensions, file, sharp })
|
||||
|
||||
filesToSave.push({
|
||||
buffer: croppedImage,
|
||||
@@ -223,7 +224,7 @@ export const generateFileData = async <T>({
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(imageSizes) && fileSupportsResize) {
|
||||
if (Array.isArray(imageSizes) && fileSupportsResize && sharp) {
|
||||
req.payloadUploadSizes = {}
|
||||
const { sizeData, sizesToSave } = await resizeAndTransformImageSizes({
|
||||
config: collectionConfig,
|
||||
@@ -238,6 +239,7 @@ export const generateFileData = async <T>({
|
||||
mimeType: fileData.mimeType,
|
||||
req,
|
||||
savedFilename: fsSafeName || file.name,
|
||||
sharp,
|
||||
staticPath,
|
||||
})
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { OutputInfo } from 'sharp'
|
||||
import type { OutputInfo, default as Sharp } from 'sharp'
|
||||
import type sharp from 'sharp'
|
||||
|
||||
import { fromBuffer } from 'file-type'
|
||||
import fs from 'fs'
|
||||
import sanitize from 'sanitize-filename'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import type { SanitizedCollectionConfig } from '../collections/config/types'
|
||||
import type { SharpDependency } from '../exports/config'
|
||||
import type { UploadEdits } from '../exports/types'
|
||||
import type { CustomPayloadRequest, PayloadRequest } from '../types'
|
||||
import type { FileSize, FileSizes, FileToSave, ImageSize, ProbedImageSize } from './types'
|
||||
@@ -24,6 +25,7 @@ type ResizeArgs = {
|
||||
}
|
||||
}
|
||||
savedFilename: string
|
||||
sharp: SharpDependency
|
||||
staticPath: string
|
||||
}
|
||||
|
||||
@@ -213,6 +215,7 @@ export default async function resizeAndTransformImageSizes({
|
||||
mimeType,
|
||||
req,
|
||||
savedFilename,
|
||||
sharp,
|
||||
staticPath,
|
||||
}: ResizeArgs): Promise<ImageSizesResult> {
|
||||
const { imageSizes } = config.upload
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud-storage",
|
||||
"description": "The official cloud storage plugin for Payload CMS",
|
||||
"version": "1.1.2",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud",
|
||||
"description": "The official Payload Cloud plugin",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"license": "MIT",
|
||||
@@ -10,7 +10,7 @@
|
||||
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
|
||||
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
||||
"clean": "rimraf {dist,*.tsbuildinfo} && rimraf dev/yarn.lock",
|
||||
"prepublishOnly": "pnpm clean && pnpm turbo build && pnpm test",
|
||||
"prepublishOnly": "pnpm clean && pnpm turbo build",
|
||||
"test": "jest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-seo",
|
||||
"version": "2.2.1",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"homepage:": "https://payloadcms.com",
|
||||
"repository": "git@github.com:payloadcms/plugin-seo.git",
|
||||
"description": "SEO plugin for Payload",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import type { FieldType, Options } from '@payloadcms/ui'
|
||||
import type { TextareaField } from 'payload/types'
|
||||
import type { FieldType, FormFieldBase, Options } from '@payloadcms/ui'
|
||||
|
||||
import { useFieldPath } from '@payloadcms/ui'
|
||||
import { useTranslation } from '@payloadcms/ui'
|
||||
@@ -9,7 +8,7 @@ import { TextareaInput } from '@payloadcms/ui'
|
||||
import { useAllFormFields, useDocumentInfo, useField, useLocale } from '@payloadcms/ui'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
import type { PluginConfig } from '../types'
|
||||
import type { GenerateDescription } from '../types'
|
||||
|
||||
import { defaults } from '../defaults'
|
||||
import { LengthIndicator } from '../ui/LengthIndicator'
|
||||
@@ -17,13 +16,13 @@ import { LengthIndicator } from '../ui/LengthIndicator'
|
||||
const { maxLength, minLength } = defaults.description
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
type MetaDescriptionProps = TextareaField & {
|
||||
type MetaDescriptionProps = FormFieldBase & {
|
||||
hasGenerateDescriptionFn: boolean
|
||||
path: string
|
||||
pluginConfig: PluginConfig
|
||||
}
|
||||
|
||||
export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
|
||||
const { name, label, path, pluginConfig, required } = props
|
||||
const { Label, hasGenerateDescriptionFn, path, required } = props
|
||||
const { path: pathFromContext, schemaPath } = useFieldPath()
|
||||
|
||||
const { t } = useTranslation()
|
||||
@@ -33,27 +32,31 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
|
||||
const docInfo = useDocumentInfo()
|
||||
|
||||
const field: FieldType<string> = useField({
|
||||
name,
|
||||
label,
|
||||
path,
|
||||
} as Options)
|
||||
|
||||
const { errorMessage, setValue, showError, value } = field
|
||||
|
||||
const regenerateDescription = useCallback(async () => {
|
||||
/*const { generateDescription } = pluginConfig
|
||||
let generatedDescription
|
||||
if (!hasGenerateDescriptionFn) return
|
||||
|
||||
if (typeof generateDescription === 'function') {
|
||||
generatedDescription = await generateDescription({
|
||||
const genDescriptionResponse = await fetch('/api/plugin-seo/generate-description', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...fields },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
})
|
||||
}
|
||||
} satisfies Parameters<GenerateDescription>[0]),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
setValue(generatedDescription)*/
|
||||
}, [fields, setValue, pluginConfig, locale, docInfo])
|
||||
const { result: generatedDescription } = await genDescriptionResponse.json()
|
||||
|
||||
setValue(generatedDescription || '')
|
||||
}, [fields, setValue, hasGenerateDescriptionFn, locale, docInfo])
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -67,8 +70,8 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
{label && typeof label === 'string' && label}
|
||||
<div className="plugin-seo__field">
|
||||
{Label}
|
||||
|
||||
{required && (
|
||||
<span
|
||||
@@ -81,7 +84,7 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
|
||||
</span>
|
||||
)}
|
||||
|
||||
{typeof pluginConfig?.generateDescription === 'function' && (
|
||||
{hasGenerateDescriptionFn && (
|
||||
<React.Fragment>
|
||||
—
|
||||
<button
|
||||
@@ -126,7 +129,7 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
|
||||
<TextareaInput
|
||||
Error={errorMessage} // TODO: Fix
|
||||
onChange={setValue}
|
||||
path={name || pathFromContext}
|
||||
path={pathFromContext}
|
||||
required={required}
|
||||
showError={showError}
|
||||
style={{
|
||||
@@ -147,7 +150,3 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const getMetaDescriptionField = (props: MetaDescriptionProps) => (
|
||||
<MetaDescription {...props} />
|
||||
)
|
||||
|
||||
@@ -13,18 +13,17 @@ import {
|
||||
} from '@payloadcms/ui'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
import type { PluginConfig } from '../types'
|
||||
import type { GenerateImage } from '../types'
|
||||
|
||||
import { Pill } from '../ui/Pill'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
type MetaImageProps = UploadInputProps & {
|
||||
path: string
|
||||
pluginConfig: PluginConfig
|
||||
hasGenerateImageFn: boolean
|
||||
}
|
||||
|
||||
export const MetaImage: React.FC<MetaImageProps> = (props) => {
|
||||
const { label, pluginConfig, relationTo, required } = props || {}
|
||||
const { Label, hasGenerateImageFn, path, relationTo, required } = props || {}
|
||||
|
||||
const field: FieldType<string> = useField(props as Options)
|
||||
|
||||
@@ -37,19 +36,25 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
|
||||
const { errorMessage, setValue, showError, value } = field
|
||||
|
||||
const regenerateImage = useCallback(async () => {
|
||||
/*const { generateImage } = pluginConfig
|
||||
let generatedImage
|
||||
if (!hasGenerateImageFn) return
|
||||
|
||||
if (typeof generateImage === 'function') {
|
||||
generatedImage = await generateImage({
|
||||
const genImageResponse = await fetch('/api/plugin-seo/generate-image', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...fields },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
})
|
||||
}
|
||||
} satisfies Parameters<GenerateImage>[0]),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
setValue(generatedImage)*/
|
||||
}, [fields, setValue, pluginConfig, locale, docInfo])
|
||||
const { result: generatedImage } = await genImageResponse.json()
|
||||
|
||||
setValue(generatedImage || '')
|
||||
}, [fields, setValue, hasGenerateImageFn, locale, docInfo])
|
||||
|
||||
const hasImage = Boolean(value)
|
||||
|
||||
@@ -71,8 +76,8 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
{label && typeof label === 'string' && label}
|
||||
<div className="plugin-seo__field">
|
||||
{Label}
|
||||
|
||||
{required && (
|
||||
<span
|
||||
@@ -85,7 +90,7 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
|
||||
</span>
|
||||
)}
|
||||
|
||||
{typeof pluginConfig?.generateImage === 'function' && (
|
||||
{hasGenerateImageFn && (
|
||||
<React.Fragment>
|
||||
—
|
||||
<button
|
||||
@@ -106,7 +111,7 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
{typeof pluginConfig?.generateImage === 'function' && (
|
||||
{hasGenerateImageFn && (
|
||||
<div
|
||||
style={{
|
||||
color: '#9A9A9A',
|
||||
@@ -162,5 +167,3 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const getMetaImageField = (props: MetaImageProps) => <MetaImage {...props} />
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import type { FieldType, Options } from '@payloadcms/ui'
|
||||
import type { TextField as TextFieldType } from 'payload/types'
|
||||
import type { FieldType, FormFieldBase, Options } from '@payloadcms/ui'
|
||||
|
||||
import { useFieldPath } from '@payloadcms/ui'
|
||||
import {
|
||||
@@ -14,29 +13,26 @@ import {
|
||||
} from '@payloadcms/ui'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
import type { PluginConfig } from '../types'
|
||||
import type { GenerateTitle } from '../types'
|
||||
|
||||
import { defaults } from '../defaults'
|
||||
import { LengthIndicator } from '../ui/LengthIndicator'
|
||||
import './index.scss'
|
||||
|
||||
const { maxLength, minLength } = defaults.title
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
type MetaTitleProps = TextFieldType & {
|
||||
path: string
|
||||
pluginConfig: PluginConfig
|
||||
type MetaTitleProps = FormFieldBase & {
|
||||
hasGenerateTitleFn: boolean
|
||||
}
|
||||
|
||||
export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
|
||||
const { name, label, path, pluginConfig, required } = props || {}
|
||||
console.log('props tit', props)
|
||||
const { Label, hasGenerateTitleFn, path, required } = props || {}
|
||||
const { path: pathFromContext, schemaPath } = useFieldPath()
|
||||
|
||||
const { t } = useTranslation()
|
||||
|
||||
const field: FieldType<string> = useField({
|
||||
name,
|
||||
label,
|
||||
path,
|
||||
} as Options)
|
||||
|
||||
@@ -47,19 +43,25 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
|
||||
const { errorMessage, setValue, showError, value } = field
|
||||
|
||||
const regenerateTitle = useCallback(async () => {
|
||||
/* const { generateTitle } = pluginConfig
|
||||
let generatedTitle
|
||||
if (!hasGenerateTitleFn) return
|
||||
|
||||
if (typeof generateTitle === 'function') {
|
||||
generatedTitle = await generateTitle({
|
||||
const genTitleResponse = await fetch('/api/plugin-seo/generate-title', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...fields },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
})
|
||||
}
|
||||
} satisfies Parameters<GenerateTitle>[0]),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
setValue(generatedTitle)*/
|
||||
}, [fields, setValue, pluginConfig, locale, docInfo])
|
||||
const { result: generatedTitle } = await genTitleResponse.json()
|
||||
|
||||
setValue(generatedTitle || '')
|
||||
}, [fields, setValue, hasGenerateTitleFn, locale, docInfo])
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -73,8 +75,8 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
{label && typeof label === 'string' && label}
|
||||
<div className="plugin-seo__field">
|
||||
{Label}
|
||||
|
||||
{required && (
|
||||
<span
|
||||
@@ -87,7 +89,7 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
|
||||
</span>
|
||||
)}
|
||||
|
||||
{typeof pluginConfig?.generateTitle === 'function' && (
|
||||
{hasGenerateTitleFn && (
|
||||
<React.Fragment>
|
||||
—
|
||||
<button
|
||||
@@ -133,7 +135,7 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
|
||||
<TextInput
|
||||
Error={errorMessage} // TODO: fix errormessage
|
||||
onChange={setValue}
|
||||
path={name || pathFromContext}
|
||||
path={pathFromContext}
|
||||
required={required}
|
||||
showError={showError}
|
||||
style={{
|
||||
@@ -154,5 +156,3 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const getMetaTitleField = (props: MetaTitleProps) => <MetaTitle {...props} />
|
||||
|
||||
5
packages/plugin-seo/src/fields/index.scss
Normal file
5
packages/plugin-seo/src/fields/index.scss
Normal file
@@ -0,0 +1,5 @@
|
||||
.plugin-seo__field {
|
||||
.field-label {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,20 @@ import type { Field, GroupField, TabsField, TextField } from 'payload/types'
|
||||
import { deepMerge } from 'payload/utilities'
|
||||
import React from 'react'
|
||||
|
||||
import type { PluginConfig } from './types'
|
||||
import type {
|
||||
GenerateDescription,
|
||||
GenerateImage,
|
||||
GenerateTitle,
|
||||
GenerateURL,
|
||||
PluginConfig,
|
||||
} from './types'
|
||||
|
||||
import { MetaDescription, getMetaDescriptionField } from './fields/MetaDescription'
|
||||
import { MetaImage, getMetaImageField } from './fields/MetaImage'
|
||||
import { MetaTitle, getMetaTitleField } from './fields/MetaTitle'
|
||||
import { MetaDescription } from './fields/MetaDescription'
|
||||
import { MetaImage } from './fields/MetaImage'
|
||||
import { MetaTitle } from './fields/MetaTitle'
|
||||
import translations from './translations'
|
||||
import { Overview } from './ui/Overview'
|
||||
import { Preview, getPreviewField } from './ui/Preview'
|
||||
import { Preview } from './ui/Preview'
|
||||
|
||||
const seo =
|
||||
(pluginConfig: PluginConfig) =>
|
||||
@@ -36,22 +42,30 @@ const seo =
|
||||
type: 'text',
|
||||
admin: {
|
||||
components: {
|
||||
Field: (props) => {
|
||||
return <MetaTitle {...props} />
|
||||
},
|
||||
Field: (props) => (
|
||||
<MetaTitle
|
||||
{...props}
|
||||
hasGenerateTitleFn={typeof pluginConfig.generateTitle === 'function'}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
localized: true,
|
||||
...((pluginConfig?.fieldOverrides?.title as TextField) ?? {}),
|
||||
...((pluginConfig?.fieldOverrides?.title as unknown as TextField) ?? {}),
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
admin: {
|
||||
components: {
|
||||
Field: (props) => {
|
||||
return <MetaDescription {...props} />
|
||||
},
|
||||
Field: (props) => (
|
||||
<MetaDescription
|
||||
{...props}
|
||||
hasGenerateDescriptionFn={
|
||||
typeof pluginConfig.generateDescription === 'function'
|
||||
}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
localized: true,
|
||||
@@ -65,9 +79,12 @@ const seo =
|
||||
type: 'upload',
|
||||
admin: {
|
||||
components: {
|
||||
Field: (props) => {
|
||||
return <MetaImage {...props} />
|
||||
},
|
||||
Field: (props) => (
|
||||
<MetaImage
|
||||
{...props}
|
||||
hasGenerateImageFn={typeof pluginConfig.generateImage === 'function'}
|
||||
/>
|
||||
),
|
||||
},
|
||||
description:
|
||||
'Maximum upload file size: 12MB. Recommended file size for images is <500KB.',
|
||||
@@ -85,9 +102,12 @@ const seo =
|
||||
type: 'ui',
|
||||
admin: {
|
||||
components: {
|
||||
Field: (props) => {
|
||||
return <Preview {...props} />
|
||||
},
|
||||
Field: (props) => (
|
||||
<Preview
|
||||
{...props}
|
||||
hasGenerateURLFn={typeof pluginConfig.generateURL === 'function'}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
label: 'Preview',
|
||||
@@ -159,6 +179,48 @@ const seo =
|
||||
|
||||
return collection
|
||||
}) || [],
|
||||
endpoints: [
|
||||
{
|
||||
handler: async (req) => {
|
||||
const args: Parameters<GenerateTitle>[0] =
|
||||
req.data as unknown as Parameters<GenerateTitle>[0]
|
||||
const result = await pluginConfig.generateTitle(args)
|
||||
return new Response(JSON.stringify({ result }), { status: 200 })
|
||||
},
|
||||
method: 'post',
|
||||
path: '/plugin-seo/generate-title',
|
||||
},
|
||||
{
|
||||
handler: async (req) => {
|
||||
const args: Parameters<GenerateDescription>[0] =
|
||||
req.data as unknown as Parameters<GenerateDescription>[0]
|
||||
const result = await pluginConfig.generateDescription(args)
|
||||
return new Response(JSON.stringify({ result }), { status: 200 })
|
||||
},
|
||||
method: 'post',
|
||||
path: '/plugin-seo/generate-description',
|
||||
},
|
||||
{
|
||||
handler: async (req) => {
|
||||
const args: Parameters<GenerateURL>[0] =
|
||||
req.data as unknown as Parameters<GenerateURL>[0]
|
||||
const result = await pluginConfig.generateURL(args)
|
||||
return new Response(JSON.stringify({ result }), { status: 200 })
|
||||
},
|
||||
method: 'post',
|
||||
path: '/plugin-seo/generate-url',
|
||||
},
|
||||
{
|
||||
handler: async (req) => {
|
||||
const args: Parameters<GenerateImage>[0] =
|
||||
req.data as unknown as Parameters<GenerateImage>[0]
|
||||
const result = await pluginConfig.generateImage(args)
|
||||
return new Response(result, { status: 200 })
|
||||
},
|
||||
method: 'post',
|
||||
path: '/plugin-seo/generate-image',
|
||||
},
|
||||
],
|
||||
globals:
|
||||
config.globals?.map((global) => {
|
||||
const { slug } = global
|
||||
|
||||
@@ -5,16 +5,14 @@ import type { FormField, UIField } from 'payload/types'
|
||||
import { useAllFormFields, useDocumentInfo, useLocale, useTranslation } from '@payloadcms/ui'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
import type { PluginConfig } from '../types'
|
||||
import type { GenerateURL } from '../types'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
type PreviewProps = UIField & {
|
||||
pluginConfig: PluginConfig
|
||||
hasGenerateURLFn: boolean
|
||||
}
|
||||
|
||||
export const Preview: React.FC<PreviewProps> = (props) => {
|
||||
const { pluginConfig: { generateURL } = {} } = props || {}
|
||||
|
||||
export const Preview: React.FC<PreviewProps> = ({ hasGenerateURLFn }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const locale = useLocale()
|
||||
@@ -29,20 +27,29 @@ export const Preview: React.FC<PreviewProps> = (props) => {
|
||||
const [href, setHref] = useState<string>()
|
||||
|
||||
useEffect(() => {
|
||||
/* const getHref = async () => {
|
||||
if (typeof generateURL === 'function' && !href) {
|
||||
const newHref = await generateURL({
|
||||
const getHref = async () => {
|
||||
const genURLResponse = await fetch('/api/plugin-seo/generate-url', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...fields },
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
})
|
||||
} satisfies Parameters<GenerateURL>[0]),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
setHref(newHref)
|
||||
}
|
||||
const { result: newHref } = await genURLResponse.json()
|
||||
|
||||
setHref(newHref)
|
||||
}
|
||||
|
||||
getHref() // eslint-disable-line @typescript-eslint/no-floating-promises*/
|
||||
}, [generateURL, fields, href, locale, docInfo])
|
||||
if (hasGenerateURLFn && !href) {
|
||||
void getHref()
|
||||
}
|
||||
}, [fields, href, locale, docInfo, hasGenerateURLFn])
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -101,5 +108,3 @@ export const Preview: React.FC<PreviewProps> = (props) => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const getPreviewField = (props: PreviewProps) => <Preview {...props} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-lexical",
|
||||
"version": "0.7.0",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -82,7 +82,6 @@ export const getGenerateComponentMap =
|
||||
const mappedFields = mapFields({
|
||||
config,
|
||||
fieldSchema: sanitizedFields,
|
||||
operation: 'update',
|
||||
permissions: {},
|
||||
readOnly: false,
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-slate",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"description": "The officially supported Slate richtext adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -70,7 +70,7 @@ export const getGenerateComponentMap =
|
||||
switch (element.name) {
|
||||
case 'link': {
|
||||
const linkFields = sanitizeFields({
|
||||
config: config,
|
||||
config,
|
||||
fields: transformExtraFields(args.admin?.link?.fields, config, i18n),
|
||||
validRelationships,
|
||||
})
|
||||
@@ -78,7 +78,6 @@ export const getGenerateComponentMap =
|
||||
const mappedFields = mapFields({
|
||||
config,
|
||||
fieldSchema: linkFields,
|
||||
operation: 'update',
|
||||
permissions: {},
|
||||
readOnly: false,
|
||||
})
|
||||
@@ -110,7 +109,6 @@ export const getGenerateComponentMap =
|
||||
const mappedFields = mapFields({
|
||||
config,
|
||||
fieldSchema: uploadFields,
|
||||
operation: 'update',
|
||||
permissions: {},
|
||||
readOnly: false,
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/translations",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"main": "./dist/exports/index.ts",
|
||||
"types": "./dist/types.d.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -79,7 +79,8 @@ const replaceVars = ({
|
||||
.map((part) => {
|
||||
if (part.startsWith('{{') && part.endsWith('}}')) {
|
||||
const placeholder = part.substring(2, part.length - 2).trim()
|
||||
return vars[placeholder] || part
|
||||
const value = vars[placeholder]
|
||||
return value !== undefined && value !== null ? value : part
|
||||
} else {
|
||||
return part
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "commonjs"
|
||||
"type": "es6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/ui",
|
||||
"version": "3.0.0-alpha.14",
|
||||
"version": "3.0.0-alpha.18",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import type { Description } from 'payload/types'
|
||||
import type { Description, Operation } from 'payload/types'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
@import '../../scss/styles.scss';
|
||||
|
||||
.field-description {
|
||||
display: flex;
|
||||
color: var(--theme-elevation-400);
|
||||
margin-top: calc(var(--base) / 4);
|
||||
|
||||
&--margin-bottom {
|
||||
margin-top: 0;
|
||||
margin-bottom: calc(var(--base) / 2);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ type FieldPathContextType = {
|
||||
path: string
|
||||
schemaPath: string
|
||||
}
|
||||
|
||||
const FieldPathContext = React.createContext<FieldPathContextType>({
|
||||
path: '',
|
||||
schemaPath: '',
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
export type Props = {
|
||||
className?: string
|
||||
description?: string
|
||||
marginPlacement?: 'bottom' | 'top'
|
||||
value?: unknown
|
||||
}
|
||||
@@ -556,7 +556,7 @@ const Form: React.FC<Props> = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
executeOnChange() // eslint-disable-line @typescript-eslint/no-floating-promises
|
||||
void executeOnChange() // eslint-disable-line @typescript-eslint/no-floating-promises
|
||||
},
|
||||
150,
|
||||
[fields, dispatchFields, onChange],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
|
||||
import { Banner } from '../../elements/Banner'
|
||||
@@ -13,6 +14,7 @@ type NullifyLocaleFieldProps = {
|
||||
localized: boolean
|
||||
path: string
|
||||
}
|
||||
|
||||
export const NullifyLocaleField: React.FC<NullifyLocaleFieldProps> = ({
|
||||
fieldValue,
|
||||
localized,
|
||||
@@ -30,8 +32,8 @@ export const NullifyLocaleField: React.FC<NullifyLocaleFieldProps> = ({
|
||||
const useFallback = !checked
|
||||
|
||||
dispatchFields({
|
||||
path,
|
||||
type: 'UPDATE',
|
||||
path,
|
||||
value: useFallback ? null : fieldValue || 0,
|
||||
})
|
||||
setModified(true)
|
||||
|
||||
18
packages/ui/src/forms/ReadOnlyProvider/index.tsx
Normal file
18
packages/ui/src/forms/ReadOnlyProvider/index.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
|
||||
const ReadOnlyContext = React.createContext<boolean | undefined>(undefined)
|
||||
|
||||
export const ReadOnlyProvider: React.FC<{
|
||||
children: React.ReactNode
|
||||
readOnly?: boolean
|
||||
}> = (props) => {
|
||||
const { children, readOnly } = props
|
||||
|
||||
return <ReadOnlyContext.Provider value={readOnly}>{children}</ReadOnlyContext.Provider>
|
||||
}
|
||||
|
||||
export const useReadOnly = () => {
|
||||
const path = React.useContext(ReadOnlyContext)
|
||||
return path
|
||||
}
|
||||
@@ -1,20 +1,45 @@
|
||||
'use client'
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import { useOperation } from '../../providers/OperationProvider'
|
||||
import { FieldPathProvider, useFieldPath } from '../FieldPathProvider'
|
||||
import { ReadOnlyProvider, useReadOnly } from '../ReadOnlyProvider'
|
||||
|
||||
export const RenderField: React.FC<{
|
||||
Field: React.ReactNode
|
||||
fieldPermissions: FieldPermissions
|
||||
name?: string
|
||||
readOnly?: boolean
|
||||
}> = (props) => {
|
||||
const { name, Field } = props
|
||||
const { name, Field, fieldPermissions, readOnly: readOnlyFromProps } = props
|
||||
|
||||
const { path: pathFromContext, schemaPath: schemaPathFromContext } = useFieldPath()
|
||||
|
||||
const readOnlyFromContext = useReadOnly()
|
||||
|
||||
const operation = useOperation()
|
||||
|
||||
const path = `${pathFromContext ? `${pathFromContext}.` : ''}${name || ''}`
|
||||
const schemaPath = `${schemaPathFromContext ? `${schemaPathFromContext}.` : ''}${name || ''}`
|
||||
|
||||
// `admin.readOnly` displays the value but prevents the field from being edited
|
||||
let readOnly = readOnlyFromProps
|
||||
|
||||
// if parent field is `readOnly: true`, but this field is `readOnly: false`, the field should still be editable
|
||||
if (readOnlyFromContext && readOnly !== false) readOnly = true
|
||||
|
||||
// if the user does not have access control to begin with, force it to be read-only
|
||||
if (fieldPermissions?.[operation]?.permission === false) {
|
||||
readOnly = true
|
||||
}
|
||||
|
||||
return (
|
||||
<FieldPathProvider path={path} schemaPath={schemaPath}>
|
||||
{Field}
|
||||
</FieldPathProvider>
|
||||
<ReadOnlyProvider readOnly={readOnly}>
|
||||
<FieldPathProvider path={path} schemaPath={schemaPath}>
|
||||
{Field}
|
||||
</FieldPathProvider>
|
||||
</ReadOnlyProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -53,8 +53,14 @@ const RenderFields: React.FC<Props> = (props) => {
|
||||
ref={intersectionRef}
|
||||
>
|
||||
{hasRendered &&
|
||||
fieldMap?.map(({ name, Field }, fieldIndex) => (
|
||||
<RenderField Field={Field} key={fieldIndex} name={name} />
|
||||
fieldMap?.map(({ name, Field, fieldPermissions, readOnly }, fieldIndex) => (
|
||||
<RenderField
|
||||
Field={Field}
|
||||
fieldPermissions={fieldPermissions}
|
||||
key={fieldIndex}
|
||||
name={name}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { Operation } from 'payload/types'
|
||||
|
||||
import type { FieldMap } from '../../utilities/buildComponentMap/types'
|
||||
|
||||
export type Props = {
|
||||
@@ -5,4 +7,5 @@ export type Props = {
|
||||
fieldMap: FieldMap
|
||||
forceRender?: boolean
|
||||
margins?: 'small' | false
|
||||
operation?: Operation
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
import type { ArrayField, Row, RowLabel as RowLabelType } from 'payload/types'
|
||||
import type { ArrayField, Operation, Row, RowLabel as RowLabelType } from 'payload/types'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import React from 'react'
|
||||
|
||||
@@ -105,10 +105,10 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
const addRow = useCallback(
|
||||
async (rowIndex: number, blockType: string) => {
|
||||
dispatchFields({
|
||||
type: 'ADD_ROW',
|
||||
blockType,
|
||||
path,
|
||||
rowIndex,
|
||||
type: 'ADD_ROW',
|
||||
})
|
||||
|
||||
setModified(true)
|
||||
@@ -117,12 +117,12 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
scrollToID(`${path}-row-${rowIndex + 1}`)
|
||||
}, 0)
|
||||
},
|
||||
[path, setModified],
|
||||
[path, setModified, dispatchFields],
|
||||
)
|
||||
|
||||
const duplicateRow = useCallback(
|
||||
(rowIndex: number) => {
|
||||
dispatchFields({ path, rowIndex, type: 'DUPLICATE_ROW' })
|
||||
dispatchFields({ type: 'DUPLICATE_ROW', path, rowIndex })
|
||||
setModified(true)
|
||||
|
||||
setTimeout(() => {
|
||||
@@ -135,9 +135,9 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
const removeRow = useCallback(
|
||||
(rowIndex: number) => {
|
||||
dispatchFields({
|
||||
type: 'REMOVE_ROW',
|
||||
path,
|
||||
rowIndex,
|
||||
type: 'REMOVE_ROW',
|
||||
})
|
||||
|
||||
setModified(true)
|
||||
@@ -147,7 +147,7 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
|
||||
const moveRow = useCallback(
|
||||
(moveFromIndex: number, moveToIndex: number) => {
|
||||
dispatchFields({ moveFromIndex, moveToIndex, path, type: 'MOVE_ROW' })
|
||||
dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path })
|
||||
setModified(true)
|
||||
},
|
||||
[dispatchFields, path, setModified],
|
||||
@@ -155,14 +155,14 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
|
||||
const toggleCollapseAll = useCallback(
|
||||
(collapsed: boolean) => {
|
||||
dispatchFields({ collapsed, path, setDocFieldPreferences, type: 'SET_ALL_ROWS_COLLAPSED' })
|
||||
dispatchFields({ type: 'SET_ALL_ROWS_COLLAPSED', collapsed, path, setDocFieldPreferences })
|
||||
},
|
||||
[dispatchFields, path, setDocFieldPreferences],
|
||||
)
|
||||
|
||||
const setCollapse = useCallback(
|
||||
(rowID: string, collapsed: boolean) => {
|
||||
dispatchFields({ collapsed, path, rowID, setDocFieldPreferences, type: 'SET_ROW_COLLAPSED' })
|
||||
dispatchFields({ type: 'SET_ROW_COLLAPSED', collapsed, path, rowID, setDocFieldPreferences })
|
||||
},
|
||||
[dispatchFields, path, setDocFieldPreferences],
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import type { DocumentPreferences } from 'payload/types'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { tabHasName } from 'payload/types'
|
||||
import { toKebabCase } from 'payload/utilities'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import type { Props } from './types'
|
||||
|
||||
import { useConfig } from '../../../providers/Config'
|
||||
import { useLocale } from '../../../providers/Locale'
|
||||
import { useTranslation } from '../../../providers/Translation'
|
||||
import LabelComp from '../../Label'
|
||||
import useField from '../../useField'
|
||||
import { withCondition } from '../../withCondition'
|
||||
@@ -33,10 +32,8 @@ const Text: React.FC<Props> = (props) => {
|
||||
maxRows,
|
||||
minLength,
|
||||
minRows,
|
||||
onKeyDown,
|
||||
path: pathFromProps,
|
||||
placeholder,
|
||||
readOnly,
|
||||
required,
|
||||
rtl,
|
||||
style,
|
||||
@@ -46,8 +43,6 @@ const Text: React.FC<Props> = (props) => {
|
||||
|
||||
const Label = LabelFromProps || <LabelComp label={label} required={required} />
|
||||
|
||||
const { i18n, t } = useTranslation()
|
||||
|
||||
const locale = useLocale()
|
||||
|
||||
const { localization: localizationConfig } = useConfig()
|
||||
@@ -60,7 +55,7 @@ const Text: React.FC<Props> = (props) => {
|
||||
[validate, minLength, maxLength, required],
|
||||
)
|
||||
|
||||
const { path, schemaPath, setValue, showError, value } = useField({
|
||||
const { path, readOnly, setValue, showError, value } = useField({
|
||||
path: pathFromProps || name,
|
||||
validate: memoizedValidate,
|
||||
})
|
||||
|
||||
@@ -31,7 +31,6 @@ const Textarea: React.FC<Props> = (props) => {
|
||||
minLength,
|
||||
path: pathFromProps,
|
||||
placeholder,
|
||||
readOnly,
|
||||
required,
|
||||
rtl,
|
||||
style,
|
||||
@@ -62,7 +61,7 @@ const Textarea: React.FC<Props> = (props) => {
|
||||
[validate, required, maxLength, minLength],
|
||||
)
|
||||
|
||||
const { path, setValue, showError, value } = useField<string>({
|
||||
const { path, readOnly, setValue, showError, value } = useField<string>({
|
||||
path: pathFromProps || name,
|
||||
validate: memoizedValidate,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { User } from 'payload/auth'
|
||||
import type { FieldPermissions, User } from 'payload/auth'
|
||||
import type { Locale, SanitizedLocalizationConfig } from 'payload/config'
|
||||
import type {
|
||||
ArrayField,
|
||||
@@ -33,6 +33,7 @@ export type FormFieldBase = {
|
||||
className?: string
|
||||
docPreferences?: DocumentPreferences
|
||||
fieldMap?: FieldMap
|
||||
fieldPermissions?: FieldPermissions
|
||||
initialSubfieldState?: FormState
|
||||
label?: string
|
||||
locale?: Locale
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useOperation } from '../../providers/OperationProvider'
|
||||
import { useTranslation } from '../../providers/Translation'
|
||||
import { useFieldPath } from '../FieldPathProvider'
|
||||
import { useForm, useFormFields, useFormProcessing, useFormSubmitted } from '../Form/context'
|
||||
import { useReadOnly } from '../ReadOnlyProvider'
|
||||
|
||||
/**
|
||||
* Get and set the value of a form field.
|
||||
@@ -23,6 +24,8 @@ const useField = <T,>(options: Options): FieldType<T> => {
|
||||
|
||||
const { path: pathFromContext, schemaPath } = useFieldPath()
|
||||
|
||||
const readOnly = useReadOnly()
|
||||
|
||||
const path = options.path || pathFromContext
|
||||
|
||||
const submitted = useFormSubmitted()
|
||||
@@ -83,6 +86,7 @@ const useField = <T,>(options: Options): FieldType<T> => {
|
||||
formSubmitted: submitted,
|
||||
initialValue,
|
||||
path,
|
||||
readOnly: readOnly || false,
|
||||
rows: field?.rows,
|
||||
schemaPath,
|
||||
setValue,
|
||||
@@ -102,6 +106,7 @@ const useField = <T,>(options: Options): FieldType<T> => {
|
||||
initialValue,
|
||||
path,
|
||||
schemaPath,
|
||||
readOnly,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ export type FieldType<T> = {
|
||||
formSubmitted: boolean
|
||||
initialValue?: T
|
||||
path: string
|
||||
readOnly?: boolean
|
||||
rows?: Row[]
|
||||
schemaPath: string
|
||||
setValue: (val: unknown, disableModifyingForm?: boolean) => void
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import type { Permissions, User } from 'payload/auth'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useAuth } from '..'
|
||||
|
||||
export const HydrateClientUser: React.FC<{ permissions: Permissions; user: User }> = ({
|
||||
permissions,
|
||||
user,
|
||||
}) => {
|
||||
const { setPermissions, setUser } = useAuth()
|
||||
|
||||
useEffect(() => {
|
||||
setUser(user)
|
||||
setPermissions(permissions)
|
||||
}, [user, permissions, setUser, setPermissions])
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -159,6 +159,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
const params = {
|
||||
locale: code,
|
||||
}
|
||||
|
||||
try {
|
||||
const request = await requests.get(`${serverURL}${api}/access?${qs.stringify(params)}`, {
|
||||
headers: {
|
||||
@@ -256,13 +257,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
setLastLocationChange(Date.now())
|
||||
}, [pathname])
|
||||
|
||||
// When user changes, get new access
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
refreshPermissions()
|
||||
}
|
||||
}, [i18n, id, api, serverURL, refreshPermissions])
|
||||
|
||||
useEffect(() => {
|
||||
let reminder: ReturnType<typeof setTimeout>
|
||||
const now = Math.round(new Date().getTime() / 1000)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
import type { CollectionPermission, GlobalPermission, Permissions } from 'payload/auth'
|
||||
import type { EditViewProps, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import React from 'react'
|
||||
@@ -13,12 +13,7 @@ export const buildComponentMap = (args: {
|
||||
DefaultEditView: React.FC<EditViewProps>
|
||||
DefaultListView: React.FC<EditViewProps>
|
||||
config: SanitizedConfig
|
||||
operation?: 'create' | 'update'
|
||||
permissions?:
|
||||
| {
|
||||
[field: string]: FieldPermissions
|
||||
}
|
||||
| FieldPermissions
|
||||
permissions?: Permissions
|
||||
readOnly?: boolean
|
||||
}): ComponentMap => {
|
||||
const {
|
||||
@@ -26,15 +21,18 @@ export const buildComponentMap = (args: {
|
||||
DefaultEditView,
|
||||
DefaultListView,
|
||||
config,
|
||||
operation = 'update',
|
||||
permissions,
|
||||
readOnly: readOnlyOverride,
|
||||
} = args
|
||||
|
||||
let entityPermissions: CollectionPermission | GlobalPermission
|
||||
|
||||
// Collections
|
||||
const collections = config.collections.reduce((acc, collectionConfig) => {
|
||||
const { slug, fields } = collectionConfig
|
||||
|
||||
entityPermissions = permissions.collections[collectionConfig.slug]
|
||||
|
||||
const editViewFromConfig = collectionConfig?.admin?.components?.views?.Edit
|
||||
const listViewFromConfig = collectionConfig?.admin?.components?.views?.List
|
||||
|
||||
@@ -110,8 +108,7 @@ export const buildComponentMap = (args: {
|
||||
DefaultCell,
|
||||
config,
|
||||
fieldSchema: fields,
|
||||
operation,
|
||||
permissions,
|
||||
permissions: entityPermissions.fields,
|
||||
readOnly: readOnlyOverride,
|
||||
}),
|
||||
}
|
||||
@@ -126,6 +123,8 @@ export const buildComponentMap = (args: {
|
||||
const globals = config.globals.reduce((acc, globalConfig) => {
|
||||
const { slug, fields } = globalConfig
|
||||
|
||||
entityPermissions = permissions.globals[globalConfig.slug]
|
||||
|
||||
const editViewFromConfig = globalConfig?.admin?.components?.views?.Edit
|
||||
|
||||
const CustomEditView =
|
||||
@@ -150,8 +149,7 @@ export const buildComponentMap = (args: {
|
||||
DefaultCell,
|
||||
config,
|
||||
fieldSchema: fields,
|
||||
operation,
|
||||
permissions,
|
||||
permissions: entityPermissions.fields,
|
||||
readOnly: readOnlyOverride,
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { FieldPermissions } from 'payload/auth'
|
||||
import type { CollectionPermission, FieldPermissions, GlobalPermission } from 'payload/auth'
|
||||
import type { CellProps, Field, FieldWithPath, LabelProps, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { fieldAffectsData, fieldIsPresentationalOnly } from 'payload/types'
|
||||
@@ -21,13 +21,8 @@ export const mapFields = (args: {
|
||||
config: SanitizedConfig
|
||||
fieldSchema: FieldWithPath[]
|
||||
filter?: (field: Field) => boolean
|
||||
operation?: 'create' | 'update'
|
||||
parentPath?: string
|
||||
permissions?:
|
||||
| {
|
||||
[field: string]: FieldPermissions
|
||||
}
|
||||
| FieldPermissions
|
||||
permissions?: CollectionPermission['fields'] | GlobalPermission['fields']
|
||||
readOnly?: boolean
|
||||
}): FieldMap => {
|
||||
const {
|
||||
@@ -35,7 +30,6 @@ export const mapFields = (args: {
|
||||
config,
|
||||
fieldSchema,
|
||||
filter,
|
||||
operation = 'update',
|
||||
parentPath,
|
||||
permissions,
|
||||
readOnly: readOnlyOverride,
|
||||
@@ -57,26 +51,14 @@ export const mapFields = (args: {
|
||||
field.path || (isFieldAffectingData && 'name' in field ? field.name : '')
|
||||
}`
|
||||
|
||||
const fieldPermissions = isFieldAffectingData ? permissions?.[field.name] : permissions
|
||||
const fieldPermissions = isFieldAffectingData ? permissions?.[field.name] : undefined
|
||||
|
||||
// if the user cannot read the field, then filter it out
|
||||
// this is different from `admin.readOnly` which is executed on the client based on `operation`
|
||||
if (fieldPermissions?.read?.permission === false) {
|
||||
return acc
|
||||
}
|
||||
|
||||
// readOnly from field config
|
||||
let readOnly = field.admin && 'readOnly' in field.admin ? field.admin.readOnly : undefined
|
||||
|
||||
// if parent field is readOnly
|
||||
// but this field is `readOnly: false`
|
||||
// the field should be editable
|
||||
if (readOnlyOverride && readOnly !== false) readOnly = true
|
||||
|
||||
// unless the user does not pass access control
|
||||
if (fieldPermissions?.[operation]?.permission === false) {
|
||||
readOnly = true
|
||||
}
|
||||
|
||||
const labelProps: LabelProps = {
|
||||
htmlFor: 'TODO',
|
||||
// TODO: fix types
|
||||
@@ -103,7 +85,6 @@ export const mapFields = (args: {
|
||||
config,
|
||||
fieldSchema: field.fields,
|
||||
filter,
|
||||
operation,
|
||||
parentPath: path,
|
||||
permissions,
|
||||
readOnly: readOnlyOverride,
|
||||
@@ -120,7 +101,6 @@ export const mapFields = (args: {
|
||||
config,
|
||||
fieldSchema: tab.fields,
|
||||
filter,
|
||||
operation,
|
||||
parentPath: path,
|
||||
permissions,
|
||||
readOnly: readOnlyOverride,
|
||||
@@ -146,7 +126,6 @@ export const mapFields = (args: {
|
||||
config,
|
||||
fieldSchema: block.fields,
|
||||
filter,
|
||||
operation,
|
||||
parentPath: `${path}.${block.slug}`,
|
||||
permissions,
|
||||
readOnly: readOnlyOverride,
|
||||
@@ -232,11 +211,14 @@ export const mapFields = (args: {
|
||||
// TODO: fix types
|
||||
// label: 'label' in field ? field.label : undefined,
|
||||
blocks,
|
||||
fieldPermissions,
|
||||
hasMany: 'hasMany' in field ? field.hasMany : undefined,
|
||||
max: 'max' in field ? field.max : undefined,
|
||||
maxRows: 'maxRows' in field ? field.maxRows : undefined,
|
||||
min: 'min' in field ? field.min : undefined,
|
||||
options: 'options' in field ? field.options : undefined,
|
||||
readOnly:
|
||||
'admin' in field && 'readOnly' in field.admin ? field.admin.readOnly : undefined,
|
||||
relationTo: 'relationTo' in field ? field.relationTo : undefined,
|
||||
richTextComponentMap: undefined,
|
||||
step: 'admin' in field && 'step' in field.admin ? field.admin.step : undefined,
|
||||
@@ -353,7 +335,8 @@ export const mapFields = (args: {
|
||||
labels: 'labels' in field ? field.labels : undefined,
|
||||
localized: 'localized' in field ? field.localized : false,
|
||||
options: 'options' in field ? field.options : undefined,
|
||||
readOnly,
|
||||
readOnly:
|
||||
'admin' in field && 'readOnly' in field.admin ? field.admin.readOnly : undefined,
|
||||
relationTo: 'relationTo' in field ? field.relationTo : undefined,
|
||||
subfields: nestedFieldMap,
|
||||
tabs,
|
||||
@@ -379,7 +362,7 @@ export const mapFields = (args: {
|
||||
Field: <HiddenInput name="id" />,
|
||||
Heading: <SortColumn label="ID" name="id" />,
|
||||
fieldIsPresentational: false,
|
||||
fieldPermissions: {} as FieldPermissions, // TODO: wire this up
|
||||
fieldPermissions: {} as FieldPermissions,
|
||||
isFieldAffectingData: true,
|
||||
isSidebar: false,
|
||||
label: 'ID',
|
||||
|
||||
@@ -53,6 +53,9 @@ export type MappedField = {
|
||||
* On `select` fields only
|
||||
*/
|
||||
options?: Option[]
|
||||
/**
|
||||
* This is the `admin.readOnly` value from the field's config
|
||||
*/
|
||||
readOnly: boolean
|
||||
/**
|
||||
* On `relationship` fields only
|
||||
|
||||
66
pnpm-lock.yaml
generated
66
pnpm-lock.yaml
generated
@@ -230,6 +230,9 @@ importers:
|
||||
semver:
|
||||
specifier: ^7.5.4
|
||||
version: 7.6.0
|
||||
sharp:
|
||||
specifier: 0.32.6
|
||||
version: 0.32.6
|
||||
shelljs:
|
||||
specifier: 0.8.5
|
||||
version: 0.8.5
|
||||
@@ -716,9 +719,6 @@ importers:
|
||||
scmp:
|
||||
specifier: 2.1.0
|
||||
version: 2.1.0
|
||||
sharp:
|
||||
specifier: 0.32.6
|
||||
version: 0.32.6
|
||||
devDependencies:
|
||||
'@monaco-editor/react':
|
||||
specifier: 4.5.1
|
||||
@@ -852,6 +852,9 @@ importers:
|
||||
serve-static:
|
||||
specifier: 1.15.0
|
||||
version: 1.15.0
|
||||
sharp:
|
||||
specifier: 0.32.6
|
||||
version: 0.32.6
|
||||
ts-essentials:
|
||||
specifier: 7.0.3
|
||||
version: 7.0.3(typescript@5.2.2)
|
||||
@@ -7496,6 +7499,7 @@ packages:
|
||||
|
||||
/b4a@1.6.6:
|
||||
resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==}
|
||||
dev: true
|
||||
|
||||
/babel-jest@29.7.0(@babel/core@7.24.0):
|
||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||
@@ -7579,6 +7583,7 @@ packages:
|
||||
/bare-events@2.2.0:
|
||||
resolution: {integrity: sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/bare-fs@2.2.1:
|
||||
@@ -7589,13 +7594,13 @@ packages:
|
||||
bare-os: 2.2.0
|
||||
bare-path: 2.1.0
|
||||
streamx: 2.16.1
|
||||
dev: false
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/bare-os@2.2.0:
|
||||
resolution: {integrity: sha512-hD0rOPfYWOMpVirTACt4/nK8mC55La12K5fY1ij8HAdfQakD62M+H4o4tpfKzVGLgRDTuk3vjA4GqGXXCeFbag==}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/bare-path@2.1.0:
|
||||
@@ -7603,7 +7608,7 @@ packages:
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
bare-os: 2.2.0
|
||||
dev: false
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/base64-js@1.5.1:
|
||||
@@ -7955,7 +7960,7 @@ packages:
|
||||
|
||||
/chownr@1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/chrome-trace-event@1.0.3:
|
||||
resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==}
|
||||
@@ -8096,7 +8101,7 @@ packages:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/color@4.2.3:
|
||||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
|
||||
@@ -8104,7 +8109,7 @@ packages:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
@@ -8875,6 +8880,7 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
dev: true
|
||||
|
||||
/dedent@1.5.1:
|
||||
resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==}
|
||||
@@ -8933,6 +8939,7 @@ packages:
|
||||
/deep-extend@0.6.0:
|
||||
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
dev: true
|
||||
|
||||
/deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
@@ -10113,7 +10120,7 @@ packages:
|
||||
/expand-template@2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/expand-tilde@2.0.2:
|
||||
resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==}
|
||||
@@ -10223,6 +10230,7 @@ packages:
|
||||
|
||||
/fast-fifo@1.3.2:
|
||||
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
|
||||
dev: true
|
||||
|
||||
/fast-glob@3.3.2:
|
||||
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
||||
@@ -10537,7 +10545,7 @@ packages:
|
||||
|
||||
/fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/fs-extra@10.1.0:
|
||||
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
|
||||
@@ -10740,7 +10748,7 @@ packages:
|
||||
|
||||
/github-from-package@0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
@@ -11402,7 +11410,7 @@ packages:
|
||||
|
||||
/is-arrayish@0.3.2:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/is-async-function@2.0.0:
|
||||
resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
|
||||
@@ -13218,6 +13226,7 @@ packages:
|
||||
/mimic-response@3.1.0:
|
||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/mimic-response@4.0.0:
|
||||
resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
|
||||
@@ -13281,7 +13290,7 @@ packages:
|
||||
|
||||
/mkdirp-classic@0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/mkdirp@1.0.4:
|
||||
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
|
||||
@@ -13450,7 +13459,7 @@ packages:
|
||||
|
||||
/napi-build-utils@1.0.2:
|
||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/natural-compare-lite@1.4.0:
|
||||
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
|
||||
@@ -13587,11 +13596,11 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
semver: 7.6.0
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/node-addon-api@6.1.0:
|
||||
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
@@ -15130,7 +15139,7 @@ packages:
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/prelude-ls@1.2.1:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
@@ -15318,6 +15327,7 @@ packages:
|
||||
|
||||
/queue-tick@1.0.1:
|
||||
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
|
||||
dev: true
|
||||
|
||||
/quick-format-unescaped@4.0.4:
|
||||
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
|
||||
@@ -15354,6 +15364,7 @@ packages:
|
||||
ini: 1.3.8
|
||||
minimist: 1.2.8
|
||||
strip-json-comments: 2.0.1
|
||||
dev: true
|
||||
|
||||
/react-animate-height@2.1.2(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-A9jfz/4CTdsIsE7WCQtO9UkOpMBcBRh8LxyHl2eoZz1ki02jpyUL5xt58gabd0CyeLQ8fRyQ+s2lyV2Ufu8Owg==}
|
||||
@@ -16175,7 +16186,7 @@ packages:
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 3.0.5
|
||||
tunnel-agent: 0.6.0
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/shebang-command@1.2.0:
|
||||
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
|
||||
@@ -16230,7 +16241,7 @@ packages:
|
||||
|
||||
/simple-concat@1.0.1:
|
||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/simple-get@4.0.1:
|
||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
||||
@@ -16238,7 +16249,7 @@ packages:
|
||||
decompress-response: 6.0.0
|
||||
once: 1.4.0
|
||||
simple-concat: 1.0.1
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/simple-git@3.22.0:
|
||||
resolution: {integrity: sha512-6JujwSs0ac82jkGjMHiCnTifvf1crOiY/+tfs/Pqih6iow7VrpNKRRNdWm6RtaXpvvv/JGNYhlUtLhGFqHF+Yw==}
|
||||
@@ -16254,7 +16265,7 @@ packages:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/simple-update-notifier@2.0.0:
|
||||
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
|
||||
@@ -16515,6 +16526,7 @@ packages:
|
||||
queue-tick: 1.0.1
|
||||
optionalDependencies:
|
||||
bare-events: 2.2.0
|
||||
dev: true
|
||||
|
||||
/string-argv@0.3.2:
|
||||
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
|
||||
@@ -16649,6 +16661,7 @@ packages:
|
||||
/strip-json-comments@2.0.1:
|
||||
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/strip-json-comments@3.1.1:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
@@ -16805,7 +16818,7 @@ packages:
|
||||
mkdirp-classic: 0.5.3
|
||||
pump: 3.0.0
|
||||
tar-stream: 2.2.0
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/tar-fs@3.0.5:
|
||||
resolution: {integrity: sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==}
|
||||
@@ -16815,7 +16828,7 @@ packages:
|
||||
optionalDependencies:
|
||||
bare-fs: 2.2.1
|
||||
bare-path: 2.1.0
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/tar-stream@2.2.0:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
@@ -16826,7 +16839,7 @@ packages:
|
||||
fs-constants: 1.0.0
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/tar-stream@3.1.7:
|
||||
resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
|
||||
@@ -16834,6 +16847,7 @@ packages:
|
||||
b4a: 1.6.6
|
||||
fast-fifo: 1.3.2
|
||||
streamx: 2.16.1
|
||||
dev: true
|
||||
|
||||
/teeny-request@9.0.0:
|
||||
resolution: {integrity: sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==}
|
||||
@@ -17228,7 +17242,7 @@ packages:
|
||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/tunnel@0.0.6:
|
||||
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import path from 'path'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import type { Config, SanitizedConfig } from '../packages/payload/src/config/types'
|
||||
|
||||
@@ -161,6 +162,7 @@ export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<S
|
||||
}),
|
||||
],
|
||||
}),
|
||||
sharp,
|
||||
telemetry: false,
|
||||
...testConfig,
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export default buildConfigWithDefaults({
|
||||
locales: ['en', 'es', 'de'],
|
||||
},
|
||||
i18n: {
|
||||
resources: {
|
||||
translations: {
|
||||
es: {
|
||||
'plugin-seo': {
|
||||
autoGenerate: 'Auto-génerar',
|
||||
@@ -46,7 +46,7 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
},
|
||||
generateTitle: (data: any) => `Website.com — ${data?.doc?.title?.value}`,
|
||||
generateDescription: ({ doc }: any) => doc?.excerpt?.value,
|
||||
generateDescription: ({ doc }: any) => doc?.excerpt?.value || 'generated description',
|
||||
generateURL: ({ doc, locale }: any) =>
|
||||
`https://yoursite.com/${locale ? locale + '/' : ''}${doc?.slug?.value || ''}`,
|
||||
}),
|
||||
|
||||
@@ -13,7 +13,7 @@ export const seed = async (payload: Payload): Promise<boolean> => {
|
||||
|
||||
try {
|
||||
// Create image
|
||||
const filePath = path.resolve(__dirname, '../image-1.jpg')
|
||||
const filePath = path.resolve(process.cwd(), './test/plugin-seo/image-1.jpg')
|
||||
const file = await getFileByPath(filePath)
|
||||
|
||||
const mediaDoc = await payload.create({
|
||||
|
||||
Reference in New Issue
Block a user