Advanced filters bug bash (#11178)

This commit is contained in:
Lucas Bordeau
2025-03-26 11:06:53 +01:00
committed by GitHub
parent 7d6573e766
commit 8cc9f77417
15 changed files with 190 additions and 137 deletions

View File

@ -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,
})
: [];

View File

@ -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)) {

View File

@ -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={
<DropdownMenuItemsContainer>
<ObjectFilterDropdownFilterInput />
</DropdownMenuItemsContainer>
<ObjectFilterDropdownFilterInput recordFilterId={filter.id} />
}
dropdownHotkeyScope={{ scope: dropdownId }}
dropdownOffset={{ y: 8, x: 0 }}
dropdownPlacement="bottom-start"
dropdownMenuWidth={280}
dropdownMenuWidth={200}
/>
)}
</StyledValueDropdownContainer>

View File

@ -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('');
};

View File

@ -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}
/>
);

View File

@ -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 && <ObjectFilterDropdownTextInput />}
{TEXT_FILTER_TYPES.includes(filterType) && (
<ObjectFilterDropdownTextInput />
)}
{NUMBER_FILTER_TYPES.includes(filterType) && (
<ObjectFilterDropdownNumberInput />
)}
@ -87,15 +90,21 @@ export const ObjectFilterDropdownFilterInput = ({
<>
<ObjectFilterDropdownSearchInput />
<DropdownMenuSeparator />
<ObjectFilterDropdownRecordSelect />
</>
)}
{filterType === 'ACTOR' && isActorSourceCompositeFilter && (
<>
<DropdownMenuSeparator />
<ObjectFilterDropdownSourceSelect />
<ObjectFilterDropdownRecordSelect
recordFilterId={recordFilterId}
/>
</>
)}
{filterType === 'ACTOR' &&
(isActorSourceCompositeFilter ? (
<>
<ObjectFilterDropdownSourceSelect />
</>
) : (
<>
<ObjectFilterDropdownTextInput />
</>
))}
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
<>
<ObjectFilterDropdownSearchInput />

View File

@ -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)) {

View File

@ -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 && (
<DropdownMenuInput
ref={handleInputRef}
value={inputValue}
autoFocus
type="number"
placeholder={fieldMetadataItemUsedInDropdown.label}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value;
<DropdownMenuItemsContainer>
<DropdownMenuInput
ref={handleInputRef}
value={inputValue}
autoFocus
type="number"
placeholder={fieldMetadataItemUsedInDropdown.label}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
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,
});
}}
/>
</DropdownMenuItemsContainer>
)
);
};

View File

@ -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,

View File

@ -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<FieldRatingValue, null>,
): string => {
@ -51,7 +56,7 @@ export const ObjectFilterDropdownRatingInput = () => {
return (
fieldMetadataItemUsedInDropdown &&
selectedOperandInDropdown && (
<DropdownMenuItemsContainer>
<StyledRatingInputContainer>
<RatingInput
value={selectedFilter?.value as FieldRatingValue}
onChange={(newValue: FieldRatingValue) => {
@ -73,7 +78,7 @@ export const ObjectFilterDropdownRatingInput = () => {
});
}}
/>
</DropdownMenuItemsContainer>
</StyledRatingInputContainer>
)
);
};

View File

@ -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,
});
}
}
};

View File

@ -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',
});
}
};

View File

@ -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 && (
<DropdownMenuInput
ref={handleInputRef}
value={inputValue}
autoFocus
type="text"
placeholder={fieldMetadataItemUsedInDropdown.label}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value;
<DropdownMenuItemsContainer>
<DropdownMenuInput
ref={handleInputRef}
value={inputValue}
autoFocus
type="text"
placeholder={fieldMetadataItemUsedInDropdown.label}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
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,
});
}}
/>
</DropdownMenuItemsContainer>
)
);
};

View File

@ -6,7 +6,6 @@ export const TEXT_FILTER_TYPES = [
'LINK',
'LINKS',
'ADDRESS',
'ACTOR',
'ARRAY',
'RAW_JSON',
];

View File

@ -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;