Skip to content
Closed
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
9ef5c9a
fix: adds enableStatusLocalization option to reflects current locale …
jessrynkar Jul 17, 2025
6ac13f4
fix: add enableStatusLocalization support for postgres
jessrynkar Jul 17, 2025
9c3316e
chore: make localeStatus an optional property
jessrynkar Jul 17, 2025
32bfb7b
chore: make localeStatus an optional property again
jessrynkar Jul 17, 2025
b5185bb
chore: feedback changes
jessrynkar Aug 5, 2025
403bf5b
chore: merge conflicts
jessrynkar Aug 5, 2025
035ff38
fix: update status component
jessrynkar Aug 8, 2025
d885f07
Merge branch 'main' into fix/localized-status-UI
jessrynkar Aug 11, 2025
35471fc
fix: apply locale specific status to draft if available
jessrynkar Aug 12, 2025
75f9d99
chore: revert error thrown when adding locale status fields
jessrynkar Aug 12, 2025
1b71d69
chore: remove log and fix tests
jessrynkar Aug 13, 2025
8a9caef
Merge branch 'main' into fix/localized-status-UI
jessrynkar Aug 13, 2025
b2becb8
chore: update localization.enableStatusLocalization to experimental.l…
jessrynkar Aug 14, 2025
51f1c99
Merge branch 'main' into fix/localized-status-UI
jessrynkar Aug 14, 2025
b5ea211
chore: update localizeStatus option verbiage in docs
jessrynkar Aug 14, 2025
8996a31
Merge branch 'main' into fix/localized-status-UI
jessrynkar Aug 15, 2025
7425b04
feat: adds experimental.allLocaleStatus flag to add new group status …
jessrynkar Aug 19, 2025
54f444f
chore: updates docs to add experimental.allLocaleStatus
jessrynkar Aug 19, 2025
961355e
Merge branch 'main' into fix/localized-status-UI
jessrynkar Aug 19, 2025
cef081c
chore: separates experimental from localization in createClientConfig
jessrynkar Aug 19, 2025
903d235
chore: update createClientConfig to remove unnecessary if statement
jessrynkar Aug 19, 2025
d8eabd1
Merge branch 'fix/localized-status-UI' into feat/all-locale-status
jessrynkar Aug 19, 2025
eb8a925
chore: fix typo in createClientConfig
jessrynkar Aug 19, 2025
5ef49cf
add default experimental object
JarrodMFlesch Aug 19, 2025
29f4b8e
Merge branch 'fix/localized-status-UI' into feat/all-locale-status
jessrynkar Aug 27, 2025
ee8933f
chore: merge conflicts
jessrynkar Sep 5, 2025
04d5d43
Merge branch 'main' into feat/all-locale-status
jessrynkar Sep 18, 2025
fcfcd56
chore: improve localeStatus query performance and rename field
jessrynkar Sep 18, 2025
1e8df7a
chore: feedback updates
jessrynkar Sep 19, 2025
7595b05
chore: merge conflicts
jessrynkar Sep 19, 2025
33f6ebb
fix: only add the allLocaleStatus field to versioned collections
JarrodMFlesch Sep 23, 2025
818d26f
clean up saveVersion looping
JarrodMFlesch Sep 23, 2025
8ee892a
rm duplicative type
JarrodMFlesch Sep 23, 2025
cf9a15e
assign to shared localStatus
JarrodMFlesch Sep 23, 2025
9872d24
simplify react code
JarrodMFlesch Sep 23, 2025
1405877
fix var naming
JarrodMFlesch Sep 24, 2025
0348d5b
removes unnecessary optional chaining
JarrodMFlesch Sep 24, 2025
1a942e5
moves version read logic to server component, out of hooks
JarrodMFlesch Sep 24, 2025
3353a8c
localize label
JarrodMFlesch Sep 24, 2025
efd75cb
Merge branch 'main' into feat/all-locale-status
JarrodMFlesch Sep 24, 2025
374d3b5
update translations
JarrodMFlesch Sep 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/configuration/localization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,10 @@ export default buildConfig({

The following experimental options are available related to localization:

| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| Option | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| **`allLocaleStatus`** | **Boolean.** When `true`, adds an `_allLocaleStatus` field that stores the status of each locale. In list views, this field is rendered as a custom cell with colored status pills. Defaults to `false`. |

## Field Localization

Expand Down
7 changes: 4 additions & 3 deletions docs/experimental/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ const config = buildConfig({

The following options are available:

| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| Option | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| **`allLocaleStatus`** | **Boolean.** When `true`, adds an `_allLocaleStatus` field that stores the status of each locale. In list views, this field is rendered as a custom cell with colored status pills. Defaults to `false`. |

This list may change without notice.

Expand Down
5 changes: 5 additions & 0 deletions packages/payload/src/collections/config/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 4 additions & 0 deletions packages/payload/src/config/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ export const createClientConfig = ({
if (config.experimental?.localizeStatus) {
clientConfig.experimental.localizeStatus = config.experimental.localizeStatus
}

if (config.experimental?.allLocaleStatus) {
clientConfig.experimental.allLocaleStatus = config.experimental.allLocaleStatus
}
}

break
Expand Down
9 changes: 9 additions & 0 deletions packages/payload/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,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
}

Expand Down
38 changes: 38 additions & 0 deletions packages/payload/src/fields/baseFields/baseAllLocaleStatusField.ts
Original file line number Diff line number Diff line change
@@ -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',
},
]
2 changes: 1 addition & 1 deletion packages/payload/src/versions/buildCollectionFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const buildVersionCollectionFields = <T extends boolean = false>(
}),
})

if (config.experimental?.localizeStatus) {
if (config.experimental?.localizeStatus || config.experimental?.allLocaleStatus) {
const localeStatusFields = buildLocaleStatusField(config)

fields.push({
Expand Down
2 changes: 1 addition & 1 deletion packages/payload/src/versions/buildGlobalFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const buildVersionGlobalFields = <T extends boolean = false>(
}),
})

if (config.experimental.localizeStatus) {
if (config.experimental.localizeStatus || config.experimental?.allLocaleStatus) {
const localeStatusFields = buildLocaleStatusField(config)

fields.push({
Expand Down
3 changes: 2 additions & 1 deletion packages/payload/src/versions/saveVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) ||
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<div className={baseClass}>
{Object.entries(localesToRender).map(([locale, status]) => (
<Pill key={locale} pillStyle={status === 'published' ? 'success' : 'light-gray'} size="small">
{locale}
</Pill>
))}
</div>
)
}
10 changes: 10 additions & 0 deletions packages/ui/src/elements/Status/AllLocaleStatusCell/index.scss
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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 (
<AllLocaleStatusCellClient
availableLocales={availableLocales}
data={cellData}
/>
)
}
1 change: 1 addition & 0 deletions packages/ui/src/exports/rsc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
1 change: 1 addition & 0 deletions test/localization/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ export default buildConfigWithDefaults({
],
experimental: {
localizeStatus: true,
allLocaleStatus: true,
},
localization: {
filterAvailableLocales: ({ locales }) => {
Expand Down
Loading