From 3a494905ec9a9056a804ce711426c5b3cb9e658a Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Thu, 15 May 2025 13:58:22 +0200 Subject: [PATCH] Fixed error with previous filters on ACTOR with new sub-field filtering (#12050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/twentyhq/core-team-issues/issues/969 that appeared since the new ACTOR sub-field filtering that changed the default sub-field filtering from name to source. Now we apply any existing filter value on an ACTOR field, whether for a sub-field or not, to the name sub-field by default. If the user wants to create a sub-field filter on source, he has to create a new advanced filter. Fixes https://github.com/twentyhq/core-team-issues/issues/967 --------- Co-authored-by: Félix Malfait --- .../ObjectFilterDropdownFilterInput.tsx | 3 +- .../getOperandsForFilterType.test.ts | 2 +- .../turnRecordFilterIntoGqlOperationFilter.ts | 178 ++++++------------ ...ieldNameForCompositeFilterableFieldType.ts | 2 +- .../utils/getRecordFilterOperands.ts | 5 +- 5 files changed, 64 insertions(+), 126 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx index 69d1f7527..60dbcb755 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx @@ -10,7 +10,6 @@ import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect'; import { ObjectFilterDropdownCurrencySelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownCurrencySelect'; -import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect'; import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput'; import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes'; import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes'; @@ -97,7 +96,7 @@ export const ObjectFilterDropdownFilterInput = ({ )} {filterType === 'ACTOR' && ( <> - + )} {filterType === 'ADDRESS' && diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts index 9eb66850a..a97e2e8ff 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts @@ -59,7 +59,7 @@ describe('getOperandsForFilterType', () => { ['LINKS', [...containsOperands, ...emptyOperands], 'secondaryLinks'], ['ACTOR', [...containsOperands, ...emptyOperands], 'name'], ['ACTOR', [...actorSourceOperands, ...emptyOperands], 'source'], - ['ACTOR', [...actorSourceOperands, ...emptyOperands]], + ['ACTOR', [...containsOperands, ...emptyOperands]], [ 'CURRENCY', [...currencyCurrencyCodeOperands, ...emptyOperands], diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter.ts index 3308bb54c..092992bea 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter.ts @@ -886,139 +886,81 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ } } case 'ACTOR': { - if (isSubFieldFilter) { - switch (subFieldName) { - case 'source': { - switch (recordFilter.operand) { - case RecordFilterOperand.Is: { - if (recordFilter.value === '[]') { - return; - } - - const parsedSources = JSON.parse( - recordFilter.value, - ) as string[]; - - return { - [correspondingFieldMetadataItem.name]: { - source: { - in: parsedSources, - } satisfies RelationFilter, - }, - }; - } - case RecordFilterOperand.IsNot: { - if (recordFilter.value === '[]') { - return; - } - - const parsedSources = JSON.parse( - recordFilter.value, - ) as string[]; - - if (parsedSources.length === 0) return; - - return { - not: { - [correspondingFieldMetadataItem.name]: { - source: { - in: parsedSources, - } satisfies RelationFilter, - }, - }, - }; - } - default: - throw new Error( - `Unknown operand ${recordFilter.operand} for ${recordFilter.label} filter`, - ); - } - } - case 'name': { - switch (recordFilter.operand) { - case RecordFilterOperand.Contains: - return { - or: [ - { - [correspondingFieldMetadataItem.name]: { - name: { - ilike: `%${recordFilter.value}%`, - }, - } satisfies ActorFilter, - }, - ], - }; - case RecordFilterOperand.DoesNotContain: - return { - and: [ - { - not: { - [correspondingFieldMetadataItem.name]: { - name: { - ilike: `%${recordFilter.value}%`, - }, - } satisfies ActorFilter, - }, - }, - ], - }; - default: - throw new Error( - `Unknown operand ${recordFilter.operand} for ${recordFilter.label} filter`, - ); - } - } - } - break; - } else { - if (recordFilter.value === '[]') { - return; - } - - const parsedSources = JSON.parse(recordFilter.value) as string[]; - - if (parsedSources.length === 0) return; - + if (subFieldName === 'source') { switch (recordFilter.operand) { - case RecordFilterOperand.Is: + case RecordFilterOperand.Is: { + if (recordFilter.value === '[]') { + return; + } + + const parsedSources = JSON.parse(recordFilter.value) as string[]; + return { [correspondingFieldMetadataItem.name]: { source: { in: parsedSources, - }, - } satisfies ActorFilter, + } satisfies RelationFilter, + }, }; - case RecordFilterOperand.IsNot: + } + case RecordFilterOperand.IsNot: { + if (recordFilter.value === '[]') { + return; + } + + const parsedSources = JSON.parse(recordFilter.value) as string[]; + + if (parsedSources.length === 0) return; + return { - and: [ - { - or: [ - { - not: { - [correspondingFieldMetadataItem.name]: { - source: { - in: parsedSources, - }, - } satisfies ActorFilter, - }, - }, - { - [correspondingFieldMetadataItem.name]: { - source: { - is: 'NULL', - }, - } satisfies ActorFilter, - }, - ], + not: { + [correspondingFieldMetadataItem.name]: { + source: { + in: parsedSources, + } satisfies RelationFilter, }, - ], + }, }; + } default: throw new Error( `Unknown operand ${recordFilter.operand} for ${recordFilter.label} filter`, ); } } + + switch (recordFilter.operand) { + case RecordFilterOperand.Contains: + return { + or: [ + { + [correspondingFieldMetadataItem.name]: { + name: { + ilike: `%${recordFilter.value}%`, + }, + } satisfies ActorFilter, + }, + ], + }; + case RecordFilterOperand.DoesNotContain: + return { + and: [ + { + not: { + [correspondingFieldMetadataItem.name]: { + name: { + ilike: `%${recordFilter.value}%`, + }, + } satisfies ActorFilter, + }, + }, + ], + }; + default: + throw new Error( + `Unknown operand ${recordFilter.operand} for ${recordFilter.label} filter`, + ); + } } case 'EMAILS': { return computeGqlOperationFilterForEmails({ diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts index 07e9ea5bb..d2ca3688e 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts @@ -25,7 +25,7 @@ export const getDefaultSubFieldNameForCompositeFilterableFieldType = ( case 'ADDRESS': return undefined; case 'ACTOR': - return 'source'; + return 'name'; case 'FULL_NAME': return undefined; default: diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts index 53a66fce3..828e68462 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts @@ -3,7 +3,6 @@ import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dro import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType'; import { CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName'; import { ViewFilterOperand as RecordFilterOperand } from '@/views/types/ViewFilterOperand'; -import { isNonEmptyString } from '@sniptt/guards'; import { FieldMetadataType } from 'twenty-shared/types'; import { assertUnreachable } from 'twenty-shared/utils'; @@ -148,8 +147,6 @@ export const getRecordFilterOperands = ({ filterType, subFieldName, }: GetRecordFilterOperandsParams) => { - const isFilterOnSubField = isNonEmptyString(subFieldName); - switch (filterType) { case 'TEXT': case 'EMAILS': @@ -187,7 +184,7 @@ export const getRecordFilterOperands = ({ case 'SELECT': return FILTER_OPERANDS_MAP.SELECT; case 'ACTOR': { - if (isFilterOnActorSourceSubField(subFieldName) || !isFilterOnSubField) { + if (isFilterOnActorSourceSubField(subFieldName)) { return [ RecordFilterOperand.Is, RecordFilterOperand.IsNot,