diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx index 63ee78ad8..17a7074ca 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx @@ -13,8 +13,8 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import styled from '@emotion/styled'; -import { MenuItem } from 'twenty-ui'; import { isDefined } from 'twenty-shared/utils'; +import { MenuItem } from 'twenty-ui'; const StyledContainer = styled.div` flex: 1; @@ -80,6 +80,7 @@ export const AdvancedFilterRecordFilterOperandSelect = ({ const operandsForFilterType = isDefined(filterType) ? getRecordFilterOperands({ filterType, + subFieldName: filter?.subFieldName, }) : []; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx index 5b9902eb3..918251f05 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx @@ -12,6 +12,7 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState'; +import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState'; import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel'; import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel'; import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs'; @@ -37,6 +38,10 @@ export const AdvancedFilterSubFieldSelectMenu = ({ objectFilterDropdownFilterIsSelectedComponentState, ); + const [, setSubFieldNameUsedInDropdown] = useRecoilComponentStateV2( + subFieldNameUsedInDropdownComponentState, + ); + const [, setObjectFilterDropdownIsSelectingCompositeField] = useRecoilComponentStateV2( objectFilterDropdownIsSelectingCompositeFieldComponentState, @@ -81,6 +86,7 @@ export const AdvancedFilterSubFieldSelectMenu = ({ setObjectFilterDropdownSubMenuFieldType(null); setObjectFilterDropdownIsSelectingCompositeField(false); setObjectFilterDropdownFilterIsSelected(false); + setSubFieldNameUsedInDropdown(null); }; if (!isDefined(objectFilterDropdownSubMenuFieldType)) { diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx index 446e22fcf..2d21233fb 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx @@ -6,7 +6,6 @@ import { configurableViewFilterOperands } from '@/object-record/object-filter-dr import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { SelectControl } from '@/ui/input/components/SelectControl'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; @@ -79,14 +78,12 @@ export const AdvancedFilterValueInputDropdownButton = ({ setSelectedFilter(filter); }} dropdownComponents={ - - - + } dropdownHotkeyScope={{ scope: dropdownId }} dropdownOffset={{ y: 8, x: 0 }} dropdownPlacement="bottom-start" - dropdownMenuWidth={280} + dropdownMenuWidth={200} /> )} diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts index 8437da734..1c98de863 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts @@ -72,6 +72,7 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => { const firstOperand = getRecordFilterOperands({ filterType, + subFieldName, })[0]; setSelectedOperandInDropdown(firstOperand); @@ -97,9 +98,7 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => { subFieldName, }); - if (isDefined(subFieldName)) { - setSubFieldNameUsedInDropdown(subFieldName); - } + setSubFieldNameUsedInDropdown(subFieldName); setObjectFilterDropdownSearchInput(''); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx index bff15daf8..2823f756f 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx @@ -16,8 +16,8 @@ import { VariableDateViewFilterValueUnit, } from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; import { useState } from 'react'; -import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from 'twenty-shared/utils'; +import { FieldMetadataType } from '~/generated-metadata/graphql'; export const ObjectFilterDropdownDateInput = () => { const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( @@ -114,7 +114,6 @@ export const ObjectFilterDropdownDateInput = () => { date={internalDate} onChange={handleAbsoluteDateChange} onRelativeDateChange={handleRelativeDateChange} - onClose={handleAbsoluteDateChange} isDateTimeInput={isDateTimeInput} /> ); 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 f3a93a9f1..3580d3f3d 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 @@ -23,10 +23,12 @@ import { isDefined } from 'twenty-shared/utils'; type ObjectFilterDropdownFilterInputProps = { filterDropdownId?: string; + recordFilterId?: string; }; export const ObjectFilterDropdownFilterInput = ({ filterDropdownId, + recordFilterId, }: ObjectFilterDropdownFilterInputProps) => { const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( fieldMetadataItemUsedInDropdownComponentSelector, @@ -74,8 +76,9 @@ export const ObjectFilterDropdownFilterInput = ({ <> {isConfigurable && selectedOperandInDropdown && ( <> - {TEXT_FILTER_TYPES.includes(filterType) && - !isActorSourceCompositeFilter && } + {TEXT_FILTER_TYPES.includes(filterType) && ( + + )} {NUMBER_FILTER_TYPES.includes(filterType) && ( )} @@ -87,15 +90,21 @@ export const ObjectFilterDropdownFilterInput = ({ <> - - - )} - {filterType === 'ACTOR' && isActorSourceCompositeFilter && ( - <> - - + )} + {filterType === 'ACTOR' && + (isActorSourceCompositeFilter ? ( + <> + + + ) : ( + <> + + + ))} {['SELECT', 'MULTI_SELECT'].includes(filterType) && ( <> diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx index 40f59eb26..dad887061 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx @@ -22,8 +22,8 @@ import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useState } from 'react'; -import { IconApps, IconChevronLeft, MenuItem, useIcons } from 'twenty-ui'; import { isDefined } from 'twenty-shared/utils'; +import { IconApps, IconChevronLeft, MenuItem, useIcons } from 'twenty-ui'; export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => { const [searchText] = useState(''); @@ -126,6 +126,7 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => { setObjectFilterDropdownSubMenuFieldType(null); setObjectFilterDropdownIsSelectingCompositeField(false); setObjectFilterDropdownFilterIsSelected(false); + setSubFieldNameUsedInDropdown(null); }; if (!isDefined(objectFilterDropdownSubMenuFieldType)) { diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx index 12a27edb7..398ea06be 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput.tsx @@ -7,6 +7,7 @@ import { selectedFilterComponentState } from '@/object-record/object-filter-drop import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; +import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; export const ObjectFilterDropdownNumberInput = () => { @@ -44,31 +45,33 @@ export const ObjectFilterDropdownNumberInput = () => { return ( fieldMetadataItemUsedInDropdown && selectedOperandInDropdown && ( - ) => { - const newValue = event.target.value; + + ) => { + const newValue = event.target.value; - setInputValue(newValue); + setInputValue(newValue); - applyRecordFilter({ - id: selectedFilter?.id ? selectedFilter.id : v4(), - fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '', - value: newValue, - operand: selectedOperandInDropdown, - displayValue: newValue, - type: getFilterTypeFromFieldType( - fieldMetadataItemUsedInDropdown.type, - ), - label: fieldMetadataItemUsedInDropdown.label, - recordFilterGroupId: selectedFilter?.recordFilterGroupId, - }); - }} - /> + applyRecordFilter({ + id: selectedFilter?.id ? selectedFilter.id : v4(), + fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '', + value: newValue, + operand: selectedOperandInDropdown, + displayValue: newValue, + type: getFilterTypeFromFieldType( + fieldMetadataItemUsedInDropdown.type, + ), + label: fieldMetadataItemUsedInDropdown.label, + recordFilterGroupId: selectedFilter?.recordFilterGroupId, + }); + }} + /> + ) ); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx index d04037cbf..424b9f512 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx @@ -14,9 +14,9 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import styled from '@emotion/styled'; +import { isDefined } from 'twenty-shared/utils'; import { MenuItem } from 'twenty-ui'; import { getOperandLabel } from '../utils/getOperandLabel'; -import { isDefined } from 'twenty-shared/utils'; const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)` background-color: ${({ theme }) => theme.background.primary}; @@ -66,7 +66,7 @@ export const ObjectFilterDropdownOperandSelect = () => { if (isValuelessOperand && isDefined(fieldMetadataItemUsedInDropdown)) { applyRecordFilter({ - id: v4(), + id: selectedFilter?.id ? selectedFilter.id : v4(), fieldMetadataId: fieldMetadataItemUsedInDropdown.id, displayValue: '', operand: newOperand, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx index 352e3d649..553fceda8 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx @@ -5,12 +5,17 @@ import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { RatingInput } from '@/ui/field/input/components/RatingInput'; -import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; +import styled from '@emotion/styled'; + +const StyledRatingInputContainer = styled.div` + padding: ${({ theme }) => theme.spacing(2)}; +`; + const convertFieldRatingValueToNumber = ( rating: Exclude, ): string => { @@ -51,7 +56,7 @@ export const ObjectFilterDropdownRatingInput = () => { return ( fieldMetadataItemUsedInDropdown && selectedOperandInDropdown && ( - + { @@ -73,7 +78,7 @@ export const ObjectFilterDropdownRatingInput = () => { }); }} /> - + ) ); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx index 67000ca6b..f5ed91e91 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx @@ -7,24 +7,23 @@ import { ObjectFilterDropdownRecordPinnedItems } from '@/object-record/object-fi import { CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID } from '@/object-record/object-filter-dropdown/constants/CurrentWorkspaceMemberSelectableItemId'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; -import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState'; import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters'; import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope'; import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown'; import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect'; import { SelectableItem } from '@/object-record/select/types/SelectableItem'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { RelationFilterValue } from '@/views/view-filter-value/types/RelationFilterValue'; import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema'; import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/simpleRelationFilterValueSchema'; +import { isDefined } from 'twenty-shared/utils'; import { IconUserCircle } from 'twenty-ui'; import { v4 } from 'uuid'; -import { isDefined } from 'twenty-shared/utils'; export const EMPTY_FILTER_VALUE: string = JSON.stringify({ isCurrentWorkspaceMemberSelected: false, @@ -35,10 +34,12 @@ export const MAX_RECORDS_TO_DISPLAY = 3; type ObjectFilterDropdownRecordSelectProps = { viewComponentId?: string; + recordFilterId?: string; }; export const ObjectFilterDropdownRecordSelect = ({ viewComponentId, + recordFilterId, }: ObjectFilterDropdownRecordSelectProps) => { const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValueV2( fieldMetadataItemUsedInDropdownComponentSelector, @@ -56,12 +57,8 @@ export const ObjectFilterDropdownRecordSelect = ({ objectFilterDropdownSearchInputComponentState, ); - const objectFilterDropdownSelectedRecordIds = useRecoilComponentValueV2( - objectFilterDropdownSelectedRecordIdsComponentState, - ); - - const setObjectFilterDropdownSelectedRecordIds = useSetRecoilComponentStateV2( - objectFilterDropdownSelectedRecordIdsComponentState, + const currentRecordFilters = useRecoilComponentValueV2( + currentRecordFiltersComponentState, ); const { applyRecordFilter } = useApplyRecordFilter(viewComponentId); @@ -97,10 +94,34 @@ export const ObjectFilterDropdownRecordSelect = ({ throw new Error('objectNameSingular is not defined'); } + const firstSimpleRecordFilterForFieldMetadataItemUsedInDropdown = + currentRecordFilters.find( + (filter) => + filter.fieldMetadataId === fieldMetadataItemUsedInFilterDropdown?.id && + !isDefined(filter.recordFilterGroupId), + ); + + const recordFilterPassedInProps = currentRecordFilters.find( + (filter) => filter.id === recordFilterId, + ); + + const recordFilterUsedInDropdown = isDefined(recordFilterId) + ? recordFilterPassedInProps + : firstSimpleRecordFilterForFieldMetadataItemUsedInDropdown; + + const { selectedRecordIds } = jsonRelationFilterValueSchema + .catch({ + isCurrentWorkspaceMemberSelected: false, + selectedRecordIds: simpleRelationFilterValueSchema.parse( + recordFilterUsedInDropdown?.value, + ), + }) + .parse(recordFilterUsedInDropdown?.value); + const { loading, filteredSelectedRecords, recordsToSelect, selectedRecords } = useRecordsForSelect({ searchFilterText: objectFilterDropdownSearchInput, - selectedIds: objectFilterDropdownSelectedRecordIds, + selectedIds: selectedRecordIds, objectNameSingular, limit: 10, }); @@ -123,10 +144,6 @@ export const ObjectFilterDropdownRecordSelect = ({ .includes(objectFilterDropdownSearchInput.toLowerCase()), ); - const currentRecordFilters = useRecoilComponentValueV2( - currentRecordFiltersComponentState, - ); - const handleMultipleRecordSelectChange = ( itemToSelect: SelectableItem, isNewSelectedValue: boolean, @@ -139,17 +156,16 @@ export const ObjectFilterDropdownRecordSelect = ({ itemToSelect.id === CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID; const selectedRecordIdsWithAddedRecord = [ - ...objectFilterDropdownSelectedRecordIds, + ...selectedRecordIds, itemToSelect.id, ]; - const selectedRecordIdsWithRemovedRecord = - objectFilterDropdownSelectedRecordIds.filter( - (id) => id !== itemToSelect.id, - ); + const selectedRecordIdsWithRemovedRecord = selectedRecordIds.filter( + (id) => id !== itemToSelect.id, + ); const newSelectedRecordIds = isItemCurrentWorkspaceMember - ? objectFilterDropdownSelectedRecordIds + ? selectedRecordIds : isNewSelectedValue ? selectedRecordIdsWithAddedRecord : selectedRecordIdsWithRemovedRecord; @@ -194,28 +210,44 @@ export const ObjectFilterDropdownRecordSelect = ({ } satisfies RelationFilterValue) : ''; - const recordFilterInDropdown = currentRecordFilters.find( - (recordFilter) => - recordFilter.fieldMetadataId === - fieldMetadataItemUsedInFilterDropdown.id, + const duplicateFilterInCurrentRecordFilters = + findDuplicateRecordFilterInNonAdvancedRecordFilters({ + recordFilters: currentRecordFilters, + fieldMetadataItemId: fieldMetadataItemUsedInFilterDropdown.id, + }); + + const filterIsAlreadyInCurrentRecordFilters = isDefined( + duplicateFilterInCurrentRecordFilters, ); - setObjectFilterDropdownSelectedRecordIds(newSelectedRecordIds); - - const filterId = recordFilterInDropdown?.id ?? v4(); - - applyRecordFilter({ - id: selectedFilter?.id ? selectedFilter.id : filterId, - type: getFilterTypeFromFieldType( - fieldMetadataItemUsedInFilterDropdown.type, - ), - label: fieldMetadataItemUsedInFilterDropdown.label, - operand: selectedOperandInDropdown, - displayValue: filterDisplayValue, - fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id, - value: newFilterValue, - recordFilterGroupId: selectedFilter?.recordFilterGroupId, - }); + if (filterIsAlreadyInCurrentRecordFilters && !isDefined(recordFilterId)) { + applyRecordFilter({ + id: duplicateFilterInCurrentRecordFilters.id, + type: getFilterTypeFromFieldType( + fieldMetadataItemUsedInFilterDropdown.type, + ), + label: fieldMetadataItemUsedInFilterDropdown.label, + operand: selectedOperandInDropdown, + displayValue: filterDisplayValue, + fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id, + value: newFilterValue, + recordFilterGroupId: + duplicateFilterInCurrentRecordFilters.recordFilterGroupId, + }); + } else { + applyRecordFilter({ + id: selectedFilter?.id ? selectedFilter.id : v4(), + type: getFilterTypeFromFieldType( + fieldMetadataItemUsedInFilterDropdown.type, + ), + label: fieldMetadataItemUsedInFilterDropdown.label, + operand: selectedOperandInDropdown, + displayValue: filterDisplayValue, + fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id, + value: newFilterValue, + recordFilterGroupId: selectedFilter?.recordFilterGroupId, + }); + } } }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx index 05722e9ac..032c27237 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect.tsx @@ -1,8 +1,4 @@ -import { useState } from 'react'; -import { v4 } from 'uuid'; - import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; -import { useEmptyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useEmptyRecordFilter'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState'; @@ -10,8 +6,8 @@ import { selectedFilterComponentState } from '@/object-record/object-filter-drop import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { getActorSourceMultiSelectOptions } from '@/object-record/object-filter-dropdown/utils/getActorSourceMultiSelectOptions'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; -import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters'; import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope'; import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown'; import { SelectableItem } from '@/object-record/select/types/SelectableItem'; @@ -19,6 +15,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { isDefined } from 'twenty-shared/utils'; +import { v4 } from 'uuid'; export const EMPTY_FILTER_VALUE = '[]'; export const MAX_ITEMS_TO_DISPLAY = 3; @@ -56,9 +53,6 @@ export const ObjectFilterDropdownSourceSelect = ({ const { applyRecordFilter } = useApplyRecordFilter(viewComponentId); - // TODO: this should be removed as it is not consistent across re-renders - const [fieldId] = useState(v4()); - const sourceTypes = getActorSourceMultiSelectOptions( objectFilterDropdownSelectedRecordIds, ); @@ -67,10 +61,6 @@ export const ObjectFilterDropdownSourceSelect = ({ objectFilterDropdownSelectedRecordIds.includes(option.id), ); - const { emptyRecordFilter } = useEmptyRecordFilter(); - - const { removeRecordFilter } = useRemoveRecordFilter(); - const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -91,13 +81,6 @@ export const ObjectFilterDropdownSourceSelect = ({ ); } - if (newSelectedItemIds.length === 0) { - emptyRecordFilter(); - removeRecordFilter(fieldMetadataItemUsedInFilterDropdown.id); - - return; - } - setObjectFilterDropdownSelectedRecordIds(newSelectedItemIds); const selectedItemNames = sourceTypes @@ -118,13 +101,20 @@ export const ObjectFilterDropdownSourceSelect = ({ ? JSON.stringify(newSelectedItemIds) : EMPTY_FILTER_VALUE; - const recordFilter = currentRecordFilters.find( - (recordFilter) => - recordFilter.fieldMetadataId === - fieldMetadataItemUsedInFilterDropdown.id, + const duplicateFilterInCurrentRecordFilters = + findDuplicateRecordFilterInNonAdvancedRecordFilters({ + recordFilters: currentRecordFilters, + fieldMetadataItemId: fieldMetadataItemUsedInFilterDropdown.id, + subFieldName: 'source', + }); + + const filterIsAlreadyInCurrentRecordFilters = isDefined( + duplicateFilterInCurrentRecordFilters, ); - const filterId = recordFilter?.id ?? fieldId; + const filterId = filterIsAlreadyInCurrentRecordFilters + ? duplicateFilterInCurrentRecordFilters?.id + : v4(); applyRecordFilter({ id: selectedFilter?.id ? selectedFilter.id : filterId, @@ -137,6 +127,7 @@ export const ObjectFilterDropdownSourceSelect = ({ fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id, value: newFilterValue, recordFilterGroupId: selectedFilter?.recordFilterGroupId, + subFieldName: 'source', }); } }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx index e22856d88..754f941bf 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput.tsx @@ -7,6 +7,7 @@ import { selectedFilterComponentState } from '@/object-record/object-filter-drop import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; +import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; export const ObjectFilterDropdownTextInput = () => { @@ -44,31 +45,33 @@ export const ObjectFilterDropdownTextInput = () => { return ( fieldMetadataItemUsedInDropdown && selectedOperandInDropdown && ( - ) => { - const newValue = event.target.value; + + ) => { + const newValue = event.target.value; - setInputValue(newValue); + setInputValue(newValue); - applyRecordFilter({ - id: selectedFilter?.id ? selectedFilter.id : v4(), - fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '', - value: newValue, - operand: selectedOperandInDropdown, - displayValue: newValue, - type: getFilterTypeFromFieldType( - fieldMetadataItemUsedInDropdown.type, - ), - label: fieldMetadataItemUsedInDropdown.label, - recordFilterGroupId: selectedFilter?.recordFilterGroupId, - }); - }} - /> + applyRecordFilter({ + id: selectedFilter?.id ? selectedFilter.id : v4(), + fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '', + value: newValue, + operand: selectedOperandInDropdown, + displayValue: newValue, + type: getFilterTypeFromFieldType( + fieldMetadataItemUsedInDropdown.type, + ), + label: fieldMetadataItemUsedInDropdown.label, + recordFilterGroupId: selectedFilter?.recordFilterGroupId, + }); + }} + /> + ) ); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/constants/TextFilterTypes.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/constants/TextFilterTypes.ts index 0c702e01c..ef63718ba 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/constants/TextFilterTypes.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/constants/TextFilterTypes.ts @@ -6,7 +6,6 @@ export const TEXT_FILTER_TYPES = [ 'LINK', 'LINKS', 'ADDRESS', - 'ACTOR', 'ARRAY', 'RAW_JSON', ]; 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 755ce536d..c7e28c0a8 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 @@ -671,6 +671,10 @@ export const computeFilterRecordGqlOperationFilter = ({ case 'ACTOR': { switch (filter.operand) { case RecordFilterOperand.Is: { + if (filter.value === '[]') { + return; + } + const parsedRecordIds = JSON.parse(filter.value) as string[]; return { @@ -682,6 +686,10 @@ export const computeFilterRecordGqlOperationFilter = ({ }; } case RecordFilterOperand.IsNot: { + if (filter.value === '[]') { + return; + } + const parsedRecordIds = JSON.parse(filter.value) as string[]; if (parsedRecordIds.length === 0) return;