From be14f9e966fecbfb66a049b54e93e5d6c1a475db Mon Sep 17 00:00:00 2001 From: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com> Date: Tue, 18 Nov 2025 15:45:32 -0500 Subject: [PATCH 1/2] fix(ui): pass undefined instead of empty string for cleared filter values --- .../elements/WhereBuilder/Condition/index.tsx | 4 +-- test/admin/e2e/list-view/e2e.spec.ts | 31 +++++++++++++++++++ test/admin/payload-types.ts | 28 +++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/elements/WhereBuilder/Condition/index.tsx b/packages/ui/src/elements/WhereBuilder/Condition/index.tsx index 181bb0c4c7e..07f39d2728b 100644 --- a/packages/ui/src/elements/WhereBuilder/Condition/index.tsx +++ b/packages/ui/src/elements/WhereBuilder/Condition/index.tsx @@ -74,7 +74,7 @@ export const Condition: React.FC = (props) => { valueOptions = reducedField.field.options } - const updateValue = useEffectEvent(async (debouncedValue) => { + const updateValue = useEffectEvent(async (debouncedValue: Value) => { if (operator) { await updateCondition({ type: 'value', @@ -82,7 +82,7 @@ export const Condition: React.FC = (props) => { field: reducedField, operator, orIndex, - value: debouncedValue === null ? '' : debouncedValue, + value: debouncedValue === null || debouncedValue === '' ? undefined : debouncedValue, }) } }) diff --git a/test/admin/e2e/list-view/e2e.spec.ts b/test/admin/e2e/list-view/e2e.spec.ts index 16c671204cd..3509e449234 100644 --- a/test/admin/e2e/list-view/e2e.spec.ts +++ b/test/admin/e2e/list-view/e2e.spec.ts @@ -742,6 +742,37 @@ describe('List View', () => { await expect(valueInput).toHaveValue('Test') }) + test('should show all documents when equals filter value is cleared', async () => { + await page.goto(postsUrl.list) + + // Verify we start with 2 posts + await expect(page.locator(tableRowLocator)).toHaveCount(2) + + // Add a filter with a value + const { whereBuilder } = await addListFilter({ + page, + fieldLabel: 'Title', + operatorLabel: 'equals', + value: 'post1', + }) + + // Wait for filter to be applied + await page.waitForTimeout(500) + + // Should now show only 1 post + await expect(page.locator(tableRowLocator)).toHaveCount(1) + + // Clear the filter value + const valueInput = whereBuilder.locator('.condition__value >> input') + await valueInput.clear() + + // Wait for debounce + await page.waitForTimeout(500) + + // Should now show all 2 posts again (not 0 posts) + await expect(page.locator(tableRowLocator)).toHaveCount(2) + }) + test('should still show second filter if two filters exist and first filter is removed', async () => { await page.goto(postsUrl.list) diff --git a/test/admin/payload-types.ts b/test/admin/payload-types.ts index ef6d773641f..9a59a5a9e6e 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; + 'payload-kv': PayloadKv; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; @@ -135,6 +136,7 @@ export interface Config { 'list-view-select-api': ListViewSelectApiSelect | ListViewSelectApiSelect; virtuals: VirtualsSelect | VirtualsSelect; 'no-timestamps': NoTimestampsSelect | NoTimestampsSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; @@ -142,6 +144,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: ('false' | 'none' | 'null') | false | null | ('es' | 'en') | ('es' | 'en')[]; globals: { 'hidden-global': HiddenGlobal; 'not-in-view-global': NotInViewGlobal; @@ -637,6 +640,23 @@ export interface NoTimestamp { id: string; title?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents". @@ -1227,6 +1247,14 @@ export interface VirtualsSelect { export interface NoTimestampsSelect { title?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents_select". From cfb3ec12a742d43e8ff8a9444960fed8166eed5a Mon Sep 17 00:00:00 2001 From: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:19:19 -0500 Subject: [PATCH 2/2] test: clean up test --- test/admin/e2e/list-view/e2e.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/admin/e2e/list-view/e2e.spec.ts b/test/admin/e2e/list-view/e2e.spec.ts index 3509e449234..56d3c061564 100644 --- a/test/admin/e2e/list-view/e2e.spec.ts +++ b/test/admin/e2e/list-view/e2e.spec.ts @@ -745,10 +745,8 @@ describe('List View', () => { test('should show all documents when equals filter value is cleared', async () => { await page.goto(postsUrl.list) - // Verify we start with 2 posts await expect(page.locator(tableRowLocator)).toHaveCount(2) - // Add a filter with a value const { whereBuilder } = await addListFilter({ page, fieldLabel: 'Title', @@ -759,10 +757,8 @@ describe('List View', () => { // Wait for filter to be applied await page.waitForTimeout(500) - // Should now show only 1 post await expect(page.locator(tableRowLocator)).toHaveCount(1) - // Clear the filter value const valueInput = whereBuilder.locator('.condition__value >> input') await valueInput.clear()