From ba8797d22009b32ec1953de939fbed228f7f02e3 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Thu, 13 Feb 2025 00:57:28 +0100 Subject: [PATCH] Remove filterDefinition.type usage (#10164) This PR essentially removes the usage of filterDefinition.type, by replacing it with fieldMetadataItem.type derivation. Thus allowing to completely remove filterDefinition later on. In computeFilterRecordGqlOperationFilter, emptyOperationFilter is now returned before going into the big switch case. This avoids repeating the same exact call to getEmptyRecordGqlOperationFilter for each type. Fixed some tests that need getJestMetadataAndApolloMocksAndActionMenuWrapper to have record filters properly working with the new implementation. We'll probably want to refactor the record context store, record index context, etc. Co-authored-by: Charles Bochet --- .../computeContextStoreFilters.test.ts | 19 +- ...ColumnDefinitionsFromFieldMetadata.test.ts | 6 +- .../useColumnDefinitionsFromFieldMetadata.ts | 25 +- .../AdvancedFilterViewFilterOperandSelect.tsx | 24 +- .../components/AdvancedFilterButton.tsx | 19 +- .../MultipleFiltersDropdownContent.tsx | 13 +- ...ersDropdownFilterOnFilterChangedEffect.tsx | 26 +- .../ObjectFilterDropdownFilterInput.tsx | 52 +-- ...jectFilterDropdownFilterSelectMenuItem.tsx | 9 +- ...EntityObjectFilterDropdownButtonEffect.tsx | 15 +- ...useSelectFilterDefinitionUsedInDropdown.ts | 16 +- .../getOperandsForFilterType.test.ts | 9 +- .../useObjectOptionsForBoard.test.tsx | 91 ++--- ...omputeViewRecordGqlOperationFilter.test.ts | 5 +- .../computeViewRecordGqlOperationFilter.ts | 315 +++++++----------- .../utils/getEmptyRecordGqlOperationFilter.ts | 31 +- ...FilterOperandsForRecordFilterDefinition.ts | 99 ------ .../hooks/useHandleToggleColumnFilter.ts | 14 +- ...ViewFiltersToCurrentRecordFilters.test.tsx | 24 +- ...ViewFiltersToCurrentRecordFilters.test.tsx | 22 +- .../WorkflowEditTriggerCronForm.tsx | 2 +- ...taAndApolloMocksAndContextStoreWrapper.tsx | 50 ++- .../getJestMetadataAndApolloMocksWrapper.tsx | 32 +- 23 files changed, 427 insertions(+), 491 deletions(-) delete mode 100644 packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition.ts diff --git a/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts index ec8f071713..1321cd0446 100644 --- a/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts +++ b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts @@ -73,9 +73,22 @@ describe('computeContextStoreFilters', () => { expect(filters).toEqual({ and: [ { - name: { - ilike: '%John%', - }, + or: [ + { + name: { + firstName: { + ilike: '%John%', + }, + }, + }, + { + name: { + lastName: { + ilike: '%John%', + }, + }, + }, + ], }, { not: { diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts index 90e76e6d44..65b3de83d8 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useColumnDefinitionsFromFieldMetadata.test.ts @@ -9,11 +9,13 @@ import { SubscriptionStatus, WorkspaceActivationStatus, } from '~/generated/graphql'; -import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; +import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; -const Wrapper = getJestMetadataAndApolloMocksWrapper({ +const Wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({ apolloMocks: [], + componentInstanceId: 'instanceId', + contextStoreCurrentObjectMetadataNameSingular: 'company', onInitializeRecoilSnapshot: ({ set }) => { set(currentWorkspaceState, { id: '1', diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata.ts index 09bf1aaf61..07fc72adcd 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata.ts @@ -6,10 +6,8 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata' import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import { FeatureFlagKey } from '~/generated/graphql'; +import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext'; import { formatFieldMetadataItemAsColumnDefinition } from '../utils/formatFieldMetadataItemAsColumnDefinition'; -import { formatFieldMetadataItemsAsFilterDefinitions } from '../utils/formatFieldMetadataItemsAsFilterDefinitions'; import { formatFieldMetadataItemsAsSortDefinitions } from '../utils/formatFieldMetadataItemsAsSortDefinitions'; export const useColumnDefinitionsFromFieldMetadata = ( @@ -25,14 +23,8 @@ export const useColumnDefinitionsFromFieldMetadata = ( [objectMetadataItem], ); - const isJsonFilterEnabled = useIsFeatureEnabled( - FeatureFlagKey.IsJsonFilterEnabled, - ); - - const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({ - fields: activeFieldMetadataItems, - isJsonFilterEnabled, - }); + const { filterableFieldMetadataItems } = + useFilterableFieldMetadataItemsInRecordIndexContext(); const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({ fields: activeFieldMetadataItems, @@ -51,9 +43,11 @@ export const useColumnDefinitionsFromFieldMetadata = ( ) .filter(filterAvailableTableColumns) .map((column) => { - const existsInFilterDefinitions = filterDefinitions.some( - (filter) => filter.fieldMetadataId === column.fieldMetadataId, - ); + const existsInFilterDefinitions = + filterableFieldMetadataItems.some( + (fieldMetadataItem) => + fieldMetadataItem.id === column.fieldMetadataId, + ); const existsInSortDefinitions = sortDefinitions.some( (sort) => sort.fieldMetadataId === column.fieldMetadataId, @@ -67,16 +61,15 @@ export const useColumnDefinitionsFromFieldMetadata = ( }) : [], [ + filterableFieldMetadataItems, activeFieldMetadataItems, objectMetadataItem, - filterDefinitions, sortDefinitions, ], ); return { columnDefinitions, - filterDefinitions, sortDefinitions, }; }; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect.tsx index 8daba133cc..2c149f68be 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect.tsx @@ -1,7 +1,9 @@ +import { useGetFieldMetadataItemById } from '@/object-metadata/hooks/useGetFieldMetadataItemById'; +import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { useCurrentViewFilter } from '@/object-record/advanced-filter/hooks/useCurrentViewFilter'; import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue'; import { getOperandLabel } from '@/object-record/object-filter-dropdown/utils/getOperandLabel'; -import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition'; +import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { SelectControl } from '@/ui/input/components/SelectControl'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -28,6 +30,8 @@ export const AdvancedFilterViewFilterOperandSelect = ({ const filter = useCurrentViewFilter({ viewFilterId }); + const { getFieldMetadataItemById } = useGetFieldMetadataItemById(); + const isDisabled = !filter?.fieldMetadataId; const { closeDropdown } = useDropdown(dropdownId); @@ -41,8 +45,16 @@ export const AdvancedFilterViewFilterOperandSelect = ({ throw new Error('Filter is not defined'); } + const fieldMetadataItem = getFieldMetadataItemById(filter.fieldMetadataId); + + if (!isDefined(fieldMetadataItem)) { + throw new Error('Field metadata item is not defined'); + } + + const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type); + const { value, displayValue } = getInitialFilterValue( - filter.definition.type, + filterType, operand, filter.value, filter.displayValue, @@ -56,8 +68,12 @@ export const AdvancedFilterViewFilterOperandSelect = ({ }); }; - const operandsForFilterType = isDefined(filter?.definition) - ? getRecordFilterOperandsForRecordFilterDefinition(filter.definition) + const filterType = filter?.type; + + const operandsForFilterType = isDefined(filterType) + ? getRecordFilterOperands({ + filterType, + }) : []; if (isDisabled === true) { diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/AdvancedFilterButton.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/AdvancedFilterButton.tsx index 8ea9ce944a..816706facb 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/AdvancedFilterButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/AdvancedFilterButton.tsx @@ -1,9 +1,13 @@ import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector'; -import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { + formatFieldMetadataItemAsFilterDefinition, + getFilterTypeFromFieldType, +} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup'; import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId'; -import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition'; +import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; + import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; @@ -110,11 +114,18 @@ export const AdvancedFilterButton = () => { field: defaultFieldMetadataItem, }); + const filterType = getFilterTypeFromFieldType( + defaultFieldMetadataItem.type, + ); + + const firstOperand = getRecordFilterOperands({ + filterType, + })[0]; + upsertCombinedViewFilter({ id: v4(), fieldMetadataId: defaultFieldMetadataItem.id, - operand: - getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0], + operand: firstOperand, definition: filterDefinition, value: '', displayValue: '', diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx index 08c3d8b06f..67b613264e 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx @@ -1,10 +1,8 @@ import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu'; import { ObjectFilterOperandSelectAndInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterOperandSelectAndInput'; -import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect'; import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect'; @@ -15,11 +13,6 @@ type MultipleFiltersDropdownContentProps = { export const MultipleFiltersDropdownContent = ({ filterDropdownId, }: MultipleFiltersDropdownContentProps) => { - const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( - filterDefinitionUsedInDropdownComponentState, - filterDropdownId, - ); - const [objectFilterDropdownIsSelectingCompositeField] = useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, @@ -47,11 +40,7 @@ export const MultipleFiltersDropdownContent = ({ ) : ( )} - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx index 5b8d12162b..06b434804a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx @@ -1,16 +1,28 @@ import { useEffect } from 'react'; +import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { isDefined } from 'twenty-shared'; -export const MultipleFiltersDropdownFilterOnFilterChangedEffect = ({ - filterDefinitionUsedInDropdownType, -}: { - filterDefinitionUsedInDropdownType: string | undefined; -}) => { +export const MultipleFiltersDropdownFilterOnFilterChangedEffect = () => { const { setDropdownWidth } = useDropdown(); + const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + useEffect(() => { - switch (filterDefinitionUsedInDropdownType) { + if (!isDefined(fieldMetadataItemUsedInDropdown)) { + return; + } + + const filterType = getFilterTypeFromFieldType( + fieldMetadataItemUsedInDropdown.type, + ); + + switch (filterType) { case 'DATE': case 'DATE_TIME': setDropdownWidth(280); @@ -18,7 +30,7 @@ export const MultipleFiltersDropdownFilterOnFilterChangedEffect = ({ default: setDropdownWidth(200); } - }, [filterDefinitionUsedInDropdownType, setDropdownWidth]); + }, [fieldMetadataItemUsedInDropdown, setDropdownWidth]); return null; }; 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 891521ee65..3121c2dd62 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 @@ -6,17 +6,19 @@ import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter- import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput'; import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect'; import { ObjectFilterDropdownTextSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput'; -import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { isDefined } from 'twenty-shared'; +import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect'; import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes'; import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes'; import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes'; -import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; +import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; +import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState'; +import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; type ObjectFilterDropdownFilterInputProps = { @@ -26,10 +28,16 @@ type ObjectFilterDropdownFilterInputProps = { export const ObjectFilterDropdownFilterInput = ({ filterDropdownId, }: ObjectFilterDropdownFilterInputProps) => { - const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( - filterDefinitionUsedInDropdownComponentState, + const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, filterDropdownId, ); + + const subFieldNameUsedInDropdown = useRecoilComponentValueV2( + subFieldNameUsedInDropdownComponentState, + filterDropdownId, + ); + const selectedOperandInDropdown = useRecoilComponentValueV2( selectedOperandInDropdownComponentState, filterDropdownId, @@ -50,52 +58,54 @@ export const ObjectFilterDropdownFilterInput = ({ ViewFilterOperand.IsRelative, ].includes(selectedOperandInDropdown); - if (!isDefined(filterDefinitionUsedInDropdown)) { + if (!isDefined(fieldMetadataItemUsedInDropdown)) { return null; } + const filterType = getFilterTypeFromFieldType( + fieldMetadataItemUsedInDropdown.type, + ); + + const isActorSourceCompositeFilter = isFilterOnActorSourceSubField( + subFieldNameUsedInDropdown, + ); + return ( <> {isConfigurable && selectedOperandInDropdown && ( <> - {TEXT_FILTER_TYPES.includes(filterDefinitionUsedInDropdown.type) && - !isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && ( + {TEXT_FILTER_TYPES.includes(filterType) && + !isActorSourceCompositeFilter && ( )} - {NUMBER_FILTER_TYPES.includes( - filterDefinitionUsedInDropdown.type, - ) && } - {filterDefinitionUsedInDropdown.type === 'RATING' && ( - + {NUMBER_FILTER_TYPES.includes(filterType) && ( + )} - {DATE_FILTER_TYPES.includes(filterDefinitionUsedInDropdown.type) && ( + {filterType === 'RATING' && } + {DATE_FILTER_TYPES.includes(filterType) && ( )} - {filterDefinitionUsedInDropdown.type === 'RELATION' && ( + {filterType === 'RELATION' && ( <> )} - {isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && ( + {isActorSourceCompositeFilter && ( <> )} - {['SELECT', 'MULTI_SELECT'].includes( - filterDefinitionUsedInDropdown.type, - ) && ( + {['SELECT', 'MULTI_SELECT'].includes(filterType) && ( <> )} - {filterDefinitionUsedInDropdown.type === 'BOOLEAN' && ( - - )} + {filterType === 'BOOLEAN' && } )} diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx index 6e4603772d..9ea449a6b7 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx @@ -91,16 +91,15 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({ setFilterDefinitionUsedInDropdown(filterDefinition); - if ( - filterDefinition.type === 'RELATION' || - filterDefinition.type === 'SELECT' - ) { + const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type); + + if (filterType === 'RELATION' || filterType === 'SELECT') { setHotkeyScope(RelationPickerHotkeyScope.RelationPicker); } setSelectedOperandInDropdown( getRecordFilterOperands({ - filterType: filterDefinition.type, + filterType, })[0], ); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButtonEffect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButtonEffect.tsx index 58c9ba456a..be0c30e8d5 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButtonEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButtonEffect.tsx @@ -1,9 +1,12 @@ -import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { + formatFieldMetadataItemAsFilterDefinition, + getFilterTypeFromFieldType, +} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext'; -import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition'; +import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useEffect } from 'react'; @@ -30,14 +33,16 @@ export const SingleEntityObjectFilterDropdownButtonEffect = () => { }); useEffect(() => { - setFieldMetadataItemIdUsedInDropdown(firstFieldDefinition.fieldMetadataId); + setFieldMetadataItemIdUsedInDropdown(firstFieldMetadataItem.id); setFilterDefinitionUsedInDropdown(firstFieldDefinition); - const defaultOperand = - getRecordFilterOperandsForRecordFilterDefinition(firstFieldDefinition)[0]; + const filterType = getFilterTypeFromFieldType(firstFieldMetadataItem.type); + + const defaultOperand = getRecordFilterOperands({ filterType })[0]; setSelectedOperandInDropdown(defaultOperand); }, [ + firstFieldMetadataItem, firstFieldDefinition, setFilterDefinitionUsedInDropdown, setSelectedOperandInDropdown, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown.ts index db3d2255f6..71ba160d83 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown.ts @@ -6,7 +6,8 @@ import { selectedOperandInDropdownComponentState } from '@/object-record/object- import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; -import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition'; +import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; + import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -62,13 +63,15 @@ export const useSelectFilterDefinitionUsedInDropdown = ( setHotkeyScope(RelationPickerHotkeyScope.RelationPicker); } - setSelectedOperandInDropdown( - getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0], - ); + const firstOperand = getRecordFilterOperands({ + filterType: filterDefinition.type, + })[0]; + + setSelectedOperandInDropdown(firstOperand); const { value, displayValue } = getInitialFilterValue( filterDefinition.type, - getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0], + firstOperand, ); const isAdvancedFilter = isDefined(advancedFilterViewFilterId); @@ -78,8 +81,7 @@ export const useSelectFilterDefinitionUsedInDropdown = ( id: advancedFilterViewFilterId ?? v4(), fieldMetadataId: filterDefinition.fieldMetadataId, displayValue, - operand: - getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0], + operand: firstOperand, value, definition: filterDefinition, viewFilterGroupId: advancedFilterViewFilterGroupId, 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 b4f8b45976..dbe5c921ff 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 @@ -1,7 +1,6 @@ import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType'; -import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; -import { getRecordFilterOperandsForRecordFilterDefinition } from '../../../record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition'; +import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; describe('getOperandsForFilterType', () => { const emptyOperands = [ @@ -49,9 +48,9 @@ describe('getOperandsForFilterType', () => { testCases.forEach(([filterType, expectedOperands]) => { it(`should return correct operands for FilterType.${filterType}`, () => { - const result = getRecordFilterOperandsForRecordFilterDefinition({ - type: filterType as FilterableFieldType, - } as RecordFilterDefinition); + const result = getRecordFilterOperands({ + filterType: filterType as FilterableFieldType, + }); expect(result).toEqual(expectedOperands); }); }); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useObjectOptionsForBoard.test.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useObjectOptionsForBoard.test.tsx index 055e62271f..875b65bc70 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useObjectOptionsForBoard.test.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/__tests__/useObjectOptionsForBoard.test.tsx @@ -3,7 +3,8 @@ import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/s import { DropResult, ResponderProvided } from '@hello-pangea/dnd'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; -import { RecoilRoot } from 'recoil'; +import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; +import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; jest.mock('@/views/hooks/useSaveCurrentViewFields', () => ({ useSaveCurrentViewFields: jest.fn(() => ({ @@ -17,53 +18,67 @@ jest.mock('@/views/hooks/useUpdateCurrentView', () => ({ })), })); -jest.mock('@/object-metadata/hooks/useObjectMetadataItem', () => ({ - useObjectMetadataItem: jest.fn(() => ({ - objectMetadataItem: { - fields: [ - { - id: 'field1', - name: 'field1', - label: 'Field 1', - isVisible: true, - position: 0, - }, - { - id: 'field2', - name: 'field2', - label: 'Field 2', - isVisible: true, - position: 1, - }, - ], - }, - })), -})); +const objectNameSingular = 'company'; describe('useObjectOptionsForBoard', () => { + const mockObjectMetadataItem = generatedMockObjectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingular, + ); + + if (!mockObjectMetadataItem) { + throw new Error('Mock object metadata item not found'); + } + + const mockFieldMetadataItem1 = mockObjectMetadataItem.fields.find( + (field) => field.name === 'name', + ); + + if (!mockFieldMetadataItem1) { + throw new Error('Mock field metadata item not found for "name"'); + } + + const mockFieldMetadataItem2 = mockObjectMetadataItem.fields.find( + (field) => field.name === 'createdAt', + ); + + if (!mockFieldMetadataItem2) { + throw new Error('Mock field metadata item not found for "createdAt"'); + } + const initialRecoilState = [ - { fieldMetadataId: 'field1', isVisible: true, position: 0 }, - { fieldMetadataId: 'field2', isVisible: true, position: 1 }, + { + fieldMetadataId: mockFieldMetadataItem1.id, + isVisible: true, + position: 0, + }, + { + fieldMetadataId: mockFieldMetadataItem2.id, + isVisible: true, + position: 1, + }, ]; const renderWithRecoil = () => renderHook( () => useObjectOptionsForBoard({ - objectNameSingular: 'object', + objectNameSingular, recordBoardId: 'boardId', viewBarId: 'viewBarId', }), { - wrapper: ({ children }) => ( - { - set(recordIndexFieldDefinitionsState, initialRecoilState as any); - }} - > - {children} - - ), + wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({ + apolloMocks: [], + onInitializeRecoilSnapshot: (snapshot) => { + snapshot.set( + recordIndexFieldDefinitionsState, + initialRecoilState as any, + ); + }, + componentInstanceId: 'test', + contextStoreCurrentObjectMetadataNameSingular: objectNameSingular, + }), }, ); @@ -73,7 +88,7 @@ describe('useObjectOptionsForBoard', () => { const dropResult: DropResult = { source: { droppableId: 'droppable', index: 1 }, destination: { droppableId: 'droppable', index: 2 }, - draggableId: 'field1', + draggableId: mockFieldMetadataItem1.id, type: 'TYPE', mode: 'FLUID', reason: 'DROP', @@ -90,12 +105,12 @@ describe('useObjectOptionsForBoard', () => { expect(result.current.visibleBoardFields).toEqual([ { - fieldMetadataId: 'field2', + fieldMetadataId: mockFieldMetadataItem2.id, isVisible: true, position: 0, }, { - fieldMetadataId: 'field1', + fieldMetadataId: mockFieldMetadataItem1.id, isVisible: true, position: 1, }, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts index e4b7b4985d..18a8b2d269 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts @@ -1,4 +1,5 @@ import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; import { RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies'; import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; @@ -33,7 +34,9 @@ describe('computeViewRecordGqlOperationFilter', () => { value: companiesMock[0].name, fieldMetadataId: companyMockNameFieldMetadataId?.id, displayValue: companiesMock[0].name, - operand: ViewFilterOperand.Contains, + operand: RecordFilterOperand.Contains, + type: 'TEXT', + label: 'Name', definition: { type: 'TEXT', fieldMetadataId: companyMockNameFieldMetadataId?.id, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/computeViewRecordGqlOperationFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/computeViewRecordGqlOperationFilter.ts index 5e22001820..bf7f219c2c 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/computeViewRecordGqlOperationFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/computeViewRecordGqlOperationFilter.ts @@ -22,6 +22,7 @@ import { isDefined } from 'twenty-shared'; import { Field } from '~/generated/graphql'; import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; +import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { convertGreaterThanRatingToArrayOfRatingValues, convertLessThanRatingToArrayOfRatingValues, @@ -40,22 +41,35 @@ import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/valid import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns'; import { z } from 'zod'; -const computeFilterRecordGqlOperationFilter = ( - filterValueDependencies: RecordFilterValueDependencies, - filter: RecordFilter, - fields: Pick[], -): RecordGqlOperationFilter | undefined => { +import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType'; + +type ComputeFilterRecordGqlOperationFilterParams = { + filterValueDependencies: RecordFilterValueDependencies; + filter: RecordFilter; + fieldMetadataItems: Pick[]; +}; + +export const computeFilterRecordGqlOperationFilter = ({ + filterValueDependencies, + filter, + fieldMetadataItems: fields, +}: ComputeFilterRecordGqlOperationFilterParams): + | RecordGqlOperationFilter + | undefined => { const correspondingField = fields.find( (field) => field.id === filter.fieldMetadataId, ); - const compositeFieldName = filter.definition.compositeFieldName; + const compositeFieldName = filter.subFieldName; const isCompositeFieldFiter = isNonEmptyString(compositeFieldName); - const isEmptyOperand = [ + const isEmptinessOperand = [ RecordFilterOperand.IsEmpty, RecordFilterOperand.IsNotEmpty, + ].includes(filter.operand); + + const isDateOperandWithoutValue = [ RecordFilterOperand.IsInPast, RecordFilterOperand.IsInFuture, RecordFilterOperand.IsToday, @@ -65,13 +79,35 @@ const computeFilterRecordGqlOperationFilter = ( return; } - if (!isEmptyOperand) { - if (!isDefined(filter.value) || filter.value === '') { - return; - } + const filterType = getFilterTypeFromFieldType(correspondingField.type); + + const isFilterValueEmpty = !isDefined(filter.value) || filter.value === ''; + + const shouldSkipFiltering = + !isEmptinessOperand && !isDateOperandWithoutValue && isFilterValueEmpty; + + if (shouldSkipFiltering) { + return; } - switch (filter.definition.type) { + const filterTypesThatHaveNoEmptinessOperand: FilterableFieldType[] = [ + 'BOOLEAN', + ]; + + const filterHasEmptinessOperands = + !filterTypesThatHaveNoEmptinessOperand.includes(filterType); + + if (filterHasEmptinessOperands && isEmptinessOperand) { + const emptyOperationFilter = getEmptyRecordGqlOperationFilter({ + operand: filter.operand, + correspondingField, + recordFilter: filter, + }); + + return emptyOperationFilter; + } + + switch (filterType) { case 'TEXT': switch (filter.operand) { case RecordFilterOperand.Contains: @@ -88,16 +124,9 @@ const computeFilterRecordGqlOperationFilter = ( } as StringFilter, }, }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } case 'RAW_JSON': @@ -116,16 +145,9 @@ const computeFilterRecordGqlOperationFilter = ( } as RawJsonFilter, }, }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } case 'DATE': @@ -150,14 +172,6 @@ const computeFilterRecordGqlOperationFilter = ( } as DateFilter, }; } - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: { - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); - } case RecordFilterOperand.IsRelative: { const dateRange = z .object({ start: z.date(), end: z.date() }) @@ -238,7 +252,7 @@ const computeFilterRecordGqlOperationFilter = ( } default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, // + `Unknown operand ${filter.operand} for ${filterType} filter`, // ); } } @@ -266,16 +280,10 @@ const computeFilterRecordGqlOperationFilter = ( ), } as RatingFilter, }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); + default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } case 'NUMBER': @@ -292,83 +300,61 @@ const computeFilterRecordGqlOperationFilter = ( lte: parseFloat(filter.value), } as FloatFilter, }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } case 'RELATION': { - if (!isEmptyOperand) { - const { isCurrentWorkspaceMemberSelected, selectedRecordIds } = - jsonRelationFilterValueSchema - .catch({ - isCurrentWorkspaceMemberSelected: false, - selectedRecordIds: simpleRelationFilterValueSchema.parse( - filter.value, - ), - }) - .parse(filter.value); + const { isCurrentWorkspaceMemberSelected, selectedRecordIds } = + jsonRelationFilterValueSchema + .catch({ + isCurrentWorkspaceMemberSelected: false, + selectedRecordIds: simpleRelationFilterValueSchema.parse( + filter.value, + ), + }) + .parse(filter.value); - const recordIds = isCurrentWorkspaceMemberSelected - ? [ - ...selectedRecordIds, - filterValueDependencies.currentWorkspaceMemberId, - ] - : selectedRecordIds; + const recordIds = isCurrentWorkspaceMemberSelected + ? [ + ...selectedRecordIds, + filterValueDependencies.currentWorkspaceMemberId, + ] + : selectedRecordIds; - if (recordIds.length === 0) return; - switch (filter.operand) { - case RecordFilterOperand.Is: - return { - [correspondingField.name + 'Id']: { - in: recordIds, - } as RelationFilter, - }; - case RecordFilterOperand.IsNot: { - if (recordIds.length === 0) return; - return { - or: [ - { - not: { - [correspondingField.name + 'Id']: { - in: recordIds, - } as RelationFilter, - }, - }, - { + if (recordIds.length === 0) return; + + switch (filter.operand) { + case RecordFilterOperand.Is: + return { + [correspondingField.name + 'Id']: { + in: recordIds, + } as RelationFilter, + }; + case RecordFilterOperand.IsNot: { + if (recordIds.length === 0) return; + return { + or: [ + { + not: { [correspondingField.name + 'Id']: { - is: 'NULL', + in: recordIds, } as RelationFilter, }, - ], - }; - } - default: - throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, - ); - } - } else { - switch (filter.operand) { - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); - default: - throw new Error( - `Unknown empty operand ${filter.operand} for ${filter.definition.type} filter`, - ); + }, + { + [correspondingField.name + 'Id']: { + is: 'NULL', + } as RelationFilter, + }, + ], + }; } + default: + throw new Error( + `Unknown operand ${filter.operand} for ${filterType} filter`, + ); } } case 'CURRENCY': @@ -385,16 +371,9 @@ const computeFilterRecordGqlOperationFilter = ( amountMicros: { lte: parseFloat(filter.value) * 1000000 }, } as CurrencyFilter, }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } case 'LINKS': { @@ -439,16 +418,9 @@ const computeFilterRecordGqlOperationFilter = ( }, }; } - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } } @@ -493,16 +465,9 @@ const computeFilterRecordGqlOperationFilter = ( }, }; } - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } } @@ -609,27 +574,12 @@ const computeFilterRecordGqlOperationFilter = ( }, }; } - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } case 'MULTI_SELECT': { - if (isEmptyOperand) { - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); - } - const options = resolveSelectViewFilterValue(filter); if (options.length === 0) return; @@ -665,18 +615,11 @@ const computeFilterRecordGqlOperationFilter = ( }; default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } } case 'SELECT': { - if (isEmptyOperand) { - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); - } const options = resolveSelectViewFilterValue(filter); if (options.length === 0) return; @@ -698,7 +641,7 @@ const computeFilterRecordGqlOperationFilter = ( }; default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } } @@ -718,16 +661,9 @@ const computeFilterRecordGqlOperationFilter = ( } as ArrayFilter, }, }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } } @@ -786,13 +722,6 @@ const computeFilterRecordGqlOperationFilter = ( }, ], }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( `Unknown operand ${filter.operand} for ${filter.label} filter`, @@ -827,16 +756,9 @@ const computeFilterRecordGqlOperationFilter = ( }, ], }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } case 'PHONES': { @@ -869,16 +791,9 @@ const computeFilterRecordGqlOperationFilter = ( }, ], }; - case RecordFilterOperand.IsEmpty: - case RecordFilterOperand.IsNotEmpty: - return getEmptyRecordGqlOperationFilter( - filter.operand, - correspondingField, - filter.definition, - ); default: throw new Error( - `Unknown operand ${filter.operand} for ${filter.definition.type} filter`, + `Unknown operand ${filter.operand} for ${filterType} filter`, ); } } @@ -897,7 +812,7 @@ const computeFilterRecordGqlOperationFilter = ( const computeViewFilterGroupRecordGqlOperationFilter = ( filterValueDependencies: RecordFilterValueDependencies, filters: RecordFilter[], - fields: Pick[], + fields: Pick[], viewFilterGroups: ViewFilterGroup[], currentViewFilterGroupId?: string, ): RecordGqlOperationFilter | undefined => { @@ -915,11 +830,11 @@ const computeViewFilterGroupRecordGqlOperationFilter = ( const groupRecordGqlOperationFilters = groupFilters .map((filter) => - computeFilterRecordGqlOperationFilter( + computeFilterRecordGqlOperationFilter({ filterValueDependencies, filter, - fields, - ), + fieldMetadataItems: fields, + }), ) .filter(isDefined); @@ -968,17 +883,17 @@ const computeViewFilterGroupRecordGqlOperationFilter = ( export const computeViewRecordGqlOperationFilter = ( filterValueDependencies: RecordFilterValueDependencies, filters: RecordFilter[], - fields: Pick[], + fields: Pick[], viewFilterGroups: ViewFilterGroup[], ): RecordGqlOperationFilter => { const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] = filters .filter((filter) => !filter.viewFilterGroupId) .map((regularFilter) => - computeFilterRecordGqlOperationFilter( + computeFilterRecordGqlOperationFilter({ filterValueDependencies, - regularFilter, - fields, - ), + filter: regularFilter, + fieldMetadataItems: fields, + }), ) .filter(isDefined); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter.ts index cabfc67d77..f5f3d2cb31 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter.ts @@ -1,3 +1,4 @@ +import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { ActorFilter, AddressFilter, @@ -15,24 +16,32 @@ import { StringFilter, URLFilter, } from '@/object-record/graphql/types/RecordGqlOperationFilter'; -import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; +import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { isNonEmptyString } from '@sniptt/guards'; import { Field } from '~/generated/graphql'; import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; -export const getEmptyRecordGqlOperationFilter = ( - operand: ViewFilterOperand, - correspondingField: Pick, - definition: RecordFilterDefinition, -) => { +type GetEmptyRecordGqlOperationFilterParams = { + operand: ViewFilterOperand; + correspondingField: Pick; + recordFilter: RecordFilter; +}; + +export const getEmptyRecordGqlOperationFilter = ({ + operand, + correspondingField, + recordFilter, +}: GetEmptyRecordGqlOperationFilterParams) => { let emptyRecordFilter: RecordGqlOperationFilter = {}; - const compositeFieldName = definition.compositeFieldName; + const compositeFieldName = recordFilter.subFieldName; const isCompositeField = isNonEmptyString(compositeFieldName); - switch (definition.type) { + const filterType = getFilterTypeFromFieldType(correspondingField.type); + + switch (filterType) { case 'TEXT': emptyRecordFilter = { or: [ @@ -344,7 +353,7 @@ export const getEmptyRecordGqlOperationFilter = ( }; break; default: - throw new Error(`Unsupported empty filter type ${definition.type}`); + throw new Error(`Unsupported empty filter type ${filterType}`); } switch (operand) { @@ -355,8 +364,6 @@ export const getEmptyRecordGqlOperationFilter = ( not: emptyRecordFilter, }; default: - throw new Error( - `Unknown operand ${operand} for ${definition.type} filter`, - ); + throw new Error(`Unknown operand ${operand} for ${filterType} filter`); } }; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition.ts deleted file mode 100644 index 9effb72028..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter'; -import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; -import { ViewFilterOperand as RecordFilterOperand } from '@/views/types/ViewFilterOperand'; - -export const getRecordFilterOperandsForRecordFilterDefinition = ( - filterDefinition: Pick, -): RecordFilterOperand[] => { - const emptyOperands = [ - RecordFilterOperand.IsEmpty, - RecordFilterOperand.IsNotEmpty, - ]; - - const relationOperands = [RecordFilterOperand.Is, RecordFilterOperand.IsNot]; - - switch (filterDefinition.type) { - case 'TEXT': - case 'EMAILS': - case 'FULL_NAME': - case 'ADDRESS': - case 'LINKS': - case 'PHONES': - return [ - RecordFilterOperand.Contains, - RecordFilterOperand.DoesNotContain, - ...emptyOperands, - ]; - case 'CURRENCY': - case 'NUMBER': - return [ - RecordFilterOperand.GreaterThan, - RecordFilterOperand.LessThan, - ...emptyOperands, - ]; - case 'RAW_JSON': - return [ - RecordFilterOperand.Contains, - RecordFilterOperand.DoesNotContain, - ...emptyOperands, - ]; - case 'DATE_TIME': - case 'DATE': - return [ - RecordFilterOperand.Is, - RecordFilterOperand.IsRelative, - RecordFilterOperand.IsInPast, - RecordFilterOperand.IsInFuture, - RecordFilterOperand.IsToday, - RecordFilterOperand.IsBefore, - RecordFilterOperand.IsAfter, - ...emptyOperands, - ]; - case 'RATING': - return [ - RecordFilterOperand.Is, - RecordFilterOperand.GreaterThan, - RecordFilterOperand.LessThan, - ...emptyOperands, - ]; - case 'RELATION': - return [...relationOperands, ...emptyOperands]; - case 'MULTI_SELECT': - return [ - RecordFilterOperand.Contains, - RecordFilterOperand.DoesNotContain, - ...emptyOperands, - ]; - case 'SELECT': - return [ - RecordFilterOperand.Is, - RecordFilterOperand.IsNot, - ...emptyOperands, - ]; - case 'ACTOR': { - if (isActorSourceCompositeFilter(filterDefinition)) { - return [ - RecordFilterOperand.Is, - RecordFilterOperand.IsNot, - ...emptyOperands, - ]; - } - - return [ - RecordFilterOperand.Contains, - RecordFilterOperand.DoesNotContain, - ...emptyOperands, - ]; - } - case 'ARRAY': - return [ - RecordFilterOperand.Contains, - RecordFilterOperand.DoesNotContain, - ...emptyOperands, - ]; - case 'BOOLEAN': - return [RecordFilterOperand.Is]; - default: - return []; - } -}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts index d9614843b8..ef5e2f0b3e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts @@ -5,12 +5,15 @@ import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/u import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector'; -import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { + formatFieldMetadataItemAsFilterDefinition, + getFilterTypeFromFieldType, +} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { useSelectFilterDefinitionUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown'; import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition'; +import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; @@ -115,8 +118,11 @@ export const useHandleToggleColumnFilter = ({ throw new Error('Filter definition not found'); } - const availableOperandsForFilter = - getRecordFilterOperandsForRecordFilterDefinition(filterDefinition); + const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type); + + const availableOperandsForFilter = getRecordFilterOperands({ + filterType, + }); const defaultOperand = availableOperandsForFilter[0]; diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx index 327d3a0005..149237b5c8 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx @@ -13,15 +13,17 @@ import { currentViewIdComponentState } from '@/views/states/currentViewIdCompone import { ViewFilter } from '@/views/types/ViewFilter'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { isDefined } from 'twenty-shared'; -import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; +import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters'; jest.mock('@/prefetch/hooks/usePrefetchedData'); +const mockObjectMetadataItemNameSingular = 'company'; + describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { const mockObjectMetadataItem = generatedMockObjectMetadataItems.find( - (item) => item.nameSingular === 'company', + (item) => item.nameSingular === mockObjectMetadataItemNameSingular, ); if (!isDefined(mockObjectMetadataItem)) { @@ -76,7 +78,11 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { }; }, { - wrapper: getJestMetadataAndApolloMocksWrapper({ + wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({ + apolloMocks: [], + componentInstanceId: 'instanceId', + contextStoreCurrentObjectMetadataNameSingular: + mockObjectMetadataItemNameSingular, onInitializeRecoilSnapshot: (snapshot) => { snapshot.set( currentViewIdComponentState.atomFamily({ @@ -129,7 +135,11 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { }; }, { - wrapper: getJestMetadataAndApolloMocksWrapper({ + wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({ + apolloMocks: [], + componentInstanceId: 'instanceId', + contextStoreCurrentObjectMetadataNameSingular: + mockObjectMetadataItemNameSingular, onInitializeRecoilSnapshot: (snapshot) => { snapshot.set( currentViewIdComponentState.atomFamily({ @@ -174,7 +184,11 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => { }; }, { - wrapper: getJestMetadataAndApolloMocksWrapper({ + wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({ + apolloMocks: [], + componentInstanceId: 'instanceId', + contextStoreCurrentObjectMetadataNameSingular: + mockObjectMetadataItemNameSingular, onInitializeRecoilSnapshot: (snapshot) => { snapshot.set( currentViewIdComponentState.atomFamily({ diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx index b17767c935..7b972a08e2 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx @@ -11,18 +11,20 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/ import { ViewFilter } from '@/views/types/ViewFilter'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { isDefined } from 'twenty-shared'; -import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; +import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; import { useApplyViewFiltersToCurrentRecordFilters } from '../useApplyViewFiltersToCurrentRecordFilters'; +const mockObjectMetadataItemNameSingular = 'company'; + describe('useApplyViewFiltersToCurrentRecordFilters', () => { const mockObjectMetadataItem = generatedMockObjectMetadataItems.find( - (item) => item.nameSingular === 'company', + (item) => item.nameSingular === mockObjectMetadataItemNameSingular, ); if (!isDefined(mockObjectMetadataItem)) { throw new Error( - 'Missing mock object metadata item with name singular "company"', + `Missing mock object metadata item with name singular ${mockObjectMetadataItemNameSingular}`, ); } @@ -58,7 +60,12 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => { return { applyViewFiltersToCurrentRecordFilters, currentFilters }; }, { - wrapper: getJestMetadataAndApolloMocksWrapper({}), + wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({ + apolloMocks: [], + componentInstanceId: 'instanceId', + contextStoreCurrentObjectMetadataNameSingular: + mockObjectMetadataItemNameSingular, + }), }, ); @@ -95,7 +102,12 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => { return { applyViewFiltersToCurrentRecordFilters, currentFilters }; }, { - wrapper: getJestMetadataAndApolloMocksWrapper({}), + wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({ + apolloMocks: [], + componentInstanceId: 'instanceId', + contextStoreCurrentObjectMetadataNameSingular: + mockObjectMetadataItemNameSingular, + }), }, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx index 3ef5e6172e..9612ddd80d 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx @@ -121,7 +121,7 @@ export const WorkflowEditTriggerCronForm = ({ const cronValidator = cron(newPattern); - if (cronValidator.isError()) { + if (cronValidator.isError() === true) { setErrorMessages({ CUSTOM: `Invalid cron pattern, ${cronValidator .getError()[0] diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx index b01c98be40..aa7eaa19d7 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx @@ -1,14 +1,17 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; import { MockedResponse } from '@apollo/client/testing'; import { ReactNode } from 'react'; import { MutableSnapshot } from 'recoil'; +import { isDefined } from 'twenty-shared'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; import { JestContextStoreSetter, JestContextStoreSetterMocks, } from '~/testing/jest/JestContextStoreSetter'; +import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; export type GetJestMetadataAndApolloMocksAndActionMenuWrapperProps = { apolloMocks: @@ -32,6 +35,18 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({ onInitializeRecoilSnapshot, }); + const mockObjectMetadataItem = generatedMockObjectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === + contextStoreCurrentObjectMetadataNameSingular, + ); + + if (!isDefined(mockObjectMetadataItem)) { + throw new Error( + `Mock object metadata item ${contextStoreCurrentObjectMetadataNameSingular} not found`, + ); + } + return ({ children }: { children: ReactNode }) => ( - 'indexIdentifierUrl', + onIndexRecordsLoaded: () => {}, + objectNamePlural: mockObjectMetadataItem.namePlural, + objectNameSingular: mockObjectMetadataItem.nameSingular, + objectMetadataItem: mockObjectMetadataItem, + recordIndexId: 'recordIndexId', + }} > - {children} - + + {children} + + diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx index 4a838c24b4..41f286708c 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksWrapper.tsx @@ -3,12 +3,10 @@ import { ReactNode } from 'react'; import { MutableSnapshot, RecoilRoot } from 'recoil'; import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { InMemoryCache } from '@apollo/client'; import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter'; -import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; export const getJestMetadataAndApolloMocksWrapper = ({ apolloMocks, @@ -25,31 +23,17 @@ export const getJestMetadataAndApolloMocksWrapper = ({ - 'indexIdentifierUrl', - onIndexRecordsLoaded: () => {}, - objectNamePlural: 'objectNamePlural', - objectNameSingular: 'objectNameSingular', - objectMetadataItem: - generatedMockObjectMetadataItems.find( - (item) => item.nameSingular === 'company', - ) ?? generatedMockObjectMetadataItems[0], - recordIndexId: 'recordIndexId', - }} + - - - - {children} - - - - + + {children} + + +