From eade59c0a51a9045fb939e88ea28707a9eb454b7 Mon Sep 17 00:00:00 2001 From: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:42:21 -0500 Subject: [PATCH 1/3] fix(ui): check for localized fields before showing locale-specific publish button text --- .../ui/src/elements/PublishButton/index.tsx | 6 +++-- test/admin/collections/Localized.ts | 20 ++++++++++++++ test/admin/config.ts | 2 ++ test/admin/e2e/document-view/e2e.spec.ts | 15 +++++++++-- test/admin/payload-types.ts | 27 +++++++++++++++++++ test/admin/seed.ts | 10 +++++++ test/admin/slugs.ts | 3 +++ 7 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 test/admin/collections/Localized.ts diff --git a/packages/ui/src/elements/PublishButton/index.tsx b/packages/ui/src/elements/PublishButton/index.tsx index fcecc28ed5e..b34c50be5d6 100644 --- a/packages/ui/src/elements/PublishButton/index.tsx +++ b/packages/ui/src/elements/PublishButton/index.tsx @@ -192,8 +192,10 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { [api, collectionSlug, globalSlug, id, serverURL, setHasPublishedDoc, submit, uploadStatus], ) + // Publish to all locales unless there are localized fields AND defaultLocalePublishOption is 'active' const publishAll = - !localization || (localization && localization.defaultLocalePublishOption !== 'active') + !canPublishSpecificLocale || + (localization && localization?.defaultLocalePublishOption !== 'active') const activeLocale = localization && @@ -256,7 +258,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { } type="button" > - {localization ? defaultLabel : label} + {canPublishSpecificLocale ? defaultLabel : label} {canSchedulePublish && isModalOpen(drawerSlug) && ( { let collectionCustomViewPathId: string let editMenuItemsURL: AdminUrlUtil let reorderTabsURL: AdminUrlUtil + let localizedURL: AdminUrlUtil beforeAll(async ({ browser }, testInfo) => { const prebuild = false // Boolean(process.env.CI) @@ -93,6 +95,7 @@ describe('Document View', () => { placeholderURL = new AdminUrlUtil(serverURL, placeholderCollectionSlug) editMenuItemsURL = new AdminUrlUtil(serverURL, editMenuItemsSlug) reorderTabsURL = new AdminUrlUtil(serverURL, reorderTabsSlug) + localizedURL = new AdminUrlUtil(serverURL, localizedCollectionSlug) const context = await browser.newContext() page = await context.newPage() @@ -688,12 +691,20 @@ describe('Document View', () => { }) describe('publish button', () => { - test('should show publish active locale button with defaultLocalePublishOption', async () => { - await navigateToDoc(page, postsUrl) + test('should show publish active locale button with defaultLocalePublishOption set to active', async () => { + await navigateToDoc(page, localizedURL) const publishButton = page.locator('#action-save') await expect(publishButton).toBeVisible() await expect(publishButton).toContainText('Publish in English') }) + + test('should not show publish active locale button with defaultLocalePublishOption set to active but no localized fields', async () => { + await navigateToDoc(page, postsUrl) + const publishButton = page.locator('#action-save') + await expect(publishButton).toBeVisible() + await expect(publishButton).toContainText('Publish changes') + await expect(publishButton).not.toContainText('Publish in') + }) }) describe('reserved field names', () => { diff --git a/test/admin/payload-types.ts b/test/admin/payload-types.ts index 9a59a5a9e6e..d121b954f54 100644 --- a/test/admin/payload-types.ts +++ b/test/admin/payload-types.ts @@ -98,6 +98,7 @@ export interface Config { 'list-view-select-api': ListViewSelectApi; virtuals: Virtual; 'no-timestamps': NoTimestamp; + localized: Localized; 'payload-kv': PayloadKv; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -136,6 +137,7 @@ export interface Config { 'list-view-select-api': ListViewSelectApiSelect | ListViewSelectApiSelect; virtuals: VirtualsSelect | VirtualsSelect; 'no-timestamps': NoTimestampsSelect | NoTimestampsSelect; + localized: LocalizedSelect | LocalizedSelect; 'payload-kv': PayloadKvSelect | PayloadKvSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -640,6 +642,17 @@ export interface NoTimestamp { id: string; title?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "localized". + */ +export interface Localized { + id: string; + title?: string | null; + updatedAt: string; + createdAt: string; + _status?: ('draft' | 'published') | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-kv". @@ -787,6 +800,10 @@ export interface PayloadLockedDocument { | ({ relationTo: 'no-timestamps'; value: string | NoTimestamp; + } | null) + | ({ + relationTo: 'localized'; + value: string | Localized; } | null); globalSlug?: string | null; user: { @@ -1247,6 +1264,16 @@ export interface VirtualsSelect { export interface NoTimestampsSelect { title?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "localized_select". + */ +export interface LocalizedSelect { + title?: T; + updatedAt?: T; + createdAt?: T; + _status?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-kv_select". diff --git a/test/admin/seed.ts b/test/admin/seed.ts index 9189315dff8..b0be756cdf7 100644 --- a/test/admin/seed.ts +++ b/test/admin/seed.ts @@ -6,6 +6,7 @@ import { customViews1CollectionSlug, customViews2CollectionSlug, geoCollectionSlug, + localizedCollectionSlug, noApiViewCollectionSlug, postsCollectionSlug, usersCollectionSlug, @@ -113,6 +114,15 @@ export const seed = async (_payload: Payload) => { depth: 0, overrideAccess: true, }), + () => + _payload.create({ + collection: localizedCollectionSlug, + data: { + title: 'Localized Doc', + }, + depth: 0, + overrideAccess: true, + }), ], false, ) diff --git a/test/admin/slugs.ts b/test/admin/slugs.ts index 67cdb59e3f9..742c123cd95 100644 --- a/test/admin/slugs.ts +++ b/test/admin/slugs.ts @@ -5,6 +5,8 @@ export const reorderTabsSlug = 'reorder-tabs' export const geoCollectionSlug = 'geo' export const arrayCollectionSlug = 'array' export const postsCollectionSlug = 'posts' + +export const localizedCollectionSlug = 'localized' export const group1Collection1Slug = 'group-one-collection-ones' export const group1Collection2Slug = 'group-one-collection-twos' export const group2Collection1Slug = 'group-two-collection-ones' @@ -43,6 +45,7 @@ export const collectionSlugs = [ listDrawerSlug, virtualsSlug, formatDocURLCollectionSlug, + localizedCollectionSlug, ] export const customGlobalViews1GlobalSlug = 'custom-global-views-one' From 92a87e2e61975300ccdf29c5524cf6473a016a61 Mon Sep 17 00:00:00 2001 From: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com> Date: Thu, 20 Nov 2025 12:01:36 -0500 Subject: [PATCH 2/3] chore: update var names --- .../ui/src/elements/PublishButton/index.tsx | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/ui/src/elements/PublishButton/index.tsx b/packages/ui/src/elements/PublishButton/index.tsx index b34c50be5d6..c9f104bbf76 100644 --- a/packages/ui/src/elements/PublishButton/index.tsx +++ b/packages/ui/src/elements/PublishButton/index.tsx @@ -94,7 +94,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { setHasLocalizedFields(hasLocalizedField) }, [entityConfig?.fields]) - const canPublishSpecificLocale = localization && hasLocalizedFields && hasPublishPermission + const isSpecificLocalePublishEnabled = localization && hasLocalizedFields && hasPublishPermission const operation = useOperation() @@ -193,8 +193,8 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { ) // Publish to all locales unless there are localized fields AND defaultLocalePublishOption is 'active' - const publishAll = - !canPublishSpecificLocale || + const isDefaultPublishAll = + !isSpecificLocalePublishEnabled || (localization && localization?.defaultLocalePublishOption !== 'active') const activeLocale = @@ -209,11 +209,17 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { ? activeLocale.label : (activeLocale.label?.[localeCode] ?? undefined)) - const defaultPublish = publishAll ? publish : () => publishSpecificLocale(activeLocale.code) - const defaultLabel = publishAll ? label : t('version:publishIn', { locale: activeLocaleLabel }) - - const secondaryPublish = publishAll ? () => publishSpecificLocale(activeLocale.code) : publish - const secondaryLabel = publishAll + const defaultPublish = isDefaultPublishAll + ? publish + : () => publishSpecificLocale(activeLocale.code) + const defaultLabel = isDefaultPublishAll + ? label + : t('version:publishIn', { locale: activeLocaleLabel }) + + const secondaryPublish = isDefaultPublishAll + ? () => publishSpecificLocale(activeLocale.code) + : publish + const secondaryLabel = isDefaultPublishAll ? t('version:publishIn', { locale: activeLocaleLabel }) : t('version:publishAllLocales') @@ -230,7 +236,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { onClick={defaultPublish} size="medium" SubMenuPopupContent={ - canPublishSpecificLocale || canSchedulePublish + isSpecificLocalePublishEnabled || canSchedulePublish ? ({ close }) => { return ( @@ -244,7 +250,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { )} - {canPublishSpecificLocale && ( + {isSpecificLocalePublishEnabled && ( {secondaryLabel} @@ -258,7 +264,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { } type="button" > - {canPublishSpecificLocale ? defaultLabel : label} + {isSpecificLocalePublishEnabled ? defaultLabel : label} {canSchedulePublish && isModalOpen(drawerSlug) && ( Date: Thu, 20 Nov 2025 13:04:41 -0500 Subject: [PATCH 3/3] chore: move some variable logic inline to remove variables --- .../ui/src/elements/PublishButton/index.tsx | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/ui/src/elements/PublishButton/index.tsx b/packages/ui/src/elements/PublishButton/index.tsx index c9f104bbf76..22d086bf0ba 100644 --- a/packages/ui/src/elements/PublishButton/index.tsx +++ b/packages/ui/src/elements/PublishButton/index.tsx @@ -209,20 +209,6 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { ? activeLocale.label : (activeLocale.label?.[localeCode] ?? undefined)) - const defaultPublish = isDefaultPublishAll - ? publish - : () => publishSpecificLocale(activeLocale.code) - const defaultLabel = isDefaultPublishAll - ? label - : t('version:publishIn', { locale: activeLocaleLabel }) - - const secondaryPublish = isDefaultPublishAll - ? () => publishSpecificLocale(activeLocale.code) - : publish - const secondaryLabel = isDefaultPublishAll - ? t('version:publishIn', { locale: activeLocaleLabel }) - : t('version:publishAllLocales') - if (!hasPublishPermission) { return null } @@ -233,7 +219,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { buttonId="action-save" disabled={!canPublish} enableSubMenu={canSchedulePublish} - onClick={defaultPublish} + onClick={isDefaultPublishAll ? publish : () => publishSpecificLocale(activeLocale.code)} size="medium" SubMenuPopupContent={ isSpecificLocalePublishEnabled || canSchedulePublish @@ -252,8 +238,17 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { )} {isSpecificLocalePublishEnabled && ( - - {secondaryLabel} + publishSpecificLocale(activeLocale.code) + : publish + } + > + {isDefaultPublishAll + ? t('version:publishIn', { locale: activeLocaleLabel }) + : t('version:publishAllLocales')} )} @@ -264,7 +259,9 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { } type="button" > - {isSpecificLocalePublishEnabled ? defaultLabel : label} + {isSpecificLocalePublishEnabled + ? t('version:publishIn', { locale: activeLocaleLabel }) + : label} {canSchedulePublish && isModalOpen(drawerSlug) && (