diff --git a/packages/payload/src/collections/config/sanitize.ts b/packages/payload/src/collections/config/sanitize.ts index 617d8cdb0d..603a149e9b 100644 --- a/packages/payload/src/collections/config/sanitize.ts +++ b/packages/payload/src/collections/config/sanitize.ts @@ -9,6 +9,7 @@ import type { import { authCollectionEndpoints } from '../../auth/endpoints/index.js' import { getBaseAuthFields } from '../../auth/getAuthFields.js' import { TimestampsRequired } from '../../errors/TimestampsRequired.js' +import { baseAllLocaleStatusField } from '../../fields/baseFields/baseAllLocaleStatusField.js' import { sanitizeFields } from '../../fields/config/sanitize.js' import { fieldAffectsData } from '../../fields/config/types.js' import { mergeBaseFields } from '../../fields/mergeBaseFields.js' @@ -256,6 +257,10 @@ export const sanitizeCollection = async ( sanitized.fields = mergeBaseFields(sanitized.fields, getBaseAuthFields(sanitized.auth)) } + if (config.experimental?.allLocaleStatus) { + sanitized.fields = mergeBaseFields(sanitized.fields, baseAllLocaleStatusField) + } + if (collection?.admin?.pagination?.limits?.length) { sanitized.admin!.pagination!.limits = collection.admin.pagination.limits } diff --git a/packages/payload/src/config/client.ts b/packages/payload/src/config/client.ts index aa22cebfd8..3e86a65eee 100644 --- a/packages/payload/src/config/client.ts +++ b/packages/payload/src/config/client.ts @@ -158,6 +158,21 @@ export const createClientConfig = ({ break + case 'experiental': + if (config.experimental) { + if (!clientConfig.experimental) { + clientConfig.experimental = {} + } + if (config.experimental?.localizeStatus) { + clientConfig.experimental.localizeStatus = config.experimental.localizeStatus + } + if (config.experimental?.allLocaleStatus) { + clientConfig.experimental.allLocaleStatus = config.experimental.allLocaleStatus + } + } + + break + case 'folders': if (config.folders) { clientConfig.folders = { @@ -193,13 +208,6 @@ export const createClientConfig = ({ config.localization.defaultLocalePublishOption } - if (config.experimental?.localizeStatus) { - if (!clientConfig.experimental) { - clientConfig.experimental = {} - } - clientConfig.experimental.localizeStatus = config.experimental.localizeStatus - } - if (config.localization.fallback) { clientConfig.localization.fallback = config.localization.fallback } diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index ab9f665d08..6705d3fb9c 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -725,6 +725,15 @@ export type ImportMapGenerators = Array< * These may be unstable and may change or be removed in future releases. */ export type ExperimentalConfig = { + /** + * Adds `_allLocaleStatus` group field which maintains the statuses of all locales. + * @default false + */ + allLocaleStatus?: boolean + /** + * Returns status of the current locale instead of overall document. + * @default false + */ localizeStatus?: boolean } diff --git a/packages/payload/src/fields/baseFields/baseAllLocaleStatusField.ts b/packages/payload/src/fields/baseFields/baseAllLocaleStatusField.ts new file mode 100644 index 0000000000..38efc1439b --- /dev/null +++ b/packages/payload/src/fields/baseFields/baseAllLocaleStatusField.ts @@ -0,0 +1,38 @@ +import type { Field } from '../config/types.js' + +export const baseAllLocaleStatusField: Field[] = [ + { + name: '_allLocaleStatus', + type: 'json', + admin: { + components: { + Cell: '@payloadcms/ui/rsc#AllLocaleStatusCell', + }, + hidden: true, + }, + hooks: { + afterRead: [ + async (args) => { + const { collection, data, req } = args + const id = data?.id + if (id && collection && collection.versions) { + const version = await req.payload.findVersions({ + collection: collection.slug, + limit: 1, + where: { + parent: { + equals: id, + }, + }, + }) + + if (version.docs && version.docs[0]?.localeStatus) { + return version.docs[0].localeStatus + } + } + }, + ], + }, + label: 'Status - All Locales', + }, +] diff --git a/packages/payload/src/versions/buildCollectionFields.ts b/packages/payload/src/versions/buildCollectionFields.ts index f047373f85..26dce85a43 100644 --- a/packages/payload/src/versions/buildCollectionFields.ts +++ b/packages/payload/src/versions/buildCollectionFields.ts @@ -63,7 +63,7 @@ export const buildVersionCollectionFields = ( }), }) - if (config.experimental?.localizeStatus) { + if (config.experimental?.localizeStatus || config.experimental?.allLocaleStatus) { const localeStatusFields = buildLocaleStatusField(config) fields.push({ diff --git a/packages/payload/src/versions/buildGlobalFields.ts b/packages/payload/src/versions/buildGlobalFields.ts index b9675ddbd0..e9efb6b983 100644 --- a/packages/payload/src/versions/buildGlobalFields.ts +++ b/packages/payload/src/versions/buildGlobalFields.ts @@ -57,7 +57,7 @@ export const buildVersionGlobalFields = ( }), }) - if (config.experimental.localizeStatus) { + if (config.experimental.localizeStatus || config.experimental?.allLocaleStatus) { const localeStatusFields = buildLocaleStatusField(config) fields.push({ diff --git a/packages/payload/src/versions/saveVersion.ts b/packages/payload/src/versions/saveVersion.ts index d101aa05ca..57fd4971cd 100644 --- a/packages/payload/src/versions/saveVersion.ts +++ b/packages/payload/src/versions/saveVersion.ts @@ -137,7 +137,8 @@ export const saveVersion = async ({ if ( localizationEnabled && payload.config.localization !== false && - payload.config.experimental?.localizeStatus + (payload.config.experimental?.localizeStatus || + payload.config.experimental?.allLocaleStatus) ) { const allLocales = ( (payload.config.localization && payload.config.localization?.locales) || diff --git a/packages/ui/src/elements/Status/AllLocaleStatusCell/index.client.tsx b/packages/ui/src/elements/Status/AllLocaleStatusCell/index.client.tsx new file mode 100644 index 0000000000..017c98078d --- /dev/null +++ b/packages/ui/src/elements/Status/AllLocaleStatusCell/index.client.tsx @@ -0,0 +1,35 @@ +'use client' + +import type { Data } from 'payload' + +import React from 'react' + +import { Pill } from '../../Pill/index.js' +import './index.scss' + +type Props = { + readonly availableLocales: string[] + readonly data: Data +} + +const baseClass = 'locale-status-cell' + +export const AllLocaleStatusCellClient = ({ availableLocales, data }: Props) => { + const localesToRender = Object.fromEntries( + Object.entries(data).filter(([key]) => availableLocales.includes(key)) + ) + + if (Object.keys(localesToRender).length === 0) { + return null + } + + return ( +
+ {Object.entries(localesToRender).map(([locale, status]) => ( + + {locale} + + ))} +
+ ) +} diff --git a/packages/ui/src/elements/Status/AllLocaleStatusCell/index.scss b/packages/ui/src/elements/Status/AllLocaleStatusCell/index.scss new file mode 100644 index 0000000000..fa047e2720 --- /dev/null +++ b/packages/ui/src/elements/Status/AllLocaleStatusCell/index.scss @@ -0,0 +1,10 @@ +@import '../../../scss/styles.scss'; + +@layer payload-default { + .locale-status-cell { + display: flex; + align-items: center; + gap: calc(var(--base) / 2); + flex-wrap: wrap; + } +} diff --git a/packages/ui/src/elements/Status/AllLocaleStatusCell/index.server.tsx b/packages/ui/src/elements/Status/AllLocaleStatusCell/index.server.tsx new file mode 100644 index 0000000000..247acecd17 --- /dev/null +++ b/packages/ui/src/elements/Status/AllLocaleStatusCell/index.server.tsx @@ -0,0 +1,29 @@ +import { createLocalReq, type DefaultServerCellComponentProps } from 'payload' +import React from 'react' + +import { AllLocaleStatusCellClient } from './index.client.js' + +export const AllLocaleStatusCell = async ({ cellData, payload }: DefaultServerCellComponentProps) => { + const { localization } = payload.config + const req = await createLocalReq({}, payload) + + let availableLocales: string[] = [] + + + if (localization) { + const filtered = + (await localization.filterAvailableLocales?.({ + locales: localization.locales, + req, + })) ?? localization.locales + + availableLocales = filtered.map((locale) => locale.code) + } + + return ( + + ) +} diff --git a/packages/ui/src/exports/rsc/index.ts b/packages/ui/src/exports/rsc/index.ts index 155cd026fe..7537bd64a4 100644 --- a/packages/ui/src/exports/rsc/index.ts +++ b/packages/ui/src/exports/rsc/index.ts @@ -3,6 +3,7 @@ export { FieldDiffLabel } from '../../elements/FieldDiffLabel/index.js' export { FolderTableCell } from '../../elements/FolderView/Cell/index.server.js' export { FolderField } from '../../elements/FolderView/FolderField/index.server.js' export { getHTMLDiffComponents } from '../../elements/HTMLDiff/index.js' +export { AllLocaleStatusCell } from '../../elements/Status/AllLocaleStatusCell/index.server.js' export { File } from '../../graphics/File/index.js' export { CheckIcon } from '../../icons/Check/index.js' export { copyDataFromLocaleHandler } from '../../utilities/copyDataFromLocale.js' diff --git a/test/localization/config.ts b/test/localization/config.ts index 8389526a37..9f056cf2e2 100644 --- a/test/localization/config.ts +++ b/test/localization/config.ts @@ -430,6 +430,7 @@ export default buildConfigWithDefaults({ ], experimental: { localizeStatus: true, + allLocaleStatus: true, }, localization: { filterAvailableLocales: ({ locales }) => {