From 5873dfb73108bb06bd6e1bb5295ee3d4905d8a6b Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 28 Mar 2024 13:14:00 -0400 Subject: [PATCH] fix(ui): incorrect conditions in WhereBuilder (#5503) * fix: relationship field tests e2e * chore: adds POLL_TOPASS_TIMEOUT to relationship field tests * chore: adds comments to relationship test waits --- .../ReactSelect/ValueContainer/index.scss | 4 ++ .../elements/WhereBuilder/Condition/index.tsx | 18 +++++--- .../ui/src/elements/WhereBuilder/index.tsx | 29 ++++++------- test/fields/e2e.spec.ts | 43 +++++++++---------- 4 files changed, 51 insertions(+), 43 deletions(-) diff --git a/packages/ui/src/elements/ReactSelect/ValueContainer/index.scss b/packages/ui/src/elements/ReactSelect/ValueContainer/index.scss index af10671fb6..a6b4e61587 100644 --- a/packages/ui/src/elements/ReactSelect/ValueContainer/index.scss +++ b/packages/ui/src/elements/ReactSelect/ValueContainer/index.scss @@ -14,6 +14,10 @@ padding-top: 0; padding-bottom: 0; color: currentColor; + + .field-label { + padding-bottom: 0; + } } &--is-multi { diff --git a/packages/ui/src/elements/WhereBuilder/Condition/index.tsx b/packages/ui/src/elements/WhereBuilder/Condition/index.tsx index b52e55f541..05bf1fb6f1 100644 --- a/packages/ui/src/elements/WhereBuilder/Condition/index.tsx +++ b/packages/ui/src/elements/WhereBuilder/Condition/index.tsx @@ -36,6 +36,8 @@ export type Props = { }) => void } +import type { RelationshipFieldProps } from '@payloadcms/ui/fields/Relationship' + import { RenderCustomComponent } from '../../../elements/RenderCustomComponent/index.js' import { useDebounce } from '../../../hooks/useDebounce.js' import { Button } from '../../Button/index.js' @@ -82,7 +84,7 @@ export const Condition: React.FC = (props) => { useEffect(() => { updateCondition({ andIndex, - fieldName, + fieldName: activeField.value, operator: internalOperatorOption, orIndex, value: debouncedValue, @@ -90,7 +92,7 @@ export const Condition: React.FC = (props) => { }, [ debouncedValue, andIndex, - fieldName, + activeField?.value, internalOperatorOption, orIndex, updateCondition, @@ -128,18 +130,18 @@ export const Condition: React.FC = (props) => { }) }} options={fields} - value={fields.find((field) => fieldName === field.value) || fields[0]} + value={fields.find((field) => activeField.value === field.value) || fields[0]} />
{ setInternalOperatorOption(operator.value) updateCondition({ andIndex, - fieldName, + fieldName: activeField.value, operator: operator.value, orIndex, value: internalQueryValue, @@ -163,6 +165,12 @@ export const Condition: React.FC = (props) => { onChange: setInternalQueryValue, operator: internalOperatorOption, options: valueOptions, + relationTo: + activeField?.props?.type === 'relationship' && + 'fieldComponentProps' in activeField.props + ? (activeField?.props?.fieldComponentProps as RelationshipFieldProps) + ?.relationTo + : undefined, value: internalQueryValue ?? '', }} /> diff --git a/packages/ui/src/elements/WhereBuilder/index.tsx b/packages/ui/src/elements/WhereBuilder/index.tsx index 343c44737c..3cdd3d7f62 100644 --- a/packages/ui/src/elements/WhereBuilder/index.tsx +++ b/packages/ui/src/elements/WhereBuilder/index.tsx @@ -105,6 +105,7 @@ export const WhereBuilder: React.FC = (props) => { } ] */ + const [conditions, setConditions] = React.useState(() => { const whereFromSearch = searchParams.where if (whereFromSearch) { @@ -149,20 +150,14 @@ export const WhereBuilder: React.FC = (props) => { setConditions((prevConditions) => { const newConditions = [...prevConditions] if (typeof newConditions[orIndex].and[andIndex] === 'object') { - const [existingFieldName, existingCondition] = Object.entries( - newConditions[orIndex].and[andIndex], - )?.[0] || [fieldNameArg, operatorArg] - const fieldName = existingFieldName || fieldNameArg - const operator = operatorArg || Object.keys(existingCondition)?.[0] || undefined + const fieldName = fieldNameArg + const operator = operatorArg const value = valueArg ?? (operator ? newConditions[orIndex].and[andIndex][operator] : '') - if (fieldName) { + if (fieldName && operator && ![null, undefined].includes(value)) { newConditions[orIndex].and[andIndex] = { [fieldName]: operator ? { [operator]: value } : {}, } - } - - if (fieldName && operator && ![null, undefined].includes(value)) { setShouldUpdateQuery(true) } } @@ -208,12 +203,14 @@ export const WhereBuilder: React.FC = (props) => {
    {Array.isArray(or?.and) && or.and.map((_, andIndex) => { - const fieldName = Object.keys(conditions[orIndex].and[andIndex])[0] - const operator = - Object.keys(conditions[orIndex].and[andIndex]?.[fieldName] || {})?.[0] || - undefined + const initialFieldName = Object.keys(conditions[orIndex].and[andIndex])[0] + const initialOperator = + Object.keys( + conditions[orIndex].and[andIndex]?.[initialFieldName] || {}, + )?.[0] || undefined const initialValue = - conditions[orIndex].and[andIndex]?.[fieldName]?.[operator] || '' + conditions[orIndex].and[andIndex]?.[initialFieldName]?.[initialOperator] || + '' return (
  • @@ -223,11 +220,11 @@ export const WhereBuilder: React.FC = (props) => { { url = new AdminUrlUtil(serverURL, 'relationship-fields') }) - afterEach(async () => { - // delete all existing relationship documents - await payload.delete({ - collection: relationshipFieldsSlug, - where: { id: { exists: true } }, - }) - }) - test('should create inline relationship within field with many relations', async () => { await page.goto(url.create) @@ -1530,7 +1523,7 @@ describe('fields', () => { test('should create nested inline relationships', async () => { await page.goto(url.create) - + await page.waitForURL(`**/${url.create}`) // Open first modal await page.locator('#relationToSelf-add-new .relationship-add-new__add-button').click() @@ -1557,7 +1550,7 @@ describe('fields', () => { // Save then close the second modal await page.locator('[id^=doc-drawer_relationship-fields_2_] #action-save').click() - await wait(200) + await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).toContain('create') await page.locator('[id^=close-drawer__doc-drawer_relationship-fields_2_]').click() // Assert that the first modal is still open and the value matches @@ -1570,7 +1563,7 @@ describe('fields', () => { // Save then close the first modal await page.locator('[id^=doc-drawer_relationship-fields_1_] #action-save').click() - await wait(200) + await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).toContain('create') await page.locator('[id^=close-drawer__doc-drawer_relationship-fields_1_]').click() // Expect the original field to have a value filled @@ -1581,7 +1574,7 @@ describe('fields', () => { // Fill the required field await page.locator('#field-relationship').click() await page.locator('.rs__option:has-text("Seeded text document")').click() - + await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).toContain('create') await page.locator('#action-save').click() await expect(page.locator('.Toastify')).toContainText('successfully') @@ -1662,7 +1655,7 @@ describe('fields', () => { // Related issue: https://github.com/payloadcms/payload/issues/2815 test('should modify fields in relationship drawer', async () => { await page.goto(url.create) - + await page.waitForURL(`**/${url.create}`) // First fill out the relationship field, as it's required await page.locator('#relationship-add-new .relationship-add-new__add-button').click() await page @@ -1678,12 +1671,10 @@ describe('fields', () => { await expect(page.locator('.Toastify')).toContainText('successfully') // Create a new doc for the `relationshipHasMany` field - await page - .locator('#field-relationshipHasMany button.relationship-add-new__add-button') - .click() - const textField2 = page.locator('[id^=doc-drawer_text-fields_1_] #field-text') + await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).not.toContain('create') + await page.locator('#field-relationshipHasMany .relationship-add-new__add-button').click() const value = 'Hello, world!' - await textField2.fill(value) + await page.locator('.drawer__content #field-text').fill(value) // Save and close the drawer await page.locator('[id^=doc-drawer_text-fields_1_] #action-save').click() @@ -1731,13 +1722,16 @@ describe('fields', () => { // opened through the edit button can be saved using the hotkey. test('should save using hotkey in edit document drawer', async () => { await page.goto(url.create) - // First fill out the relationship field, as it's required await page.locator('#relationship-add-new .relationship-add-new__add-button').click() await page.locator('#field-relationship .value-container').click() // Select "Seeded text document" relationship await page.getByText('Seeded text document', { exact: true }).click() + // Need to wait to properly open drawer - without this the drawer state is flakey and closes before + // the text below can be filled before the save on the drawer + await wait(200) + // Click edit button which opens drawer await page.getByRole('button', { name: 'Edit Seeded text document' }).click() @@ -1778,19 +1772,24 @@ describe('fields', () => { test('should fail min rows validation when rows are present', async () => { await page.goto(url.create) - // First fill out the relationship field, as it's required await page.locator('#relationship-add-new .relationship-add-new__add-button').click() await page.locator('#field-relationship .value-container').click() await page.getByText('Seeded text document', { exact: true }).click() + // Need to wait to allow for field to retrieve documents before the save occurs + await wait(200) + await page.locator('#field-relationshipWithMinRows .value-container').click() + await page .locator('#field-relationshipWithMinRows .rs__option:has-text("Seeded text document")') .click() await page.click('#action-save', { delay: 100 }) - await expect(page.locator('.Toastify')).toContainText('Please correct invalid fields') + await expect(page.locator('.Toastify')).toContainText( + 'The following field is invalid: relationshipWithMinRows', + ) }) test('should sort relationship options by sortOptions property (ID in ascending order)', async () => {