Skip to content

Commit ac691b6

Browse files
fix(ui): should not show publish specific locale button when no localized fields exist (#13459)
### What? Hides the `Publish in [specific locale]` button on collections and globals when no localized fields are present. ### Why? Currently, the `Publish in [specific locale]` shows on every collection/global as long as `localization` is enabled in the Payload config, however this is not necessary when the collection/global has no localized fields. ### How? Checks that localized fields exist prior to rendering the `Publish in [specific locale]` button. Fixes #13447 --------- Co-authored-by: German Jablonski <[email protected]>
1 parent fdab271 commit ac691b6

File tree

4 files changed

+71
-3
lines changed

4 files changed

+71
-3
lines changed

packages/ui/src/elements/PublishButton/index.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { PublishButtonClientProps } from 'payload'
44

55
import { useModal } from '@faceless-ui/modal'
66
import * as qs from 'qs-esm'
7-
import React, { useCallback } from 'react'
7+
import React, { useCallback, useEffect, useState } from 'react'
88

99
import { useForm, useFormModified } from '../../forms/Form/context.js'
1010
import { FormSubmit } from '../../forms/Submit/index.js'
@@ -15,6 +15,7 @@ import { useEditDepth } from '../../providers/EditDepth/index.js'
1515
import { useLocale } from '../../providers/Locale/index.js'
1616
import { useOperation } from '../../providers/Operation/index.js'
1717
import { useTranslation } from '../../providers/Translation/index.js'
18+
import { traverseForLocalizedFields } from '../../utilities/traverseForLocalizedFields.js'
1819
import { PopupList } from '../Popup/index.js'
1920
import { ScheduleDrawer } from './ScheduleDrawer/index.js'
2021

@@ -86,6 +87,15 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
8687
(hasAutosave || !modified),
8788
)
8889

90+
const [hasLocalizedFields, setHasLocalizedFields] = useState(false)
91+
92+
useEffect(() => {
93+
const hasLocalizedField = traverseForLocalizedFields(entityConfig?.fields)
94+
setHasLocalizedFields(hasLocalizedField)
95+
}, [entityConfig?.fields])
96+
97+
const canPublishSpecificLocale = localization && hasLocalizedFields && hasPublishPermission
98+
8999
const operation = useOperation()
90100

91101
const disabled = operation === 'update' && !modified
@@ -213,7 +223,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
213223
onClick={defaultPublish}
214224
size="medium"
215225
SubMenuPopupContent={
216-
localization || canSchedulePublish
226+
canPublishSpecificLocale || canSchedulePublish
217227
? ({ close }) => {
218228
return (
219229
<React.Fragment>
@@ -227,7 +237,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
227237
</PopupList.Button>
228238
</PopupList.ButtonGroup>
229239
)}
230-
{localization && canPublish && (
240+
{canPublishSpecificLocale && (
231241
<PopupList.ButtonGroup>
232242
<PopupList.Button id="publish-locale" onClick={secondaryPublish}>
233243
{secondaryLabel}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { ClientField } from 'payload'
2+
3+
export const traverseForLocalizedFields = (fields: ClientField[]): boolean => {
4+
for (const field of fields) {
5+
if ('localized' in field && field.localized) {
6+
return true
7+
}
8+
9+
switch (field.type) {
10+
case 'array':
11+
case 'collapsible':
12+
case 'group':
13+
case 'row':
14+
if (field.fields && traverseForLocalizedFields(field.fields)) {
15+
return true
16+
}
17+
break
18+
19+
case 'blocks':
20+
if (field.blocks) {
21+
for (const block of field.blocks) {
22+
if (block.fields && traverseForLocalizedFields(block.fields)) {
23+
return true
24+
}
25+
}
26+
}
27+
break
28+
29+
case 'tabs':
30+
if (field.tabs) {
31+
for (const tab of field.tabs) {
32+
if ('localized' in tab && tab.localized) {
33+
return true
34+
}
35+
if ('fields' in tab && tab.fields && traverseForLocalizedFields(tab.fields)) {
36+
return true
37+
}
38+
}
39+
}
40+
break
41+
}
42+
}
43+
44+
return false
45+
}

test/localization/collections/NoLocalizedFields/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ export const noLocalizedFieldsCollectionSlug = 'no-localized-fields'
44

55
export const NoLocalizedFieldsCollection: CollectionConfig = {
66
slug: noLocalizedFieldsCollectionSlug,
7+
versions: {
8+
drafts: true,
9+
},
710
fields: [
811
{
912
name: 'text',

test/localization/e2e.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
2929
import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js'
3030
import { arrayCollectionSlug } from './collections/Array/index.js'
3131
import { nestedToArrayAndBlockCollectionSlug } from './collections/NestedToArrayAndBlock/index.js'
32+
import { noLocalizedFieldsCollectionSlug } from './collections/NoLocalizedFields/index.js'
3233
import { richTextSlug } from './collections/RichText/index.js'
3334
import {
3435
arrayWithFallbackCollectionSlug,
@@ -61,6 +62,7 @@ let urlCannotCreateDefaultLocale: AdminUrlUtil
6162
let urlPostsWithDrafts: AdminUrlUtil
6263
let urlArray: AdminUrlUtil
6364
let arrayWithFallbackURL: AdminUrlUtil
65+
let noLocalizedFieldsURL: AdminUrlUtil
6466

6567
const title = 'english title'
6668
const spanishTitle = 'spanish title'
@@ -87,6 +89,7 @@ describe('Localization', () => {
8789
urlPostsWithDrafts = new AdminUrlUtil(serverURL, localizedDraftsSlug)
8890
urlArray = new AdminUrlUtil(serverURL, arrayCollectionSlug)
8991
arrayWithFallbackURL = new AdminUrlUtil(serverURL, arrayWithFallbackCollectionSlug)
92+
noLocalizedFieldsURL = new AdminUrlUtil(serverURL, noLocalizedFieldsCollectionSlug)
9093

9194
context = await browser.newContext()
9295
page = await context.newPage()
@@ -671,6 +674,13 @@ describe('Localization', () => {
671674
await expect(page.locator('#field-title')).toBeEmpty()
672675
})
673676
})
677+
678+
test('should not show publish specific locale button when no localized fields exist', async () => {
679+
await page.goto(urlPostsWithDrafts.create)
680+
await expect(page.locator('#publish-locale')).toHaveCount(1)
681+
await page.goto(noLocalizedFieldsURL.create)
682+
await expect(page.locator('#publish-locale')).toHaveCount(0)
683+
})
674684
})
675685

676686
async function createLocalizedArrayItem(page: Page, url: AdminUrlUtil) {

0 commit comments

Comments
 (0)