From f1b005c4f5c94918d574ddc003b85f148192433b Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 24 Feb 2025 13:38:21 -0500 Subject: [PATCH] fix(ui): object type field labels not displaying in search filter (#11366) This PR ensures that when `titleField.label` is provided as an object, it is correctly translated and displayed in the search filter's placeholder. Previously, the implementation only supported string values, which could lead to issues with object type labels. With these changes, object type labels will now properly show as intended in the search filter. Fixes #11348 --- .../ui/src/elements/ListControls/index.tsx | 3 +- test/localization/config.ts | 9 +++++ test/localization/e2e.spec.ts | 36 +++++++++++-------- test/localization/payload-types.ts | 3 +- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/packages/ui/src/elements/ListControls/index.tsx b/packages/ui/src/elements/ListControls/index.tsx index 24310d5d97..2deb787076 100644 --- a/packages/ui/src/elements/ListControls/index.tsx +++ b/packages/ui/src/elements/ListControls/index.tsx @@ -73,7 +73,8 @@ export const ListControls: React.FC = (props) => { const searchLabel = (titleField && getTranslation( - 'label' in titleField && typeof titleField.label === 'string' + 'label' in titleField && + (typeof titleField.label === 'string' || typeof titleField.label === 'object') ? titleField.label : 'name' in titleField ? titleField.name diff --git a/test/localization/config.ts b/test/localization/config.ts index bed2f48948..b91b0eb0ae 100644 --- a/test/localization/config.ts +++ b/test/localization/config.ts @@ -64,8 +64,16 @@ export default buildConfigWithDefaults({ NestedArray, NestedFields, { + admin: { + listSearchableFields: 'name', + }, auth: true, fields: [ + { + name: 'name', + label: { en: 'Full name' }, + type: 'text', + }, { name: 'relation', relationTo: localizedPostsSlug, @@ -83,6 +91,7 @@ export default buildConfigWithDefaults({ fields: [ { name: 'title', + label: { en: 'Full title' }, index: true, localized: true, type: 'text', diff --git a/test/localization/e2e.spec.ts b/test/localization/e2e.spec.ts index cbe9c14b6c..c2403318b2 100644 --- a/test/localization/e2e.spec.ts +++ b/test/localization/e2e.spec.ts @@ -1,7 +1,11 @@ import type { BrowserContext, Page } from '@playwright/test' +import type { GeneratedTypes } from 'helpers/sdk/types.js' import { expect, test } from '@playwright/test' +import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js' import { openDocControls } from 'helpers/e2e/openDocControls.js' +import { upsertPrefs } from 'helpers/e2e/upsertPrefs.js' +import { RESTClient } from 'helpers/rest.js' import path from 'path' import { fileURLToPath } from 'url' @@ -31,11 +35,6 @@ import { spanishLocale, withRequiredLocalizedFields, } from './shared.js' -import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js' - -import { upsertPrefs } from 'helpers/e2e/upsertPrefs.js' -import { RESTClient } from 'helpers/rest.js' -import { GeneratedTypes } from 'helpers/sdk/types.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -119,16 +118,16 @@ describe('Localization', () => { await expect(page.locator('.localizer .popup')).toHaveClass(/popup--active/) - const activeOption = await page.locator( + const activeOption = page.locator( `.localizer .popup.popup--active .popup-button-list__button--selected`, ) await expect(activeOption).toBeVisible() const tagName = await activeOption.evaluate((node) => node.tagName) - await expect(tagName).not.toBe('A') + expect(tagName).not.toBe('A') await expect(activeOption).not.toHaveAttribute('href') - await expect(tagName).not.toBe('BUTTON') - await expect(tagName).toBe('DIV') + expect(tagName).not.toBe('BUTTON') + expect(tagName).toBe('DIV') }) }) @@ -140,7 +139,7 @@ describe('Localization', () => { const createNewButtonLocator = '.collection-list a[href="/admin/collections/cannot-create-default-locale/create"]' - await expect(page.locator(createNewButtonLocator)).not.toBeVisible() + await expect(page.locator(createNewButtonLocator)).toBeHidden() await changeLocale(page, spanishLocale) await expect(page.locator(createNewButtonLocator).first()).toBeVisible() await page.goto(urlCannotCreateDefaultLocale.create) @@ -330,11 +329,11 @@ describe('Localization', () => { await page.goto(url.list) - const localeLabel = await page + const localeLabel = page .locator('.localizer.app-header__localizer .localizer-button__current-label') - .innerText() + - expect(localeLabel).not.toEqual('English') + await expect(localeLabel).not.toHaveText('English') }) }) @@ -351,7 +350,7 @@ describe('Localization', () => { await navigateToDoc(page, urlRelationshipLocalized) const drawerToggler = '#field-relationMultiRelationTo .relationship--single-value__drawer-toggler' - expect(page.locator(drawerToggler)).toBeEnabled() + await expect(page.locator(drawerToggler)).toBeEnabled() await openDocDrawer(page, drawerToggler) await expect(page.locator('.doc-drawer__header-text')).toContainText('spanish-relation2') await page.locator('.doc-drawer__header-close').click() @@ -518,7 +517,7 @@ describe('Localization', () => { // only throttle test after initial load to avoid timeouts const cdpSession = await throttleTest({ - page: page, + page, context, delay: 'Fast 4G', }) @@ -541,6 +540,13 @@ describe('Localization', () => { await cdpSession.detach() }) }) + + test('should use label in search filter when string or object', async () => { + await page.goto(url.list) + const searchInput = page.locator('.search-filter__input') + await expect(searchInput).toBeVisible() + await expect(searchInput).toHaveAttribute('placeholder', 'Search by Full title') + }) }) async function fillValues(data: Partial) { diff --git a/test/localization/payload-types.ts b/test/localization/payload-types.ts index 320471a4a4..cfc3e07d4c 100644 --- a/test/localization/payload-types.ts +++ b/test/localization/payload-types.ts @@ -64,7 +64,6 @@ export interface Config { auth: { users: UserAuthOperations; }; - blocks: {}; collections: { richText: RichText; 'blocks-fields': BlocksField; @@ -322,6 +321,7 @@ export interface NestedFieldTable { */ export interface User { id: string; + name?: string | null; relation?: (string | null) | LocalizedPost; updatedAt: string; createdAt: string; @@ -928,6 +928,7 @@ export interface NestedFieldTablesSelect { * via the `definition` "users_select". */ export interface UsersSelect { + name?: T; relation?: T; updatedAt?: T; createdAt?: T;