Skip to content

Commit caf68e4

Browse files
authored
fix(ui): publish button shows locale-specific text without localized fields (#14690)
### What? Updates the publish button logic to check whether a collection/global has localized fields before displaying locale-specific button text ("Publish in [locale]"). The button now only shows locale-specific text when both conditions are met: 1. The collection/global has localized fields 2. `localization.defaultLocalePublishOption` is set to `'active'` ### Why? PR #13459 fixed the submenu "Publish in [specific locale]" button to not appear on collections without localized fields, but missed updating the main button label logic. This caused the main publish button to display "Publish in [locale]" even when a collection had no localized fields (when `defaultLocalePublishOption: 'active'` was set). ### How? - Updated `publishAll` calculation to check `canPublishSpecificLocale` (which includes the `hasLocalizedFields` check) instead of just checking if localization is enabled - Changed the button label rendering from `{localization ? defaultLabel : label}` to `{canPublishSpecificLocale ? defaultLabel : label}` Fixes #14386
1 parent 0d14b06 commit caf68e4

File tree

7 files changed

+97
-19
lines changed

7 files changed

+97
-19
lines changed

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

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
9494
setHasLocalizedFields(hasLocalizedField)
9595
}, [entityConfig?.fields])
9696

97-
const canPublishSpecificLocale = localization && hasLocalizedFields && hasPublishPermission
97+
const isSpecificLocalePublishEnabled = localization && hasLocalizedFields && hasPublishPermission
9898

9999
const operation = useOperation()
100100

@@ -192,8 +192,10 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
192192
[api, collectionSlug, globalSlug, id, serverURL, setHasPublishedDoc, submit, uploadStatus],
193193
)
194194

195-
const publishAll =
196-
!localization || (localization && localization.defaultLocalePublishOption !== 'active')
195+
// Publish to all locales unless there are localized fields AND defaultLocalePublishOption is 'active'
196+
const isDefaultPublishAll =
197+
!isSpecificLocalePublishEnabled ||
198+
(localization && localization?.defaultLocalePublishOption !== 'active')
197199

198200
const activeLocale =
199201
localization &&
@@ -207,14 +209,6 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
207209
? activeLocale.label
208210
: (activeLocale.label?.[localeCode] ?? undefined))
209211

210-
const defaultPublish = publishAll ? publish : () => publishSpecificLocale(activeLocale.code)
211-
const defaultLabel = publishAll ? label : t('version:publishIn', { locale: activeLocaleLabel })
212-
213-
const secondaryPublish = publishAll ? () => publishSpecificLocale(activeLocale.code) : publish
214-
const secondaryLabel = publishAll
215-
? t('version:publishIn', { locale: activeLocaleLabel })
216-
: t('version:publishAllLocales')
217-
218212
if (!hasPublishPermission) {
219213
return null
220214
}
@@ -225,10 +219,10 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
225219
buttonId="action-save"
226220
disabled={!canPublish}
227221
enableSubMenu={canSchedulePublish}
228-
onClick={defaultPublish}
222+
onClick={isDefaultPublishAll ? publish : () => publishSpecificLocale(activeLocale.code)}
229223
size="medium"
230224
SubMenuPopupContent={
231-
canPublishSpecificLocale || canSchedulePublish
225+
isSpecificLocalePublishEnabled || canSchedulePublish
232226
? ({ close }) => {
233227
return (
234228
<React.Fragment>
@@ -242,10 +236,19 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
242236
</PopupList.Button>
243237
</PopupList.ButtonGroup>
244238
)}
245-
{canPublishSpecificLocale && (
239+
{isSpecificLocalePublishEnabled && (
246240
<PopupList.ButtonGroup>
247-
<PopupList.Button id="publish-locale" onClick={secondaryPublish}>
248-
{secondaryLabel}
241+
<PopupList.Button
242+
id="publish-locale"
243+
onClick={
244+
isDefaultPublishAll
245+
? () => publishSpecificLocale(activeLocale.code)
246+
: publish
247+
}
248+
>
249+
{isDefaultPublishAll
250+
? t('version:publishIn', { locale: activeLocaleLabel })
251+
: t('version:publishAllLocales')}
249252
</PopupList.Button>
250253
</PopupList.ButtonGroup>
251254
)}
@@ -256,7 +259,9 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
256259
}
257260
type="button"
258261
>
259-
{localization ? defaultLabel : label}
262+
{isSpecificLocalePublishEnabled
263+
? t('version:publishIn', { locale: activeLocaleLabel })
264+
: label}
260265
</FormSubmit>
261266
{canSchedulePublish && isModalOpen(drawerSlug) && (
262267
<ScheduleDrawer
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { CollectionConfig } from 'payload'
2+
3+
import { localizedCollectionSlug } from '../slugs.js'
4+
5+
export const Localized: CollectionConfig = {
6+
slug: localizedCollectionSlug,
7+
admin: {
8+
useAsTitle: 'title',
9+
},
10+
versions: {
11+
drafts: true,
12+
},
13+
fields: [
14+
{
15+
name: 'title',
16+
type: 'text',
17+
localized: true,
18+
},
19+
],
20+
}

test/admin/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { CollectionGroup2B } from './collections/Group2B.js'
2121
import { CollectionHidden } from './collections/Hidden.js'
2222
import { ListDrawer } from './collections/ListDrawer.js'
2323
import { ListViewSelectAPI } from './collections/ListViewSelectAPI/index.js'
24+
import { Localized } from './collections/Localized.js'
2425
import { CollectionNoApiView } from './collections/NoApiView.js'
2526
import { NoTimestampsCollection } from './collections/NoTimestamps.js'
2627
import { CollectionNotInView } from './collections/NotInView.js'
@@ -199,6 +200,7 @@ export default buildConfigWithDefaults({
199200
ListViewSelectAPI,
200201
Virtuals,
201202
NoTimestampsCollection,
203+
Localized,
202204
],
203205
globals: [
204206
GlobalHidden,

test/admin/e2e/document-view/e2e.spec.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
globalSlug,
3636
group1Collection1Slug,
3737
group1GlobalSlug,
38+
localizedCollectionSlug,
3839
noApiViewCollectionSlug,
3940
noApiViewGlobalSlug,
4041
placeholderCollectionSlug,
@@ -75,6 +76,7 @@ describe('Document View', () => {
7576
let collectionCustomViewPathId: string
7677
let editMenuItemsURL: AdminUrlUtil
7778
let reorderTabsURL: AdminUrlUtil
79+
let localizedURL: AdminUrlUtil
7880

7981
beforeAll(async ({ browser }, testInfo) => {
8082
const prebuild = false // Boolean(process.env.CI)
@@ -93,6 +95,7 @@ describe('Document View', () => {
9395
placeholderURL = new AdminUrlUtil(serverURL, placeholderCollectionSlug)
9496
editMenuItemsURL = new AdminUrlUtil(serverURL, editMenuItemsSlug)
9597
reorderTabsURL = new AdminUrlUtil(serverURL, reorderTabsSlug)
98+
localizedURL = new AdminUrlUtil(serverURL, localizedCollectionSlug)
9699

97100
const context = await browser.newContext()
98101
page = await context.newPage()
@@ -688,12 +691,20 @@ describe('Document View', () => {
688691
})
689692

690693
describe('publish button', () => {
691-
test('should show publish active locale button with defaultLocalePublishOption', async () => {
692-
await navigateToDoc(page, postsUrl)
694+
test('should show publish active locale button with defaultLocalePublishOption set to active', async () => {
695+
await navigateToDoc(page, localizedURL)
693696
const publishButton = page.locator('#action-save')
694697
await expect(publishButton).toBeVisible()
695698
await expect(publishButton).toContainText('Publish in English')
696699
})
700+
701+
test('should not show publish active locale button with defaultLocalePublishOption set to active but no localized fields', async () => {
702+
await navigateToDoc(page, postsUrl)
703+
const publishButton = page.locator('#action-save')
704+
await expect(publishButton).toBeVisible()
705+
await expect(publishButton).toContainText('Publish changes')
706+
await expect(publishButton).not.toContainText('Publish in')
707+
})
697708
})
698709

699710
describe('reserved field names', () => {

test/admin/payload-types.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export interface Config {
9898
'list-view-select-api': ListViewSelectApi;
9999
virtuals: Virtual;
100100
'no-timestamps': NoTimestamp;
101+
localized: Localized;
101102
'payload-kv': PayloadKv;
102103
'payload-locked-documents': PayloadLockedDocument;
103104
'payload-preferences': PayloadPreference;
@@ -136,6 +137,7 @@ export interface Config {
136137
'list-view-select-api': ListViewSelectApiSelect<false> | ListViewSelectApiSelect<true>;
137138
virtuals: VirtualsSelect<false> | VirtualsSelect<true>;
138139
'no-timestamps': NoTimestampsSelect<false> | NoTimestampsSelect<true>;
140+
localized: LocalizedSelect<false> | LocalizedSelect<true>;
139141
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
140142
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
141143
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
@@ -640,6 +642,17 @@ export interface NoTimestamp {
640642
id: string;
641643
title?: string | null;
642644
}
645+
/**
646+
* This interface was referenced by `Config`'s JSON-Schema
647+
* via the `definition` "localized".
648+
*/
649+
export interface Localized {
650+
id: string;
651+
title?: string | null;
652+
updatedAt: string;
653+
createdAt: string;
654+
_status?: ('draft' | 'published') | null;
655+
}
643656
/**
644657
* This interface was referenced by `Config`'s JSON-Schema
645658
* via the `definition` "payload-kv".
@@ -787,6 +800,10 @@ export interface PayloadLockedDocument {
787800
| ({
788801
relationTo: 'no-timestamps';
789802
value: string | NoTimestamp;
803+
} | null)
804+
| ({
805+
relationTo: 'localized';
806+
value: string | Localized;
790807
} | null);
791808
globalSlug?: string | null;
792809
user: {
@@ -1247,6 +1264,16 @@ export interface VirtualsSelect<T extends boolean = true> {
12471264
export interface NoTimestampsSelect<T extends boolean = true> {
12481265
title?: T;
12491266
}
1267+
/**
1268+
* This interface was referenced by `Config`'s JSON-Schema
1269+
* via the `definition` "localized_select".
1270+
*/
1271+
export interface LocalizedSelect<T extends boolean = true> {
1272+
title?: T;
1273+
updatedAt?: T;
1274+
createdAt?: T;
1275+
_status?: T;
1276+
}
12501277
/**
12511278
* This interface was referenced by `Config`'s JSON-Schema
12521279
* via the `definition` "payload-kv_select".

test/admin/seed.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
customViews1CollectionSlug,
77
customViews2CollectionSlug,
88
geoCollectionSlug,
9+
localizedCollectionSlug,
910
noApiViewCollectionSlug,
1011
postsCollectionSlug,
1112
usersCollectionSlug,
@@ -113,6 +114,15 @@ export const seed = async (_payload: Payload) => {
113114
depth: 0,
114115
overrideAccess: true,
115116
}),
117+
() =>
118+
_payload.create({
119+
collection: localizedCollectionSlug,
120+
data: {
121+
title: 'Localized Doc',
122+
},
123+
depth: 0,
124+
overrideAccess: true,
125+
}),
116126
],
117127
false,
118128
)

test/admin/slugs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export const reorderTabsSlug = 'reorder-tabs'
55
export const geoCollectionSlug = 'geo'
66
export const arrayCollectionSlug = 'array'
77
export const postsCollectionSlug = 'posts'
8+
9+
export const localizedCollectionSlug = 'localized'
810
export const group1Collection1Slug = 'group-one-collection-ones'
911
export const group1Collection2Slug = 'group-one-collection-twos'
1012
export const group2Collection1Slug = 'group-two-collection-ones'
@@ -43,6 +45,7 @@ export const collectionSlugs = [
4345
listDrawerSlug,
4446
virtualsSlug,
4547
formatDocURLCollectionSlug,
48+
localizedCollectionSlug,
4649
]
4750

4851
export const customGlobalViews1GlobalSlug = 'custom-global-views-one'

0 commit comments

Comments
 (0)