Compare commits

...

56 Commits

Author SHA1 Message Date
Elliot DeNolf
e9c7f9da92 chore(release): v3.0.0-alpha.61 [skip ci] 2024-04-09 14:22:12 -04:00
James Mikrut
0ce26d2c08 Feat/config i18n (#5735) 2024-04-09 14:13:17 -04:00
Alessio Gravili
abf285d713 chore: get dev:generate-types to work again (#5750) 2024-04-09 14:12:23 -04:00
James
c2ee8e3999 chore: de-flakes fields/index tests 2024-04-09 13:56:32 -04:00
James
167ba0c68f chore: adds back all tests 2024-04-09 13:50:54 -04:00
James
9ad1cbe920 chore: adjusts test snapshot logic to restore uploads properly 2024-04-09 13:33:42 -04:00
James
313ea52e3d chore: getRequestLanguage now defaults 2024-04-09 13:17:43 -04:00
James
3acfb7a83f chore: corrects imports 2024-04-09 12:43:36 -04:00
James
783dae2bbb Merge branch 'alpha' of github.com:payloadcms/payload into feat/config-i18n 2024-04-09 12:35:57 -04:00
Alessio Gravili
59681b211b fix(richtext-lexical): upload nodes weren't visible (#5746) 2024-04-09 12:32:24 -04:00
James
98438175cf chore: handles server errors 2024-04-09 12:31:25 -04:00
Alessio Gravili
af40302e5f fix(richtext-lexical): get links to work again (#5745) 2024-04-09 12:29:45 -04:00
Alessio Gravili
ec0e0ae449 chore(richtext-lexical): add e2e test to ensure that pre-seeded upload nodes are visible 2024-04-09 12:24:54 -04:00
Alessio Gravili
607ff17033 fix(richtext-lexical): upload nodes weren't visible due to incorrect relationships condition 2024-04-09 12:24:30 -04:00
Alessio Gravili
e73e610669 chore: fields test suite: clearAndSeedEverything instead of seed for dev as well, to ensure same state as test runs (most importantly, this gets rid of leftover uploads) 2024-04-09 12:22:42 -04:00
Jarrod Flesch
30fddde066 chore: corrects type for getLocalI18n 2024-04-09 11:51:40 -04:00
Jarrod Flesch
a56d2842fb chore: converts ua to uk 2024-04-09 11:44:34 -04:00
Jarrod Flesch
35f59a47cc chore: corrects dateFNS keys, stricter types 2024-04-09 11:38:38 -04:00
Jarrod Flesch
817d57bd12 chore: migrate langs 2024-04-09 11:05:35 -04:00
Elliot DeNolf
5826048e7b ci: publish script throttling 2024-04-09 09:50:23 -04:00
Elliot DeNolf
1a975b31cf chore(release): v3.0.0-alpha.60 [skip ci] 2024-04-09 09:36:41 -04:00
James
73298a80f0 chore: adds more de-flake to tabs 2024-04-09 09:34:11 -04:00
James
a5d14ef4c1 chore: de-flakes tabs 2024-04-09 09:34:11 -04:00
James
d0c79b65f8 chore: skips index to see what remains 2024-04-09 09:34:11 -04:00
James
2fc50b1a1f chore: de-flakes array 2024-04-09 09:34:11 -04:00
James
0ddeedb0b3 chore: de-flakes relationship suite 2024-04-09 09:34:11 -04:00
James
09c2fb10f3 chore: bug in ci 2024-04-09 09:34:11 -04:00
James
5bfff5b7ba chore: ensures artifacts work 2024-04-09 09:34:11 -04:00
James
702088375c chore: attempts to de-flake 2024-04-09 09:34:11 -04:00
James
ea507fbcc4 chore: moves lexical tests into collection folder 2024-04-09 09:34:11 -04:00
James
0ff1e6632b chore: splits out relationship 2024-04-09 09:34:11 -04:00
James
996ee47f96 chore: splits out blocks and array into their own suites 2024-04-09 09:34:11 -04:00
James
3e9bd5bb62 chore: uses ci env var to set max retries 2024-04-09 09:34:11 -04:00
James
ee7221c986 chore: sets maxRetries 2024-04-09 09:34:11 -04:00
James
318c126ae3 chore: turns off prebuild for fields 2024-04-09 09:34:11 -04:00
Jarrod Flesch
2154aea89f chore: comment out all other test suites for now 2024-04-09 09:34:11 -04:00
Jarrod Flesch
4d3ad1af35 chore: run fields e2e on ci 2024-04-09 09:34:11 -04:00
Alessio Gravili
75cab7688f chore: fix incorrect next tsconfig paths breaking monorepo setup (#5743) 2024-04-09 09:26:09 -04:00
James
5084d6dd97 chore: attempts to de-flake live preview 2024-04-08 22:34:23 -04:00
James
518f80cbb6 chore: es 2024-04-08 22:29:41 -04:00
James
c9399efa65 chore: fixes access control test 2024-04-08 22:25:35 -04:00
Elliot DeNolf
dd9133659c ci: rework caching, consolidates build (#5737) 2024-04-08 22:19:37 -04:00
James
d3016b7eb5 chore: merge 2024-04-08 22:13:16 -04:00
James
69e884f5b7 chore: dynamically loads date-fns locales 2024-04-08 22:12:05 -04:00
Elliot DeNolf
6d122905f4 chore: ignore new pointer files 2024-04-08 21:19:03 -04:00
Elliot DeNolf
e6e016ac2d chore(cpa): build for es6 (#5736) 2024-04-08 17:11:03 -04:00
James
3e7925e33f chore: removes async nature from a few lexical things 2024-04-08 16:48:56 -04:00
James
7a2ccba63c Merge branch 'feat/config-i18n' of github.com:payloadcms/payload into feat/config-i18n 2024-04-08 16:39:03 -04:00
James
be2134eb69 chore: requires languages to be passed to config 2024-04-08 16:38:12 -04:00
James Mikrut
95e422b0e1 Merge branch 'alpha' into feat/config-i18n 2024-04-08 16:26:38 -04:00
James
53d9c4ca95 chore: dynamically loads translations 2024-04-08 16:25:24 -04:00
James
30948ab545 chore: dynamically loads translations 2024-04-08 16:25:21 -04:00
Jacob Fletcher
906df6b401 fix(next): properly renders document-level unauthorized view (#5734) 2024-04-08 15:40:46 -04:00
Jacob Fletcher
b9c585bab5 fix(ui): uses correct save draft button label (#5730) 2024-04-08 14:34:28 -04:00
Elliot DeNolf
12203140ad chore: unprettified pointer files 2024-04-08 13:59:03 -04:00
Patrik
0704152e38 chore(next): removes unnecessary apostrophe from payload-lng cookie (#5729) 2024-04-08 13:42:44 -04:00
294 changed files with 17297 additions and 27595 deletions

View File

@@ -39,7 +39,7 @@ jobs:
echo "needs_build: ${{ steps.filter.outputs.needs_build }}"
echo "templates: ${{ steps.filter.outputs.templates }}"
core-build:
build:
needs: changes
if: ${{ needs.changes.outputs.needs_build == 'true' }}
runs-on: ubuntu-latest
@@ -65,65 +65,29 @@ jobs:
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
- name: Setup pnpm cache
uses: actions/cache@v4
timeout-minutes: 720
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
pnpm-store-
pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
- run: pnpm install
- run: pnpm run build:core
- run: pnpm run build:all
- name: Cache build
uses: actions/cache@v4
timeout-minutes: 10
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
plugins-build:
needs: changes
if: ${{ needs.changes.outputs.needs_build == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 25
- name: Use Node.js 18
uses: actions/setup-node@v4
with:
node-version: 18
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 8
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
- run: pnpm install
- run: pnpm run build:plugins
tests-unit:
runs-on: ubuntu-latest
needs: core-build
needs: build
if: false # Disable until tests are updated for 3.0
steps:
@@ -140,6 +104,7 @@ jobs:
- name: Restore build
uses: actions/cache@v4
timeout-minutes: 10
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
@@ -151,7 +116,7 @@ jobs:
tests-int:
runs-on: ubuntu-latest
needs: core-build
needs: build
strategy:
fail-fast: false
matrix:
@@ -184,6 +149,7 @@ jobs:
- name: Restore build
uses: actions/cache@v4
timeout-minutes: 10
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
@@ -242,7 +208,7 @@ jobs:
tests-e2e:
runs-on: ubuntu-latest
needs: core-build
needs: build
strategy:
fail-fast: false
matrix:
@@ -255,8 +221,11 @@ jobs:
- email
- field-error-states
- fields-relationship
# - fields
- fields/lexical
- fields
- fields__collections__Blocks
- fields__collections__Array
- fields__collections__Relationship
- fields__collections__Lexical
- live-preview
- localization
- plugin-form-builder
@@ -279,6 +248,7 @@ jobs:
- name: Restore build
uses: actions/cache@v4
timeout-minutes: 10
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
@@ -299,7 +269,7 @@ jobs:
tests-type-generation:
if: false # This should be replaced with gen on a real Payload project
runs-on: ubuntu-latest
needs: core-build
needs: build
steps:
- name: Use Node.js 18
@@ -315,6 +285,7 @@ jobs:
- name: Restore build
uses: actions/cache@v4
timeout-minutes: 10
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}

View File

@@ -10,3 +10,5 @@
**/temp
**/docs/**
tsconfig.json
packages/payload/*.js
packages/payload/*.d.ts

View File

@@ -3,7 +3,7 @@ import type { Metadata } from 'next'
import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views/NotFound/index.js'
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
type Args = {
params: {
@@ -14,8 +14,8 @@ type Args = {
}
}
export const generateMetadata = ({ params }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params })
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams })
const NotFound = ({ params, searchParams }: Args) => NotFoundPage({ config, params, searchParams })

View File

@@ -3,7 +3,7 @@ import type { Metadata } from 'next'
import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { RootPage, generatePageMetadata } from '@payloadcms/next/views/Root/index.js'
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
type Args = {
params: {

View File

@@ -1,7 +1,7 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes/index.js'
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
export const GET = REST_GET(config)
export const POST = REST_POST(config)

View File

@@ -1,6 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes/index.js'
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
export const GET = GRAPHQL_PLAYGROUND_GET(config)

View File

@@ -1,6 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { GRAPHQL_POST } from '@payloadcms/next/routes/index.js'
import { GRAPHQL_POST } from '@payloadcms/next/routes'
export const POST = GRAPHQL_POST(config)

View File

@@ -1,6 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import configPromise from '@payload-config'
import { RootLayout } from '@payloadcms/next/layouts/Root/index.js'
import { RootLayout } from '@payloadcms/next/layouts'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import React from 'react'

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"private": true,
"type": "module",
"workspaces:": [

View File

@@ -10,6 +10,6 @@
}
},
"module": {
"type": "commonjs"
"type": "es6"
}
}

View File

@@ -1,2 +1,4 @@
#!/usr/bin/env node
require('../dist/index.js')
import { main } from '../dist/index.js'
main()

View File

@@ -1,6 +1,6 @@
{
"name": "create-payload-app",
"version": "3.0.0-alpha.54",
"version": "3.0.0-alpha.61",
"license": "MIT",
"type": "module",
"homepage": "https://payloadcms.com",

View File

@@ -1,8 +1,12 @@
import { Main } from './main.js'
import { error } from './utils/log.js'
async function main(): Promise<void> {
await new Main().init()
export async function main(): Promise<void> {
try {
await new Main().init()
} catch (e) {
if (e instanceof Error) {
error(e.message)
}
}
}
main().catch((e) => error(`An error has occurred: ${e instanceof Error ? e.message : e}`))

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"description": "The officially supported MongoDB database adapter for Payload",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"description": "The officially supported Postgres database adapter for Payload",
"repository": {
"type": "git",

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/next",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"main": "./src/index.js",
"types": "./src/index.js",
"type": "module",

View File

@@ -1,13 +1,14 @@
import type { AcceptedLanguages } from '@payloadcms/translations'
import type { SanitizedConfig } from 'payload/types'
import { translations } from '@payloadcms/translations/client'
import { rtlLanguages } from '@payloadcms/translations'
import { initI18n } from '@payloadcms/translations'
import { RootProvider } from '@payloadcms/ui/providers/Root'
import '@payloadcms/ui/scss/app.scss'
import { buildComponentMap } from '@payloadcms/ui/utilities/buildComponentMap'
import { headers as getHeaders, cookies as nextCookies } from 'next/headers.js'
import { parseCookies } from 'payload/auth'
import { createClientConfig } from 'payload/config'
import { deepMerge } from 'payload/utilities'
import React from 'react'
import 'react-toastify/dist/ReactToastify.css'
@@ -20,8 +21,6 @@ export const metadata = {
title: 'Next.js',
}
const rtlLanguages = ['ar', 'fa', 'ha', 'ku', 'ur', 'ps', 'dv', 'ks', 'khw', 'he', 'yi']
export const RootLayout = async ({
children,
config: configPromise,
@@ -30,32 +29,42 @@ export const RootLayout = async ({
config: Promise<SanitizedConfig>
}) => {
const config = await configPromise
const clientConfig = await createClientConfig(config)
const headers = getHeaders()
const cookies = parseCookies(headers)
const lang =
getRequestLanguage({
config,
cookies,
headers,
}) ?? clientConfig.i18n.fallbackLanguage
const languageCode = getRequestLanguage({
config,
cookies,
headers,
})
const dir = rtlLanguages.includes(lang) ? 'RTL' : 'LTR'
const i18n = await initI18n({ config: config.i18n, context: 'client', language: languageCode })
const clientConfig = await createClientConfig({ config, t: i18n.t })
const mergedTranslations = deepMerge(translations, clientConfig.i18n.translations)
const dir = (rtlLanguages as unknown as AcceptedLanguages[]).includes(languageCode)
? 'RTL'
: 'LTR'
const languageOptions = Object.entries(translations || {}).map(([language, translations]) => ({
label: translations.general.thisLanguage,
value: language,
}))
const languageOptions = Object.entries(config.i18n.supportedLanguages || {}).reduce(
(acc, [language, languageConfig]) => {
if (Object.keys(config.i18n.supportedLanguages).includes(language)) {
acc.push({
label: languageConfig.translations.general.thisLanguage,
value: language,
})
}
return acc
},
[],
)
// eslint-disable-next-line @typescript-eslint/require-await
async function switchLanguageServerAction(lang: string): Promise<void> {
'use server'
nextCookies().set({
name: `${config.cookiePrefix || 'payload'}-lng'`,
name: `${config.cookiePrefix || 'payload'}-lng`,
path: '/',
value: lang,
})
@@ -66,20 +75,22 @@ export const RootLayout = async ({
DefaultListView,
children,
config,
i18n,
})
return (
<html dir={dir} lang={lang}>
<html dir={dir} lang={languageCode}>
<body>
<RootProvider
componentMap={componentMap}
config={clientConfig}
dateFNSKey={i18n.dateFNSKey}
fallbackLang={clientConfig.i18n.fallbackLanguage}
lang={lang}
languageCode={languageCode}
languageOptions={languageOptions}
// eslint-disable-next-line react/jsx-no-bind
switchLanguageServerAction={switchLanguageServerAction}
translations={mergedTranslations[lang]}
translations={i18n.translations}
>
{wrappedChildren}
</RootProvider>

View File

@@ -1,11 +1,5 @@
import type { BuildFormStateArgs } from '@payloadcms/ui/forms/buildStateFromSchema'
import type {
DocumentPreferences,
Field,
PayloadRequest,
SanitizedConfig,
TypeWithID,
} from 'payload/types'
import type { DocumentPreferences, Field, PayloadRequest, TypeWithID } from 'payload/types'
import { buildStateFromSchema } from '@payloadcms/ui/forms/buildStateFromSchema'
import { reduceFieldsToValues } from '@payloadcms/ui/utilities/reduceFieldsToValues'
@@ -22,12 +16,12 @@ if (!cached) {
cached = global._payload_fieldSchemaMap = null
}
export const getFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
export const getFieldSchemaMap = (req: PayloadRequest): FieldSchemaMap => {
if (cached && process.env.NODE_ENV !== 'development') {
return cached
}
cached = buildFieldSchemaMap(config)
cached = buildFieldSchemaMap(req)
return cached
}
@@ -65,7 +59,7 @@ export const buildFormState = async ({ req }: { req: PayloadRequest }) => {
})
}
const fieldSchemaMap = getFieldSchemaMap(req.payload.config)
const fieldSchemaMap = getFieldSchemaMap(req)
const id = collectionSlug ? reqData.id : undefined
const schemaPathSegments = schemaPath.split('.')

View File

@@ -1,10 +1,13 @@
import type { SanitizedConfig } from 'payload/types'
import type { PayloadRequest } from 'payload/types'
import type { FieldSchemaMap } from './types.js'
import { traverseFields } from './traverseFields.js'
export const buildFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
export const buildFieldSchemaMap = ({
i18n,
payload: { config },
}: PayloadRequest): FieldSchemaMap => {
const result: FieldSchemaMap = new Map()
const validRelationships = config.collections.map((c) => c.slug) || []
@@ -13,6 +16,7 @@ export const buildFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap =>
traverseFields({
config,
fields: collection.fields,
i18n,
schemaMap: result,
schemaPath: collection.slug,
validRelationships,
@@ -23,6 +27,7 @@ export const buildFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap =>
traverseFields({
config,
fields: global.fields,
i18n,
schemaMap: result,
schemaPath: global.slug,
validRelationships,

View File

@@ -1,3 +1,4 @@
import type { I18n } from '@payloadcms/translations'
import type { Field, SanitizedConfig } from 'payload/types'
import { tabHasName } from 'payload/types'
@@ -7,6 +8,7 @@ import type { FieldSchemaMap } from './types.js'
type Args = {
config: SanitizedConfig
fields: Field[]
i18n: I18n
schemaMap: FieldSchemaMap
schemaPath: string
validRelationships: string[]
@@ -15,6 +17,7 @@ type Args = {
export const traverseFields = ({
config,
fields,
i18n,
schemaMap,
schemaPath,
validRelationships,
@@ -28,6 +31,7 @@ export const traverseFields = ({
traverseFields({
config,
fields: field.fields,
i18n,
schemaMap,
schemaPath: `${schemaPath}.${field.name}`,
validRelationships,
@@ -39,6 +43,7 @@ export const traverseFields = ({
traverseFields({
config,
fields: field.fields,
i18n,
schemaMap,
schemaPath,
validRelationships,
@@ -54,6 +59,7 @@ export const traverseFields = ({
traverseFields({
config,
fields: block.fields,
i18n,
schemaMap,
schemaPath: blockSchemaPath,
validRelationships,
@@ -65,6 +71,7 @@ export const traverseFields = ({
if (typeof field.editor.generateSchemaMap === 'function') {
field.editor.generateSchemaMap({
config,
i18n,
schemaMap,
schemaPath: `${schemaPath}.${field.name}`,
})
@@ -83,6 +90,7 @@ export const traverseFields = ({
traverseFields({
config,
fields: tab.fields,
i18n,
schemaMap,
schemaPath: tabSchemaPath,
validRelationships,

View File

@@ -6,7 +6,6 @@ import type {
} from 'payload/types'
import { initI18n } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { executeAuthStrategies } from 'payload/auth'
import { parseCookies } from 'payload/auth'
import { getDataLoader } from 'payload/utilities'
@@ -72,11 +71,10 @@ export const createPayloadRequest = async ({
headers: request.headers,
})
const i18n = initI18n({
const i18n = await initI18n({
config: config.i18n,
context: 'api',
language,
translations,
})
const customRequest: CustomPayloadRequest = {

View File

@@ -1,22 +1,20 @@
import type { I18n } from '@payloadcms/translations'
import type { AcceptedLanguages, I18n } from '@payloadcms/translations'
import type { SanitizedConfig } from 'payload/types'
import { initI18n } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/client'
import { cookies, headers } from 'next/headers.js'
import { getRequestLanguage } from './getRequestLanguage.js'
export const getNextI18n = ({
export const getNextI18n = async ({
config,
language,
}: {
config: SanitizedConfig
language?: string
}): I18n =>
language?: AcceptedLanguages
}): Promise<I18n> =>
initI18n({
config: config.i18n,
context: 'client',
language: language || getRequestLanguage({ config, cookies: cookies(), headers: headers() }),
translations,
})

View File

@@ -1,3 +1,4 @@
import type { AcceptedLanguages } from '@payloadcms/translations'
import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension/adapters/request-cookies.js'
import type { SanitizedConfig } from 'payload/config'
@@ -6,7 +7,7 @@ import { matchLanguage } from '@payloadcms/translations'
type GetRequestLanguageArgs = {
config: SanitizedConfig
cookies: Map<string, string> | ReadonlyRequestCookies
defaultLanguage?: string
defaultLanguage?: AcceptedLanguages
headers: Request['headers']
}
@@ -15,14 +16,15 @@ export const getRequestLanguage = ({
cookies,
defaultLanguage = 'en',
headers,
}: GetRequestLanguageArgs): string => {
}: GetRequestLanguageArgs): AcceptedLanguages => {
const acceptLanguage = headers.get('Accept-Language')
const cookieLanguage = cookies.get(`${config.cookiePrefix || 'payload'}-lng'`)
const cookieLanguage = cookies.get(`${config.cookiePrefix || 'payload'}-lng`)
const reqLanguage =
(typeof cookieLanguage === 'string' ? cookieLanguage : cookieLanguage?.value) ||
acceptLanguage ||
config.i18n.fallbackLanguage ||
defaultLanguage
return matchLanguage(reqLanguage)
return matchLanguage(reqLanguage) || defaultLanguage
}

View File

@@ -8,7 +8,6 @@ import type {
} from 'payload/types'
import { initI18n } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/client'
import { findLocaleFromCode } from '@payloadcms/ui/utilities/findLocaleFromCode'
import { headers as getHeaders } from 'next/headers.js'
import { notFound, redirect } from 'next/navigation.js'
@@ -45,14 +44,13 @@ export const initPage = async ({
const cookies = parseCookies(headers)
const language = getRequestLanguage({ config: payload.config, cookies, headers })
const i18n = initI18n({
const i18n = await initI18n({
config: payload.config.i18n,
context: 'client',
language,
translations,
})
const req = createLocalReq(
const req = await createLocalReq(
{
fallbackLocale: null,
locale: locale.code,

View File

@@ -12,10 +12,11 @@ import './index.scss'
export { generateCreateFirstUserMetadata } from './meta.js'
export const CreateFirstUser: React.FC<AdminViewProps> = async ({ initPageResult }) => {
export const CreateFirstUserView: React.FC<AdminViewProps> = async ({ initPageResult }) => {
const {
req,
req: {
i18n,
payload: {
config,
config: {
@@ -51,6 +52,7 @@ export const CreateFirstUser: React.FC<AdminViewProps> = async ({ initPageResult
const createFirstUserFieldMap = mapFields({
config,
fieldSchema: fields,
i18n,
parentPath: userSlug,
})

View File

@@ -10,7 +10,7 @@ import type {
import { APIView as DefaultAPIView } from '../API/index.js'
import { EditView as DefaultEditView } from '../Edit/index.js'
import { LivePreviewView as DefaultLivePreviewView } from '../LivePreview/index.js'
import { Unauthorized } from '../Unauthorized/index.js'
import { UnauthorizedView } from '../Unauthorized/index.js'
import { VersionView as DefaultVersionView } from '../Version/index.js'
import { VersionsView as DefaultVersionsView } from '../Versions/index.js'
import { getCustomViewByKey } from './getCustomViewByKey.js'
@@ -77,7 +77,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Default')
DefaultView = DefaultEditView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
break
}
@@ -87,7 +87,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Default')
DefaultView = DefaultEditView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
break
}
@@ -118,7 +118,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Versions')
DefaultView = DefaultVersionsView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
break
}
@@ -150,7 +150,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Version')
DefaultView = DefaultVersionView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
} else {
const baseRoute = [adminRoute, collectionEntity, collectionSlug, segment3]
@@ -191,7 +191,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Default')
DefaultView = DefaultEditView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
break
}
@@ -219,7 +219,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Versions')
DefaultView = DefaultVersionsView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
break
}
@@ -229,7 +229,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Default')
DefaultView = DefaultEditView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
break
}
@@ -244,7 +244,7 @@ export const getViewsFromConfig = ({
CustomView = getCustomViewByKey(views, 'Version')
DefaultView = DefaultVersionView
} else {
ErrorView = Unauthorized
ErrorView = UnauthorizedView
}
} else {
const baseRoute = [adminRoute, 'globals', globalSlug].filter(Boolean).join('/')

View File

@@ -15,6 +15,7 @@ import React from 'react'
import type { GenerateEditViewMetadata } from './getMetaBySegment.js'
import { NotFoundView } from '../NotFound/index.js'
import { getMetaBySegment } from './getMetaBySegment.js'
import { getViewsFromConfig } from './getViewsFromConfig.js'
@@ -106,12 +107,8 @@ export const Document: React.FC<AdminViewProps> = async ({
ErrorView = collectionViews?.ErrorView
}
if (!CustomView && !DefaultView && !ViewOverride) {
if (ErrorView) {
return <ErrorView initPageResult={initPageResult} searchParams={searchParams} />
}
notFound()
if (!CustomView && !DefaultView && !ViewOverride && !ErrorView) {
ErrorView = NotFoundView
}
}
@@ -143,12 +140,8 @@ export const Document: React.FC<AdminViewProps> = async ({
DefaultView = globalViews?.DefaultView
ErrorView = globalViews?.ErrorView
if (!CustomView && !DefaultView && !ViewOverride) {
if (ErrorView) {
return <ErrorView initPageResult={initPageResult} searchParams={searchParams} />
}
notFound()
if (!CustomView && !DefaultView && !ViewOverride && !ErrorView) {
ErrorView = NotFoundView
}
}
}
@@ -219,11 +212,15 @@ export const Document: React.FC<AdminViewProps> = async ({
uploadEdits: undefined,
}}
>
<RenderCustomComponent
CustomComponent={ViewOverride || CustomView}
DefaultComponent={DefaultView}
componentProps={viewComponentProps}
/>
{ErrorView ? (
<ErrorView initPageResult={initPageResult} searchParams={searchParams} />
) : (
<RenderCustomComponent
CustomComponent={ViewOverride || CustomView}
DefaultComponent={DefaultView}
componentProps={viewComponentProps}
/>
)}
</FormQueryParamsProvider>
</EditDepthProvider>
</DocumentInfoProvider>

View File

@@ -13,7 +13,7 @@ export { generateForgotPasswordMetadata } from './meta.js'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export const forgotPasswordBaseClass = 'forgot-password'
export const ForgotPassword: React.FC<AdminViewProps> = ({ initPageResult }) => {
export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult }) => {
const {
req: {
i18n,

View File

@@ -13,7 +13,7 @@ import React, { Fragment } from 'react'
import type { DefaultListViewProps, ListPreferences } from './Default/types.js'
import { Unauthorized } from '../Unauthorized/index.js'
import { UnauthorizedView } from '../Unauthorized/index.js'
import { DefaultListView } from './Default/index.js'
export { generateListMetadata } from './meta.js'
@@ -35,7 +35,7 @@ export const ListView: React.FC<AdminViewProps> = async ({ initPageResult, searc
const collectionSlug = collectionConfig?.slug
if (!permissions?.collections?.[collectionSlug]?.read?.permission) {
return <Unauthorized initPageResult={initPageResult} searchParams={searchParams} />
return <UnauthorizedView initPageResult={initPageResult} searchParams={searchParams} />
}
let listPreferences: ListPreferences
@@ -117,7 +117,10 @@ export const ListView: React.FC<AdminViewProps> = async ({ initPageResult, searc
<Fragment>
<HydrateClientUser permissions={permissions} user={user} />
<ListInfoProvider
collectionConfig={createClientCollectionConfig(collectionConfig)}
collectionConfig={createClientCollectionConfig({
collection: collectionConfig,
t: initPageResult.req.i18n.t,
})}
collectionSlug={collectionSlug}
hasCreatePermission={permissions?.collections?.[collectionSlug]?.create?.permission}
newDocumentURL={`${admin}/collections/${collectionSlug}/create`}

View File

@@ -11,7 +11,7 @@ export { generateLoginMetadata } from './meta.js'
export const loginBaseClass = 'login'
export const Login: React.FC<AdminViewProps> = ({ initPageResult, searchParams }) => {
export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, searchParams }) => {
const { req } = initPageResult
const {

View File

@@ -10,7 +10,7 @@ const baseClass = 'logout'
export { generateLogoutMetadata } from './meta.js'
export const Logout: React.FC<
export const LogoutView: React.FC<
AdminViewProps & {
inactivity?: boolean
}
@@ -39,5 +39,5 @@ export const Logout: React.FC<
}
export const LogoutInactivity: React.FC<AdminViewProps> = (props) => {
return <Logout inactivity {...props} />
return <LogoutView inactivity {...props} />
}

View File

@@ -1,13 +1,13 @@
import type { I18n } from '@payloadcms/translations'
import type { Metadata } from 'next'
import type { SanitizedConfig } from 'payload/types'
import type { AdminViewComponent, SanitizedConfig } from 'payload/types'
import { getNextI18n } from '@payloadcms/next/utilities'
import { HydrateClientUser } from '@payloadcms/ui/elements/HydrateClientUser'
import { DefaultTemplate } from '@payloadcms/ui/templates/Default'
import React, { Fragment } from 'react'
import { initPage } from '../../utilities/initPage.js'
import { getNextI18n } from '.././../utilities/getNextI18n.js'
import { NotFoundClient } from './index.client.js'
export const generatePageMetadata = async ({
@@ -19,7 +19,7 @@ export const generatePageMetadata = async ({
}): Promise<Metadata> => {
const config = await configPromise
const i18n = getNextI18n({
const i18n = await getNextI18n({
config,
})
@@ -65,3 +65,7 @@ export const NotFoundPage = async ({
</Fragment>
)
}
export const NotFoundView: AdminViewComponent = () => {
return <NotFoundClient marginTop="large" />
}

View File

@@ -4,15 +4,15 @@ import type { AdminViewComponent } from 'payload/types'
import type { initPage } from '../../utilities/initPage.js'
import { Account } from '../Account/index.js'
import { CreateFirstUser } from '../CreateFirstUser/index.js'
import { CreateFirstUserView } from '../CreateFirstUser/index.js'
import { Dashboard } from '../Dashboard/index.js'
import { Document as DocumentView } from '../Document/index.js'
import { ForgotPassword, forgotPasswordBaseClass } from '../ForgotPassword/index.js'
import { ForgotPasswordView, forgotPasswordBaseClass } from '../ForgotPassword/index.js'
import { ListView } from '../List/index.js'
import { Login, loginBaseClass } from '../Login/index.js'
import { Logout, LogoutInactivity } from '../Logout/index.js'
import { LoginView, loginBaseClass } from '../Login/index.js'
import { LogoutInactivity, LogoutView } from '../Logout/index.js'
import { ResetPassword, resetPasswordBaseClass } from '../ResetPassword/index.js'
import { Unauthorized } from '../Unauthorized/index.js'
import { UnauthorizedView } from '../Unauthorized/index.js'
import { Verify, verifyBaseClass } from '../Verify/index.js'
import { getCustomViewByRoute } from './getCustomViewByRoute.js'
@@ -24,12 +24,12 @@ const baseClasses = {
}
const oneSegmentViews = {
'create-first-user': CreateFirstUser,
forgot: ForgotPassword,
login: Login,
logout: Logout,
'create-first-user': CreateFirstUserView,
forgot: ForgotPasswordView,
login: LoginView,
logout: LogoutView,
'logout-inactivity': LogoutInactivity,
unauthorized: Unauthorized,
unauthorized: UnauthorizedView,
}
export const getViewFromConfig = ({

View File

@@ -49,7 +49,7 @@ export const generatePageMetadata = async ({ config: configPromise, params }: Ar
const isGlobal = segmentOne === 'globals'
const isCollection = segmentOne === 'collections'
const i18n = getNextI18n({
const i18n = await getNextI18n({
config,
})

View File

@@ -0,0 +1,36 @@
@import '../../scss/styles.scss';
.unauthorized {
margin-top: var(--base);
& > * {
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
&__button {
margin: 0;
}
&--margin-top-large {
margin-top: calc(var(--base) * 2);
}
@include large-break {
&--margin-top-large {
margin-top: var(--base);
}
}
@include small-break {
margin-top: calc(var(--base) / 2);
&--margin-top-large {
margin-top: calc(var(--base) / 2);
}
}
}

View File

@@ -5,11 +5,15 @@ import { Gutter } from '@payloadcms/ui/elements/Gutter'
import LinkImport from 'next/link.js'
import React from 'react'
import './index.scss'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export { generateUnauthorizedMetadata } from './meta.js'
export const Unauthorized: AdminViewComponent = ({ initPageResult }) => {
const baseClass = 'unauthorized'
export const UnauthorizedView: AdminViewComponent = ({ initPageResult }) => {
const {
req: {
i18n,
@@ -22,11 +26,10 @@ export const Unauthorized: AdminViewComponent = ({ initPageResult }) => {
} = initPageResult
return (
<Gutter className="unauthorized">
<Gutter className={baseClass}>
<h2>{i18n.t('error:unauthorized')}</h2>
<p>{i18n.t('error:notAllowedToAccessPage')}</p>
<br />
<Button Link={Link} el="link" to={logoutRoute}>
<Button Link={Link} className={`${baseClass}__button`} el="link" to={logoutRoute}>
{i18n.t('authentication:logOut')}
</Button>
</Gutter>

View File

@@ -85,7 +85,9 @@ export const SetStepNav: React.FC<{
url: `${adminRoute}/collections/${collectionSlug}/${id}/versions`,
},
{
label: doc?.createdAt ? formatDate(doc.createdAt, dateFormat, i18n?.language) : '',
label: doc?.createdAt
? formatDate({ date: doc.createdAt, i18n, pattern: dateFormat })
: '',
},
]
}
@@ -101,7 +103,9 @@ export const SetStepNav: React.FC<{
url: `${adminRoute}/globals/${globalConfig.slug}/versions`,
},
{
label: doc?.createdAt ? formatDate(doc.createdAt, dateFormat, i18n?.language) : '',
label: doc?.createdAt
? formatDate({ date: doc.createdAt, i18n, pattern: dateFormat })
: '',
},
]
}

View File

@@ -61,7 +61,7 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
} = config
const formattedCreatedAt = doc?.createdAt
? formatDate(doc.createdAt, dateFormat, i18n.language)
? formatDate({ date: doc.createdAt, i18n, pattern: dateFormat })
: ''
const originalDocFetchURL = `${serverURL}${apiRoute}/${globalSlug ? 'globals/' : ''}${

View File

@@ -88,7 +88,7 @@ export const SelectComparison: React.FC<Props> = (props) => {
setOptions((existingOptions) => [
...existingOptions,
...data.docs.map((doc) => ({
label: formatDate(doc.updatedAt, dateFormat, i18n.language),
label: formatDate({ date: doc.updatedAt, i18n, pattern: dateFormat }),
value: doc.id,
})),
])

View File

@@ -22,7 +22,7 @@ export const generateMetadata: GenerateEditViewMetadata = async ({
const doc: any = {} // TODO: figure this out
const formattedCreatedAt = doc?.createdAt
? formatDate(doc.createdAt, config?.admin?.dateFormat, i18n?.language)
? formatDate({ date: doc.createdAt, i18n, pattern: config?.admin?.dateFormat })
: ''
if (collectionConfig) {

View File

@@ -38,7 +38,8 @@ export const CreatedAtCell: React.FC<CreatedAtCellProps> = ({
return (
<Link href={to}>
{cellData && formatDate(cellData as Date | number | string, dateFormat, i18n.language)}
{cellData &&
formatDate({ date: cellData as Date | number | string, i18n, pattern: dateFormat })}
</Link>
)
}

View File

@@ -1,4 +1,4 @@
export { RootLayout } from './layouts/Root/index.js'
export { Dashboard as DashboardPage } from './views/Dashboard/index.js'
export { Login } from './views/Login/index.js'
export { LoginView } from './views/Login/index.js'
export { RootPage } from './views/Root/index.js'

View File

@@ -20,3 +20,7 @@
/versions.js
/operations.js
/operations.d.ts
/node.js
/node.d.ts
/uploads.js
/uploads.d.ts

View File

@@ -1,5 +0,0 @@
export {
importConfig,
importWithoutClientFiles,
} from './dist/utilities/importWithoutClientFiles.js'
//# sourceMappingURL=node.d.ts.map

View File

@@ -1,6 +0,0 @@
export {
importConfig,
importWithoutClientFiles,
} from './dist/utilities/importWithoutClientFiles.js'
//# sourceMappingURL=node.js.map

View File

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

View File

@@ -1,3 +1,4 @@
import type { I18n } from '@payloadcms/translations'
import type { JSONSchema4 } from 'json-schema'
import type { SanitizedConfig } from '../config/types.js'
@@ -28,10 +29,12 @@ type RichTextAdapterBase<
}) => Promise<void> | null
generateComponentMap: (args: {
config: SanitizedConfig
i18n: I18n
schemaPath: string
}) => Map<string, React.ReactNode>
generateSchemaMap?: (args: {
config: SanitizedConfig
i18n: I18n
schemaMap: Map<string, Field[]>
schemaPath: string
}) => Map<string, Field[]>

View File

@@ -1,6 +1,8 @@
import type React from 'react'
export type DescriptionFunction = () => string
import type { LabelFunction } from '../../config/types.js'
export type DescriptionFunction = LabelFunction
export type DescriptionComponent = React.ComponentType<FieldDescriptionProps>

View File

@@ -1,8 +1,10 @@
import type { LabelFunction } from '../../config/types.js'
export type LabelProps = {
CustomLabel?: React.ReactNode
as?: 'label' | 'span'
htmlFor?: string
label?: Record<string, string> | false | string
label?: LabelFunction | Record<string, string> | false | string
required?: boolean
unstyled?: boolean
}

View File

@@ -1,4 +1,4 @@
import type { Translations } from '@payloadcms/translations'
import type { SupportedLanguages } from '@payloadcms/translations'
import type { Permissions } from '../../auth/index.js'
import type { SanitizedCollectionConfig } from '../../collections/config/types.js'
@@ -43,7 +43,7 @@ export type InitPageResult = {
locale: Locale
permissions: Permissions
req: PayloadRequest
translations: Translations
translations: SupportedLanguages
visibleEntities: VisibleEntities
}

View File

@@ -2,15 +2,12 @@ import crypto from 'crypto'
import type { Field, FieldHook } from '../../fields/config/types.js'
import { extractTranslations } from '../../translations/extractTranslations.js'
const labels = extractTranslations(['authentication:enableAPIKey', 'authentication:apiKey'])
const encryptKey: FieldHook = ({ req, value }) =>
value ? req.payload.encrypt(value as string) : null
const decryptKey: FieldHook = ({ req, value }) =>
value ? req.payload.decrypt(value as string) : undefined
// eslint-disable-next-line no-restricted-exports
export default [
{
name: 'enableAPIKey',
@@ -21,7 +18,7 @@ export default [
},
},
defaultValue: false,
label: labels['authentication:enableAPIKey'],
label: ({ t }) => t('authentication:enableAPIKey'),
},
{
name: 'apiKey',
@@ -35,7 +32,7 @@ export default [
afterRead: [decryptKey],
beforeChange: [encryptKey],
},
label: labels['authentication:apiKey'],
label: ({ t }) => t('authentication:apiKey'),
},
{
name: 'apiKeyIndex',

View File

@@ -1,9 +1,6 @@
import type { Field } from '../../fields/config/types.js'
import { email } from '../../fields/validations.js'
import { extractTranslations } from '../../translations/extractTranslations.js'
const labels = extractTranslations(['general:email'])
const baseAuthFields: Field[] = [
{
@@ -14,7 +11,7 @@ const baseAuthFields: Field[] = [
Field: () => null,
},
},
label: labels['general:email'],
label: ({ t }) => t('general:email'),
required: true,
unique: true,
validate: email,

View File

@@ -1,9 +1,5 @@
import type { Field, FieldHook } from '../../fields/config/types.js'
import { extractTranslations } from '../../translations/extractTranslations.js'
const labels = extractTranslations(['authentication:verified'])
const autoRemoveVerificationToken: FieldHook = ({ data, operation, originalDoc, value }) => {
// If a user manually sets `_verified` to true,
// and it was `false`, set _verificationToken to `null`.
@@ -33,7 +29,7 @@ export default [
Field: () => null,
},
},
label: labels['authentication:verified'],
label: ({ t }) => t('authentication:verified'),
},
{
name: '_verificationToken',

View File

@@ -1,9 +1,5 @@
import type { CollectionConfig } from '../collections/config/types.js'
import { extractTranslations } from '../translations/extractTranslations.js'
const labels = extractTranslations(['general:user', 'general:users'])
export const defaultUserCollection: CollectionConfig = {
slug: 'users',
admin: {
@@ -14,7 +10,7 @@ export const defaultUserCollection: CollectionConfig = {
},
fields: [],
labels: {
plural: labels['general:users'],
singular: labels['general:user'],
plural: ({ t }) => t('general:users'),
singular: ({ t }) => t('general:user'),
},
}

View File

@@ -10,6 +10,6 @@ export const auth = async (payload: Payload, options: AuthArgs): Promise<AuthRes
return await authOperation({
headers,
req: createLocalReq({ req: options.req as PayloadRequest }, payload),
req: await createLocalReq({ req: options.req as PayloadRequest }, payload),
})
}

View File

@@ -78,7 +78,6 @@ export const resolve: ResolveFn = async (specifier, context, nextResolve) => {
// and keep going
let nextResult: ResolveResult
// First, try to
if (!isTS) {
try {
nextResult = await nextResolve(specifier, context, nextResolve)

View File

@@ -23,14 +23,22 @@ export type ClientCollectionConfig = Omit<
fields: ClientFieldConfig[]
}
import type { TFunction } from '@payloadcms/translations'
import type { ClientFieldConfig } from '../../fields/config/client.js'
import type { SanitizedCollectionConfig } from './types.js'
import { createClientFieldConfigs } from '../../fields/config/client.js'
export const createClientCollectionConfig = (collection: SanitizedCollectionConfig) => {
export const createClientCollectionConfig = ({
collection,
t,
}: {
collection: SanitizedCollectionConfig
t: TFunction
}) => {
const sanitized = { ...collection }
sanitized.fields = createClientFieldConfigs(sanitized.fields)
sanitized.fields = createClientFieldConfigs({ fields: sanitized.fields, t })
const serverOnlyCollectionProperties: Partial<ServerOnlyCollectionProperties>[] = [
'hooks',
@@ -60,6 +68,14 @@ export const createClientCollectionConfig = (collection: SanitizedCollectionConf
delete sanitized.auth.verify
}
if (sanitized.labels) {
Object.entries(sanitized.labels).forEach(([labelType, collectionLabel]) => {
if (typeof collectionLabel === 'function') {
sanitized.labels[labelType] = collectionLabel({ t })
}
})
}
if ('admin' in sanitized) {
sanitized.admin = { ...sanitized.admin }
@@ -85,7 +101,11 @@ export const createClientCollectionConfig = (collection: SanitizedCollectionConf
return sanitized
}
export const createClientCollectionConfigs = (
collections: SanitizedCollectionConfig[],
): ClientCollectionConfig[] =>
collections.map((collection) => createClientCollectionConfig(collection))
export const createClientCollectionConfigs = ({
collections,
t,
}: {
collections: SanitizedCollectionConfig[]
t: TFunction
}): ClientCollectionConfig[] =>
collections.map((collection) => createClientCollectionConfig({ collection, t }))

View File

@@ -11,15 +11,12 @@ import TimestampsRequired from '../../errors/TimestampsRequired.js'
import { sanitizeFields } from '../../fields/config/sanitize.js'
import { fieldAffectsData } from '../../fields/config/types.js'
import mergeBaseFields from '../../fields/mergeBaseFields.js'
import { extractTranslations } from '../../translations/extractTranslations.js'
import { getBaseUploadFields } from '../../uploads/getBaseFields.js'
import { formatLabels } from '../../utilities/formatLabels.js'
import { isPlainObject } from '../../utilities/isPlainObject.js'
import baseVersionFields from '../../versions/baseFields.js'
import { authDefaults, defaults } from './defaults.js'
const translations = extractTranslations(['general:createdAt', 'general:updatedAt'])
const sanitizeCollection = (
config: Config,
collection: CollectionConfig,
@@ -51,7 +48,7 @@ const sanitizeCollection = (
disableBulkEdit: true,
hidden: true,
},
label: translations['general:updatedAt'],
label: ({ t }) => t('general:updatedAt'),
})
}
if (!hasCreatedAt) {
@@ -64,7 +61,7 @@ const sanitizeCollection = (
// The default sort for list view is createdAt. Thus, enabling indexing by default, is a major performance improvement, especially for large or a large amount of collections.
type: 'date',
index: true,
label: translations['general:createdAt'],
label: ({ t }) => t('general:createdAt'),
})
}
}

View File

@@ -140,10 +140,10 @@ const collectionSchema = joi.object().keys({
labels: joi.object({
plural: joi
.alternatives()
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
singular: joi
.alternatives()
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
}),
timestamps: joi.boolean(),
typescript: joi.object().keys({

View File

@@ -14,6 +14,7 @@ import type {
Endpoint,
EntityDescription,
GeneratePreviewURL,
LabelFunction,
LivePreviewConfig,
} from '../../config/types.js'
import type { Field } from '../../fields/config/types.js'
@@ -360,8 +361,8 @@ export type CollectionConfig = {
* Label configuration
*/
labels?: {
plural?: Record<string, string> | string
singular?: Record<string, string> | string
plural?: LabelFunction | Record<string, string> | string
singular?: LabelFunction | Record<string, string> | string
}
slug: string
/**

View File

@@ -34,6 +34,7 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
user?: Document
}
// eslint-disable-next-line no-restricted-exports
export default async function createLocal<TSlug extends keyof GeneratedTypes['collections']>(
payload: Payload,
options: Options<TSlug>,
@@ -58,7 +59,7 @@ export default async function createLocal<TSlug extends keyof GeneratedTypes['co
)
}
const req = createLocalReq(options, payload)
const req = await createLocalReq(options, payload)
req.file = file ?? (await getFileByPath(filePath))
return createOperation<TSlug>({

View File

@@ -50,7 +50,7 @@ export async function duplicate<TSlug extends keyof GeneratedTypes['collections'
)
}
const req = createLocalReq(options, payload)
const req = await createLocalReq(options, payload)
return duplicateOperation<TSlug>({
id,

View File

@@ -1,3 +1,5 @@
import type { TFunction } from '@payloadcms/translations'
import type { ClientCollectionConfig } from '../collections/config/client.js'
import type { SanitizedCollectionConfig } from '../collections/config/types.js'
import type { ClientGlobalConfig } from '../globals/config/client.js'
@@ -41,10 +43,13 @@ export type ClientConfig = Omit<
globals: ClientGlobalConfig[]
}
export const createClientConfig = async (
configPromise: Promise<SanitizedConfig> | SanitizedConfig,
): Promise<ClientConfig> => {
const config = await configPromise
export const createClientConfig = async ({
config,
t,
}: {
config: SanitizedConfig
t: TFunction
}): Promise<ClientConfig> => {
const clientConfig: ClientConfig = { ...config }
const serverOnlyConfigProperties: Partial<ServerOnlyRootProperties>[] = [
@@ -95,11 +100,15 @@ export const createClientConfig = async (
}
}
clientConfig.collections = createClientCollectionConfigs(
clientConfig.collections as SanitizedCollectionConfig[],
)
clientConfig.collections = createClientCollectionConfigs({
collections: clientConfig.collections as SanitizedCollectionConfig[],
t,
})
clientConfig.globals = createClientGlobalConfigs(clientConfig.globals as SanitizedGlobalConfig[])
clientConfig.globals = createClientGlobalConfigs({
globals: clientConfig.globals as SanitizedGlobalConfig[],
t,
})
return clientConfig
}

View File

@@ -1,4 +1,4 @@
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import merge from 'deepmerge'
import type {
@@ -87,8 +87,10 @@ export const sanitizeConfig = (incomingConfig: Config): SanitizedConfig => {
config.i18n = {
fallbackLanguage: 'en',
supportedLanguages: Object.keys(translations),
translations,
supportedLanguages: {
en,
},
translations: {},
...(incomingConfig?.i18n ?? {}),
}

View File

@@ -1,4 +1,4 @@
import type { I18nOptions } from '@payloadcms/translations'
import type { I18nOptions, TFunction } from '@payloadcms/translations'
import type { Options as ExpressFileUploadOptions } from 'express-fileupload'
import type GraphQL from 'graphql'
import type { Transporter } from 'nodemailer'
@@ -363,6 +363,8 @@ export type LocalizationConfig = Prettify<
LocalizationConfigWithLabels | LocalizationConfigWithNoLabels
>
export type LabelFunction = ({ t }: { t: TFunction }) => string
export type SharpDependency = (
input?:
| ArrayBuffer
@@ -671,11 +673,12 @@ export type Config = {
export type SanitizedConfig = Omit<
DeepRequired<Config>,
'collections' | 'endpoint' | 'globals' | 'localization'
'collections' | 'endpoint' | 'globals' | 'i18n' | 'localization'
> & {
collections: SanitizedCollectionConfig[]
endpoints: Endpoint[]
globals: SanitizedGlobalConfig[]
i18n: Required<I18nOptions>
localization: SanitizedLocalizationConfig | false
paths: {
config: string

View File

@@ -1,6 +1,6 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
class AuthenticationError extends APIError {
constructor(t?: TFunction) {
super(
t ? t('error:emailOrPasswordIncorrect') : translations.en.error.emailOrPasswordIncorrect,
t ? t('error:emailOrPasswordIncorrect') : en.translations.error.emailOrPasswordIncorrect,
httpStatus.UNAUTHORIZED,
)
}

View File

@@ -1,6 +1,6 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
class ErrorDeletingFile extends APIError {
constructor(t?: TFunction) {
super(
t ? t('error:deletingFile') : translations.en.error.deletingFile,
t ? t('error:deletingFile') : en.translations.error.deletingFile,
httpStatus.INTERNAL_SERVER_ERROR,
)
}

View File

@@ -1,6 +1,6 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
class FileUploadError extends APIError {
constructor(t?: TFunction) {
super(
t ? t('error:problemUploadingFile') : translations.en.error.problemUploadingFile,
t ? t('error:problemUploadingFile') : en.translations.error.problemUploadingFile,
httpStatus.BAD_REQUEST,
)
}

View File

@@ -1,6 +1,6 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
class Forbidden extends APIError {
constructor(t?: TFunction) {
super(
t ? t('error:notAllowedToPerformAction') : translations.en.error.notAllowedToPerformAction,
t ? t('error:notAllowedToPerformAction') : en.translations.error.notAllowedToPerformAction,
httpStatus.FORBIDDEN,
)
}

View File

@@ -1,13 +1,13 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
class LockedAuth extends APIError {
constructor(t?: TFunction) {
super(t ? t('error:userLocked') : translations.en.error.userLocked, httpStatus.UNAUTHORIZED)
super(t ? t('error:userLocked') : en.translations.error.userLocked, httpStatus.UNAUTHORIZED)
}
}

View File

@@ -1,6 +1,6 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
class MissingFile extends APIError {
constructor(t?: TFunction) {
super(
t ? t('error:noFilesUploaded') : translations.en.error.noFilesUploaded,
t ? t('error:noFilesUploaded') : en.translations.error.noFilesUploaded,
httpStatus.BAD_REQUEST,
)
}

View File

@@ -1,13 +1,13 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
class NotFound extends APIError {
constructor(t?: TFunction) {
super(t ? t('general:notFound') : translations.en.general.notFound, httpStatus.NOT_FOUND)
super(t ? t('general:notFound') : en.translations.general.notFound, httpStatus.NOT_FOUND)
}
}

View File

@@ -1,13 +1,13 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
class UnauthorizedError extends APIError {
constructor(t?: TFunction) {
super(t ? t('error:unauthorized') : translations.en.error.unauthorized, httpStatus.UNAUTHORIZED)
super(t ? t('error:unauthorized') : en.translations.error.unauthorized, httpStatus.UNAUTHORIZED)
}
}

View File

@@ -1,6 +1,6 @@
import type { TFunction } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import { en } from '@payloadcms/translations/languages/en'
import httpStatus from 'http-status'
import APIError from './APIError.js'
@@ -10,8 +10,8 @@ class ValidationError extends APIError<{ field: string; message: string }[]> {
const message = t
? t('error:followingFieldsInvalid', { count: results.length })
: results.length === 1
? translations.en.error.followingFieldsInvalid_one
: translations.en.error.followingFieldsInvalid_other
? en.translations.error.followingFieldsInvalid_one
: en.translations.error.followingFieldsInvalid_other
super(`${message} ${results.map((f) => f.field).join(', ')}`, httpStatus.BAD_REQUEST, results)
}

View File

@@ -1 +1,2 @@
export { generateTypes } from '../bin/generateTypes.js'
export { importConfig, importWithoutClientFiles } from '../utilities/importWithoutClientFiles.js'

View File

@@ -2,7 +2,6 @@ export { getDataLoader } from '../collections/dataloader.js'
export { default as getDefaultValue } from '../fields/getDefaultValue.js'
export { promise as afterReadPromise } from '../fields/hooks/afterRead/promise.js'
export { traverseFields as afterReadTraverseFields } from '../fields/hooks/afterRead/traverseFields.js'
export { extractTranslations } from '../translations/extractTranslations.js'
export { formatFilesize } from '../uploads/formatFilesize.js'

View File

@@ -1,3 +1,5 @@
import type { TFunction } from '@payloadcms/translations'
import type { Field, FieldBase } from '../../fields/config/types.js'
export type ClientFieldConfig = Omit<Field, 'access' | 'defaultValue' | 'hooks' | 'validate'>
@@ -13,8 +15,14 @@ export type ServerOnlyFieldAdminProperties = keyof Pick<
'components' | 'condition' | 'description'
>
export const createClientFieldConfig = (f: Field) => {
const field = { ...f }
export const createClientFieldConfig = ({
field: incomingField,
t,
}: {
field: Field
t: TFunction
}) => {
const field = { ...incomingField }
const serverOnlyFieldProperties: Partial<ServerOnlyFieldProperties>[] = [
'hooks',
@@ -37,21 +45,34 @@ export const createClientFieldConfig = (f: Field) => {
}
})
if ('options' in field && Array.isArray(field.options)) {
field.options = field.options.map((option) => {
if (typeof option === 'object' && typeof option.label === 'function') {
return {
label: option.label({ t }),
value: option.value,
}
}
return option
})
}
if ('fields' in field) {
field.fields = createClientFieldConfigs(field.fields)
field.fields = createClientFieldConfigs({ fields: field.fields, t })
}
if ('blocks' in field) {
field.blocks = field.blocks.map((block) => {
const sanitized = { ...block }
sanitized.fields = createClientFieldConfigs(sanitized.fields)
sanitized.fields = createClientFieldConfigs({ fields: sanitized.fields, t })
return sanitized
})
}
if ('tabs' in field) {
// @ts-expect-error
field.tabs = field.tabs.map((tab) => createClientFieldConfig(tab))
field.tabs = field.tabs.map((tab) => createClientFieldConfig({ field: tab, t }))
}
if ('admin' in field) {
@@ -73,5 +94,10 @@ export const createClientFieldConfig = (f: Field) => {
return field
}
export const createClientFieldConfigs = (fields: Field[]): Field[] =>
fields.map(createClientFieldConfig)
export const createClientFieldConfigs = ({
fields,
t,
}: {
fields: Field[]
t: TFunction
}): Field[] => fields.map((field) => createClientFieldConfig({ field, t }))

View File

@@ -52,7 +52,12 @@ export const baseField = joi
index: joi.boolean().default(false),
label: joi
.alternatives()
.try(joi.object().pattern(joi.string(), [joi.string()]), joi.string(), joi.valid(false)),
.try(
joi.func(),
joi.object().pattern(joi.string(), [joi.string()]),
joi.string(),
joi.valid(false),
),
localized: joi.boolean().default(false),
required: joi.boolean().default(false),
saveToJWT: joi.alternatives().try(joi.boolean(), joi.string()).default(false),
@@ -216,7 +221,7 @@ export const select = baseField.keys({
joi.object({
label: joi
.alternatives()
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
value: joi.string().required().allow(''),
}),
),
@@ -245,7 +250,7 @@ export const radio = baseField.keys({
joi.object({
label: joi
.alternatives()
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()]))
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()]))
.required(),
value: joi.string().required().allow(''),
}),

View File

@@ -17,6 +17,7 @@ import type {
} from '../../admin/types.js'
import type { User } from '../../auth/index.js'
import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'
import type { LabelFunction } from '../../config/types.js'
import type { DBIdentifierName } from '../../database/types.js'
import type { SanitizedGlobalConfig } from '../../globals/config/types.js'
import type { Operation, PayloadRequest, RequestContext, Where } from '../../types/index.js'
@@ -134,8 +135,8 @@ type Admin = {
}
export type Labels = {
plural: Record<string, string> | string
singular: Record<string, string> | string
plural: LabelFunction | Record<string, string> | string
singular: LabelFunction | Record<string, string> | string
}
export type BaseValidateOptions<TData, TSiblingData> = {
@@ -165,7 +166,7 @@ export type Validate<
export type ClientValidate = Omit<Validate, 'req'>
export type OptionObject = {
label: Record<string, string> | string
label: LabelFunction | Record<string, string> | string
value: string
}
@@ -193,7 +194,7 @@ export interface FieldBase {
beforeValidate?: FieldHook[]
}
index?: boolean
label?: Record<string, string> | false | string
label?: LabelFunction | Record<string, string> | false | string
localized?: boolean
name: string
required?: boolean
@@ -394,6 +395,7 @@ export type UnnamedTab = Omit<TabBase, 'name'> & {
| {
[selectedLanguage: string]: string
}
| LabelFunction
| string
localized?: never
}

View File

@@ -1,16 +1,12 @@
// default beforeDuplicate hook for required and unique fields
import type { FieldAffectingData, FieldHook } from './config/types.js'
import { extractTranslations } from '../translations/extractTranslations.js'
const copyTranslations = extractTranslations(['general:copy'])
const unique: FieldHook = ({ value }) => (typeof value === 'string' ? `${value} - Copy` : undefined)
const localizedUnique: FieldHook = ({ req, value }) =>
value ? `${value} - ${copyTranslations?.[req.locale]?.['general:copy'] ?? 'Copy'}` : undefined
value ? `${value} - ${req?.t('general:copy') ?? 'Copy'}` : undefined
const uniqueRequired: FieldHook = ({ value }) => `${value} - Copy`
const localizedUniqueRequired: FieldHook = ({ req, value }) =>
`${value} - ${copyTranslations?.[req.locale]?.['general:copy'] ?? 'Copy'}`
`${value} - ${req?.t('general:copy') ?? 'Copy'}`
export const setDefaultBeforeDuplicate = (field: FieldAffectingData) => {
if (

View File

@@ -1,3 +1,5 @@
import type { TFunction } from '@payloadcms/translations'
import type {
LivePreviewConfig,
SanitizedConfig,
@@ -30,11 +32,15 @@ export type ClientGlobalConfig = Omit<
fields: ClientFieldConfig[]
}
export const createClientGlobalConfig = (
global: SanitizedConfig['globals'][0],
): ClientGlobalConfig => {
export const createClientGlobalConfig = ({
global,
t,
}: {
global: SanitizedConfig['globals'][0]
t: TFunction
}): ClientGlobalConfig => {
const sanitized = { ...global }
sanitized.fields = createClientFieldConfigs(sanitized.fields)
sanitized.fields = createClientFieldConfigs({ fields: sanitized.fields, t })
const serverOnlyProperties: Partial<ServerOnlyGlobalProperties>[] = [
'hooks',
@@ -73,6 +79,10 @@ export const createClientGlobalConfig = (
return sanitized
}
export const createClientGlobalConfigs = (
globals: SanitizedConfig['globals'],
): ClientGlobalConfig[] => globals.map((global) => createClientGlobalConfig(global))
export const createClientGlobalConfigs = ({
globals,
t,
}: {
globals: SanitizedConfig['globals']
t: TFunction
}): ClientGlobalConfig[] => globals.map((global) => createClientGlobalConfig({ global, t }))

View File

@@ -1,5 +1,3 @@
import { extractTranslations } from 'payload/utilities'
import type { Config } from '../../config/types.js'
import type { SanitizedGlobalConfig } from './types.js'
@@ -10,8 +8,6 @@ import mergeBaseFields from '../../fields/mergeBaseFields.js'
import { toWords } from '../../utilities/formatLabels.js'
import baseVersionFields from '../../versions/baseFields.js'
const translations = extractTranslations(['general:createdAt', 'general:updatedAt'])
const sanitizeGlobals = (config: Config): SanitizedGlobalConfig[] => {
const { collections, globals } = config
@@ -80,7 +76,7 @@ const sanitizeGlobals = (config: Config): SanitizedGlobalConfig[] => {
disableBulkEdit: true,
hidden: true,
},
label: translations['general:updatedAt'],
label: ({ t }) => t('general:updatedAt'),
})
}
if (!hasCreatedAt) {
@@ -91,7 +87,7 @@ const sanitizeGlobals = (config: Config): SanitizedGlobalConfig[] => {
disableBulkEdit: true,
hidden: true,
},
label: translations['general:createdAt'],
label: ({ t }) => t('general:createdAt'),
})
}

View File

@@ -65,7 +65,9 @@ const globalSchema = joi
beforeRead: joi.array().items(joi.func()),
beforeValidate: joi.array().items(joi.func()),
}),
label: joi.alternatives().try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
label: joi
.alternatives()
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
typescript: joi.object().keys({
interface: joi.string(),
}),

View File

@@ -20,6 +20,7 @@ export type Options<T extends keyof GeneratedTypes['globals']> = {
user?: Document
}
// eslint-disable-next-line no-restricted-exports
export default async function findVersionByIDLocal<T extends keyof GeneratedTypes['globals']>(
payload: Payload,
options: Options<T>,

View File

@@ -1,19 +0,0 @@
import { translations } from '@payloadcms/translations/api'
export const extractTranslations = (keys: string[]): Record<string, Record<string, string>> => {
const result = {}
keys.forEach((key) => {
result[key] = {}
})
Object.entries(translations).forEach(([language, resource]) => {
keys.forEach((key) => {
const [section, target] = key.split(':')
if (resource?.[section]?.[target]) {
result[key][language] = resource[section][target]
} else {
// console.error(`Missing translation for ${key} in ${language}`)
}
})
})
return result
}

View File

@@ -1,18 +1,18 @@
import type { AcceptedLanguages } from '@payloadcms/translations'
import { initI18n } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
import type { SanitizedConfig } from '../config/types.js'
export const getLocalI18n = ({
export const getLocalI18n = async ({
config,
language = 'en',
}: {
config: SanitizedConfig
language?: string
language?: AcceptedLanguages
}) =>
initI18n({
config: config.i18n,
context: 'api',
language,
translations,
})

View File

@@ -3,17 +3,8 @@ import type { Config } from '../config/types.js'
import type { Field } from '../fields/config/types.js'
import type { UploadConfig } from './types.js'
import { extractTranslations } from '../translations/extractTranslations.js'
import { mimeTypeValidator } from './mimeTypeValidator.js'
const labels = extractTranslations([
'upload:width',
'upload:height',
'upload:fileSize',
'upload:fileName',
'upload:sizes',
])
type GenerateURLArgs = {
collectionSlug: string
config: Config
@@ -87,7 +78,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
hidden: true,
readOnly: true,
},
label: labels['upload:width'],
label: ({ t }) => t('upload:width'),
}
const height: Field = {
@@ -97,7 +88,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
hidden: true,
readOnly: true,
},
label: labels['upload:height'],
label: ({ t }) => t('upload:height'),
}
const filesize: Field = {
@@ -107,7 +98,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
hidden: true,
readOnly: true,
},
label: labels['upload:fileSize'],
label: ({ t }) => t('upload:fileSize'),
}
const filename: Field = {
@@ -119,7 +110,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
readOnly: true,
},
index: true,
label: labels['upload:fileName'],
label: ({ t }) => t('upload:fileName'),
unique: true,
}
@@ -201,7 +192,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
],
label: size.name,
})),
label: labels['upload:Sizes'],
label: ({ t }) => t('upload:Sizes'),
},
])
}

View File

@@ -63,12 +63,12 @@ type CreateLocalReq = (
user?: User
},
payload: Payload,
) => PayloadRequest
export const createLocalReq: CreateLocalReq = (
) => Promise<PayloadRequest>
export const createLocalReq: CreateLocalReq = async (
{ context, fallbackLocale, locale: localeArg, req = {} as PayloadRequest, user },
payload,
) => {
const i18n = req?.i18n || getLocalI18n({ config: payload.config })
const i18n = req?.i18n || (await getLocalI18n({ config: payload.config }))
if (payload.config?.localization) {
const locale = localeArg === '*' ? 'all' : localeArg

View File

@@ -1,16 +1,12 @@
import type { Field } from '../fields/config/types.js'
import { extractTranslations } from '../translations/extractTranslations.js'
const labels = extractTranslations(['version:draft', 'version:published', 'version:status'])
export const statuses = [
{
label: labels['version:draft'],
label: ({ t }) => t('version:draft'),
value: 'draft',
},
{
label: labels['version:published'],
label: ({ t }) => t('version:published'),
value: 'published',
},
]
@@ -26,7 +22,7 @@ const baseVersionFields: Field[] = [
disableBulkEdit: true,
},
defaultValue: 'draft',
label: labels['version:status'],
label: ({ t }) => t('version:status'),
options: statuses,
},
]

View File

@@ -1,2 +1,2 @@
export { getFileByPath } from './dist/uploads/getFileByPath.js'
//# sourceMappingURL=uploads.d.ts.map
export { getFileByPath } from './dist/uploads/getFileByPath.js';
//# sourceMappingURL=uploads.d.ts.map

View File

@@ -1,3 +1,3 @@
export { getFileByPath } from './dist/uploads/getFileByPath.js'
export { getFileByPath } from './dist/uploads/getFileByPath.js';
//# sourceMappingURL=uploads.js.map
//# sourceMappingURL=uploads.js.map

View File

@@ -1,7 +1,7 @@
{
"name": "@payloadcms/plugin-cloud-storage",
"description": "The official cloud storage plugin for Payload CMS",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"main": "./src/index.ts",
"types": "./src/index.ts",
"type": "module",

View File

@@ -1,7 +1,7 @@
{
"name": "@payloadcms/plugin-cloud",
"description": "The official Payload Cloud plugin",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"main": "./src/index.ts",
"types": "./src/index.ts",
"license": "MIT",

View File

@@ -1,7 +1,7 @@
{
"name": "@payloadcms/plugin-form-builder",
"description": "Form builder plugin for Payload CMS",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"homepage:": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"description": "The official Nested Docs plugin for Payload",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-redirects",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"homepage:": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-search",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"homepage:": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-seo",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"homepage:": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "3.0.0-alpha.59",
"version": "3.0.0-alpha.61",
"description": "The officially supported Lexical richtext adapter for Payload",
"repository": {
"type": "git",

Some files were not shown because too many files have changed in this diff Show More