Record filters - Introduced fieldMetadataItemUsedInDropdown instead of filterDefinitionUsedInDropdown (#10044)

This PR progressively introduces fieldMetadataItemUsedInDropdown instead
of filterDefinitionUsedInDropdown where most easy to replace.

This allows to use `fieldMetadataItemUsedInDropdown.id` instead of
`filterDefinition.fieldMetadataId`, which is one easy dependency to
remove on filter definition.

We still derive filterDefinition instead of fully replacing it, because
it will be easier to remove RecordFilterDefinition usage in a bottom-up
approach instead.

In multiple components of the filter dropdown, we try to replace
filterDefinition by fieldMetadataItem derivation : Icon, label, id,
type, etc.

We also introduce the usage of subFieldNameUsedInDropdown instead of
storing it dynamically on filterDefinition, for handling filtering on
composite sub fields.

The method `formatFieldMetadataItemAsFilterDefinition()` that is used to
derive filterDefinition from fieldMetadataItem is what was being used
originally to create the availableFilterDefinition state. (That is
already removed)

Fixed associated unit tests accordingly.
This commit is contained in:
Lucas Bordeau
2025-02-06 11:03:55 +01:00
committed by GitHub
parent e21cbb2fe2
commit 049a0118aa
34 changed files with 483 additions and 209 deletions
@@ -54,10 +54,8 @@ describe('useColumnDefinitionsFromFieldMetadata', () => {
); );
expect(Array.isArray(result.current.columnDefinitions)).toBe(true); expect(Array.isArray(result.current.columnDefinitions)).toBe(true);
expect(Array.isArray(result.current.filterDefinitions)).toBe(true);
expect(Array.isArray(result.current.sortDefinitions)).toBe(true); expect(Array.isArray(result.current.sortDefinitions)).toBe(true);
expect(result.current.columnDefinitions.length).toBe(0); expect(result.current.columnDefinitions.length).toBe(0);
expect(result.current.filterDefinitions.length).toBe(0);
expect(result.current.sortDefinitions.length).toBe(0); expect(result.current.sortDefinitions.length).toBe(0);
}); });
@@ -76,11 +74,9 @@ describe('useColumnDefinitionsFromFieldMetadata', () => {
}, },
); );
const { columnDefinitions, filterDefinitions, sortDefinitions } = const { columnDefinitions, sortDefinitions } = result.current;
result.current;
expect(columnDefinitions.length).toBe(21); expect(columnDefinitions.length).toBe(21);
expect(filterDefinitions.length).toBe(17);
expect(sortDefinitions.length).toBe(14); expect(sortDefinitions.length).toBe(14);
}); });
}); });
@@ -4,6 +4,7 @@ import {
RelationDefinitionType, RelationDefinitionType,
} from '~/generated-metadata/graphql'; } from '~/generated-metadata/graphql';
import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
import { ObjectMetadataItem } from '../types/ObjectMetadataItem'; import { ObjectMetadataItem } from '../types/ObjectMetadataItem';
export const formatFieldMetadataItemsAsFilterDefinitions = ({ export const formatFieldMetadataItemsAsFilterDefinitions = ({
@@ -79,7 +80,9 @@ export const getRelationObjectMetadataNamePlural = ({
return field.relationDefinition?.targetObjectMetadata.namePlural; return field.relationDefinition?.targetObjectMetadata.namePlural;
}; };
export const getFilterTypeFromFieldType = (fieldType: FieldMetadataType) => { export const getFilterTypeFromFieldType = (
fieldType: FieldMetadataType,
): FilterableFieldType => {
switch (fieldType) { switch (fieldType) {
case FieldMetadataType.DATE_TIME: case FieldMetadataType.DATE_TIME:
return 'DATE_TIME'; return 'DATE_TIME';
@@ -1,8 +1,11 @@
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector'; 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 { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition'; import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
@@ -86,12 +89,17 @@ export const AdvancedFilterAddFilterRuleSelect = ({
field: defaultFieldMetadataItem, field: defaultFieldMetadataItem,
}); });
const filterType = getFilterTypeFromFieldType(
defaultFieldMetadataItem.type,
);
upsertCombinedViewFilter({ upsertCombinedViewFilter({
id: v4(), id: v4(),
fieldMetadataId: defaultFieldMetadataItem.id, fieldMetadataId: defaultFieldMetadataItem.id,
operand: getRecordFilterOperandsForRecordFilterDefinition( type: filterType,
defaultFilterDefinition, operand: getRecordFilterOperands({
)[0], filterType,
})[0],
definition: defaultFilterDefinition, definition: defaultFilterDefinition,
value: '', value: '',
displayValue: '', displayValue: '',
@@ -123,12 +131,17 @@ export const AdvancedFilterAddFilterRuleSelect = ({
field: defaultFieldMetadataItem, field: defaultFieldMetadataItem,
}); });
const filterType = getFilterTypeFromFieldType(
defaultFieldMetadataItem.type,
);
upsertCombinedViewFilter({ upsertCombinedViewFilter({
id: v4(), id: v4(),
fieldMetadataId: defaultFieldMetadataItem.id, fieldMetadataId: defaultFieldMetadataItem.id,
operand: getRecordFilterOperandsForRecordFilterDefinition( type: filterType,
defaultFilterDefinition, operand: getRecordFilterOperands({
)[0], filterType,
})[0],
definition: defaultFilterDefinition, definition: defaultFilterDefinition,
value: '', value: '',
displayValue: '', displayValue: '',
@@ -25,9 +25,9 @@ export const AdvancedFilterViewFilterFieldSelect = ({
}: AdvancedFilterViewFilterFieldSelectProps) => { }: AdvancedFilterViewFilterFieldSelectProps) => {
const { advancedFilterDropdownId } = useAdvancedFilterDropdown(viewFilterId); const { advancedFilterDropdownId } = useAdvancedFilterDropdown(viewFilterId);
const filter = useCurrentViewFilter({ viewFilterId }); const recordFilter = useCurrentViewFilter({ viewFilterId });
const selectedFieldLabel = filter?.definition.label ?? ''; const selectedFieldLabel = recordFilter?.label ?? '';
const setAdvancedFilterViewFilterId = useSetRecoilComponentStateV2( const setAdvancedFilterViewFilterId = useSetRecoilComponentStateV2(
advancedFilterViewFilterIdComponentState, advancedFilterViewFilterIdComponentState,
@@ -58,8 +58,8 @@ export const AdvancedFilterViewFilterFieldSelect = ({
/> />
} }
onOpen={() => { onOpen={() => {
setAdvancedFilterViewFilterId(filter?.id); setAdvancedFilterViewFilterId(recordFilter?.id);
setAdvancedFilterViewFilterGroupId(filter?.viewFilterGroupId); setAdvancedFilterViewFilterGroupId(recordFilter?.viewFilterGroupId);
}} }}
dropdownComponents={ dropdownComponents={
shouldShowCompositeSelectionSubMenu ? ( shouldShowCompositeSelectionSubMenu ? (
@@ -3,7 +3,8 @@ import styled from '@emotion/styled';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { formatFieldMetadataItemAsFilterDefinition } 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 { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
@@ -39,8 +40,8 @@ export const ObjectFilterDropdownBooleanSelect = () => {
const theme = useTheme(); const theme = useTheme();
const options = [true, false]; const options = [true, false];
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const selectedOperandInDropdown = useRecoilComponentValueV2( const selectedOperandInDropdown = useRecoilComponentValueV2(
@@ -65,18 +66,22 @@ export const ObjectFilterDropdownBooleanSelect = () => {
const handleOptionSelect = (value: boolean) => { const handleOptionSelect = (value: boolean) => {
if ( if (
!isDefined(filterDefinitionUsedInDropdown) || !isDefined(fieldMetadataItemUsedInDropdown) ||
!isDefined(selectedOperandInDropdown) !isDefined(selectedOperandInDropdown)
) { ) {
return; return;
} }
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ?? v4(), id: selectedFilter?.id ?? v4(),
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: value ? 'True' : 'False', displayValue: value ? 'True' : 'False',
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
value: value.toString(), value: value.toString(),
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
@@ -1,6 +1,7 @@
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { formatFieldMetadataItemAsFilterDefinition } 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 { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue'; import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue';
@@ -19,8 +20,8 @@ import { isDefined } from 'twenty-shared';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
export const ObjectFilterDropdownDateInput = () => { export const ObjectFilterDropdownDateInput = () => {
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const selectedOperandInDropdown = useRecoilComponentValueV2( const selectedOperandInDropdown = useRecoilComponentValueV2(
@@ -41,16 +42,21 @@ export const ObjectFilterDropdownDateInput = () => {
); );
const isDateTimeInput = const isDateTimeInput =
filterDefinitionUsedInDropdown?.type === FieldMetadataType.DATE_TIME; fieldMetadataItemUsedInDropdown?.type === FieldMetadataType.DATE_TIME;
const handleAbsoluteDateChange = (newDate: Date | null) => { const handleAbsoluteDateChange = (newDate: Date | null) => {
setInternalDate(newDate); setInternalDate(newDate);
if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; if (!fieldMetadataItemUsedInDropdown || !selectedOperandInDropdown) return;
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ? selectedFilter.id : v4(), id: selectedFilter?.id ? selectedFilter.id : v4(),
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, definition: filterDefinition,
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
value: newDate?.toISOString() ?? '', value: newDate?.toISOString() ?? '',
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: isDefined(newDate) displayValue: isDefined(newDate)
@@ -58,7 +64,6 @@ export const ObjectFilterDropdownDateInput = () => {
? newDate.toLocaleString() ? newDate.toLocaleString()
: newDate.toLocaleDateString() : newDate.toLocaleDateString()
: '', : '',
definition: filterDefinitionUsedInDropdown,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
}; };
@@ -70,7 +75,11 @@ export const ObjectFilterDropdownDateInput = () => {
unit: VariableDateViewFilterValueUnit; unit: VariableDateViewFilterValueUnit;
} | null, } | null,
) => { ) => {
if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; if (!fieldMetadataItemUsedInDropdown || !selectedOperandInDropdown) return;
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
const value = relativeDate const value = relativeDate
? computeVariableDateViewFilterValue( ? computeVariableDateViewFilterValue(
@@ -82,11 +91,11 @@ export const ObjectFilterDropdownDateInput = () => {
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ? selectedFilter.id : v4(), id: selectedFilter?.id ? selectedFilter.id : v4(),
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
value, value,
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: getRelativeDateDisplayValue(relativeDate), displayValue: getRelativeDateDisplayValue(relativeDate),
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
}; };
@@ -151,9 +151,7 @@ export const ObjectFilterDropdownFilterSelect = ({
filterDefinition: selectedFilterDefinition, filterDefinition: selectedFilterDefinition,
}); });
setFieldMetadataItemIdUsedInDropdown( setFieldMetadataItemIdUsedInDropdown(fieldMetadataItemId);
selectedFilterDefinition.fieldMetadataId,
);
closeAdvancedFilterDropdown(); closeAdvancedFilterDropdown();
}; };
@@ -1,7 +1,10 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown'; import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown';
import { advancedFilterViewFilterGroupIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterGroupIdComponentState'; import { advancedFilterViewFilterGroupIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterGroupIdComponentState';
import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState'; import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState';
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState'; import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState';
@@ -9,12 +12,13 @@ import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/o
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState'; import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel'; import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel'; import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue'; import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; 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 { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs'; import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@@ -37,6 +41,14 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
objectFilterDropdownFirstLevelFilterDefinitionComponentState, objectFilterDropdownFirstLevelFilterDefinitionComponentState,
); );
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
fieldMetadataItemUsedInDropdownComponentSelector,
);
const setSubFieldNameUsedInDropdown = useSetRecoilComponentStateV2(
subFieldNameUsedInDropdownComponentState,
);
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2( const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
objectFilterDropdownFilterIsSelectedComponentState, objectFilterDropdownFilterIsSelectedComponentState,
); );
@@ -83,39 +95,60 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
advancedFilterViewFilterId, advancedFilterViewFilterId,
); );
const handleSelectFilter = (definition: RecordFilterDefinition | null) => { const handleSelectFilter = (
if (definition !== null) { fieldMetadataItem: FieldMetadataItem | null | undefined,
subFieldName?: string | null | undefined,
) => {
if (isDefined(fieldMetadataItem)) {
const filterDefinition: RecordFilterDefinition = {
fieldMetadataId: fieldMetadataItem.id,
type: getFilterTypeFromFieldType(fieldMetadataItem.type),
label: fieldMetadataItem.label,
iconName: fieldMetadataItem.icon ?? '',
compositeFieldName: subFieldName ?? undefined,
};
if ( if (
isDefined(advancedFilterViewFilterId) && isDefined(advancedFilterViewFilterId) &&
isDefined(advancedFilterViewFilterGroupId) isDefined(advancedFilterViewFilterGroupId)
) { ) {
closeAdvancedFilterDropdown(); closeAdvancedFilterDropdown();
const operand = const type = getFilterTypeFromFieldType(fieldMetadataItem.type);
getRecordFilterOperandsForRecordFilterDefinition(definition)[0];
const { value, displayValue } = getInitialFilterValue( const operand = getRecordFilterOperands({
definition.type, filterType: type,
operand, subFieldName: subFieldName,
); })[0];
const { value, displayValue } = getInitialFilterValue(type, operand);
applyRecordFilter({ applyRecordFilter({
id: advancedFilterViewFilterId, id: advancedFilterViewFilterId,
fieldMetadataId: definition.fieldMetadataId, fieldMetadataId: fieldMetadataItem.id,
value, value,
operand, operand,
displayValue, displayValue,
definition, definition: filterDefinition,
viewFilterGroupId: advancedFilterViewFilterGroupId, viewFilterGroupId: advancedFilterViewFilterGroupId,
subFieldName: subFieldName,
}); });
} }
setFilterDefinitionUsedInDropdown(definition); setFilterDefinitionUsedInDropdown(filterDefinition);
setFieldMetadataItemIdUsedInDropdown(definition.fieldMetadataId); setFieldMetadataItemIdUsedInDropdown(fieldMetadataItem.id);
const type = getFilterTypeFromFieldType(fieldMetadataItem.type);
setSelectedOperandInDropdown( setSelectedOperandInDropdown(
getRecordFilterOperandsForRecordFilterDefinition(definition)[0], getRecordFilterOperands({
filterType: type,
subFieldName: subFieldName,
})[0],
); );
setSubFieldNameUsedInDropdown(subFieldName);
setObjectFilterDropdownSearchInput(''); setObjectFilterDropdownSearchInput('');
setObjectFilterDropdownFilterIsSelected(true); setObjectFilterDropdownFilterIsSelected(true);
@@ -167,36 +200,30 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
key={`select-filter-${-1}`} key={`select-filter-${-1}`}
testId={`select-filter-${-1}`} testId={`select-filter-${-1}`}
onClick={() => { onClick={() => {
handleSelectFilter(objectFilterDropdownFirstLevelFilterDefinition); handleSelectFilter(fieldMetadataItemUsedInDropdown);
}} }}
LeftIcon={IconApps} LeftIcon={IconApps}
text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`} text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`}
/> />
{/* TODO: fix this with a backend field on ViewFilter for composite field filter */} {/* TODO: fix this with a backend field on ViewFilter for composite field filter */}
{objectFilterDropdownFirstLevelFilterDefinition.type === 'ACTOR' && {fieldMetadataItemUsedInDropdown?.type === 'ACTOR' &&
options.map((subFieldName, index) => ( options.map((subFieldName, index) => (
<MenuItem <MenuItem
key={`select-filter-${index}`} key={`select-filter-${index}`}
testId={`select-filter-${index}`} testId={`select-filter-${index}`}
onClick={() => { onClick={() => {
if (isDefined(objectFilterDropdownFirstLevelFilterDefinition)) { if (isDefined(fieldMetadataItemUsedInDropdown)) {
handleSelectFilter({ handleSelectFilter(
...objectFilterDropdownFirstLevelFilterDefinition, fieldMetadataItemUsedInDropdown,
label: getCompositeSubFieldLabel( subFieldName,
objectFilterDropdownSubMenuFieldType, );
subFieldName,
),
compositeFieldName: subFieldName,
});
} }
}} }}
text={getCompositeSubFieldLabel( text={getCompositeSubFieldLabel(
objectFilterDropdownSubMenuFieldType, objectFilterDropdownSubMenuFieldType,
subFieldName, subFieldName,
)} )}
LeftIcon={getIcon( LeftIcon={getIcon(fieldMetadataItemUsedInDropdown?.icon)}
objectFilterDropdownFirstLevelFilterDefinition?.iconName,
)}
/> />
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
@@ -7,14 +7,15 @@ import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState'; import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { CompositeFilterableFieldType } from '@/object-record/record-filter/types/CompositeFilterableFieldType';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import {
formatFieldMetadataItemAsFilterDefinition,
getFilterTypeFromFieldType,
} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField'; import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -57,16 +58,10 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
OBJECT_FILTER_DROPDOWN_ID, OBJECT_FILTER_DROPDOWN_ID,
); );
const filterDefinitionToSelect = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemToSelect,
});
const isSelectedItem = useRecoilValue( const isSelectedItem = useRecoilValue(
isSelectedItemIdSelector(fieldMetadataItemToSelect.id), isSelectedItemIdSelector(fieldMetadataItemToSelect.id),
); );
const isACompositeField = isCompositeField(fieldMetadataItemToSelect.type);
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2( const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
selectedOperandInDropdownComponentState, selectedOperandInDropdownComponentState,
); );
@@ -85,27 +80,28 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
advancedFilterViewFilterId, advancedFilterViewFilterId,
); );
const handleSelectFilterDefinition = ( const handleSelectFilter = (fieldMetadataItem: FieldMetadataItem) => {
availableFilterDefinition: RecordFilterDefinition,
) => {
closeAdvancedFilterDropdown(); closeAdvancedFilterDropdown();
setFieldMetadataItemIdUsedInDropdown( setFieldMetadataItemIdUsedInDropdown(fieldMetadataItem.id);
availableFilterDefinition.fieldMetadataId,
); const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
setFilterDefinitionUsedInDropdown(availableFilterDefinition); field: fieldMetadataItem,
});
setFilterDefinitionUsedInDropdown(filterDefinition);
if ( if (
availableFilterDefinition.type === 'RELATION' || filterDefinition.type === 'RELATION' ||
availableFilterDefinition.type === 'SELECT' filterDefinition.type === 'SELECT'
) { ) {
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker); setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
} }
setSelectedOperandInDropdown( setSelectedOperandInDropdown(
getRecordFilterOperandsForRecordFilterDefinition( getRecordFilterOperands({
availableFilterDefinition, filterType: filterDefinition.type,
)[0], })[0],
); );
setObjectFilterDropdownFilterIsSelected(true); setObjectFilterDropdownFilterIsSelected(true);
@@ -113,20 +109,29 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
const { getIcon } = useIcons(); const { getIcon } = useIcons();
const Icon = getIcon(fieldMetadataItemToSelect.icon);
const shouldShowSubMenu = isCompositeField(fieldMetadataItemToSelect.type);
const handleClick = () => { const handleClick = () => {
resetSelectedItem(); resetSelectedItem();
if (isACompositeField) { const filterType = getFilterTypeFromFieldType(
// TODO: create isCompositeFilterableFieldType type guard fieldMetadataItemToSelect.type,
setObjectFilterDropdownSubMenuFieldType( );
filterDefinitionToSelect.type as CompositeFilterableFieldType,
); if (isCompositeField(filterType)) {
setObjectFilterDropdownFirstLevelFilterDefinition( setObjectFilterDropdownSubMenuFieldType(filterType);
filterDefinitionToSelect,
); const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemToSelect,
});
setObjectFilterDropdownFirstLevelFilterDefinition(filterDefinition);
setFieldMetadataItemIdUsedInDropdown(fieldMetadataItemToSelect.id);
setObjectFilterDropdownIsSelectingCompositeField(true); setObjectFilterDropdownIsSelectingCompositeField(true);
} else { } else {
handleSelectFilterDefinition(filterDefinitionToSelect); handleSelectFilter(fieldMetadataItemToSelect);
} }
}; };
@@ -135,9 +140,9 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
selected={false} selected={false}
hovered={isSelectedItem} hovered={isSelectedItem}
onClick={handleClick} onClick={handleClick}
LeftIcon={getIcon(filterDefinitionToSelect.iconName)} LeftIcon={Icon}
text={filterDefinitionToSelect.label} text={fieldMetadataItemToSelect.label}
hasSubMenu={isACompositeField} hasSubMenu={shouldShowSubMenu}
/> />
); );
}; };
@@ -1,7 +1,8 @@
import { ChangeEvent, useCallback, useState } from 'react'; import { ChangeEvent, useCallback, useState } from 'react';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { formatFieldMetadataItemAsFilterDefinition } 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 { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
@@ -13,8 +14,8 @@ export const ObjectFilterDropdownNumberInput = () => {
selectedOperandInDropdownComponentState, selectedOperandInDropdownComponentState,
); );
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const selectedFilter = useRecoilComponentValueV2( const selectedFilter = useRecoilComponentValueV2(
@@ -39,27 +40,32 @@ export const ObjectFilterDropdownNumberInput = () => {
}, },
[hasFocused], [hasFocused],
); );
return ( return (
filterDefinitionUsedInDropdown && fieldMetadataItemUsedInDropdown &&
selectedOperandInDropdown && ( selectedOperandInDropdown && (
<DropdownMenuInput <DropdownMenuInput
ref={handleInputRef} ref={handleInputRef}
value={inputValue} value={inputValue}
autoFocus autoFocus
type="number" type="number"
placeholder={filterDefinitionUsedInDropdown.label} placeholder={fieldMetadataItemUsedInDropdown.label}
onChange={(event: ChangeEvent<HTMLInputElement>) => { onChange={(event: ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value; const newValue = event.target.value;
setInputValue(newValue); setInputValue(newValue);
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ? selectedFilter.id : v4(), id: selectedFilter?.id ? selectedFilter.id : v4(),
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '',
value: newValue, value: newValue,
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: newValue, displayValue: newValue,
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
}} }}
@@ -1,10 +1,16 @@
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import {
formatFieldMetadataItemAsFilterDefinition,
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 { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue'; import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter'; import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@@ -13,7 +19,6 @@ import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared'; import { isDefined } from 'twenty-shared';
import { MenuItem } from 'twenty-ui'; import { MenuItem } from 'twenty-ui';
import { getRecordFilterOperandsForRecordFilterDefinition } from '../../record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
import { getOperandLabel } from '../utils/getOperandLabel'; import { getOperandLabel } from '../utils/getOperandLabel';
const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)` const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
@@ -22,8 +27,8 @@ const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
`; `;
export const ObjectFilterDropdownOperandSelect = () => { export const ObjectFilterDropdownOperandSelect = () => {
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2( const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
@@ -34,14 +39,21 @@ export const ObjectFilterDropdownOperandSelect = () => {
selectedFilterComponentState, selectedFilterComponentState,
); );
const subFieldNameUsedInDropdown = useRecoilComponentValueV2(
subFieldNameUsedInDropdownComponentState,
);
const { applyRecordFilter } = useApplyRecordFilter(); const { applyRecordFilter } = useApplyRecordFilter();
const { closeDropdown } = useDropdown(); const { closeDropdown } = useDropdown();
const operandsForFilterType = isDefined(filterDefinitionUsedInDropdown) const operandsForFilterType = isDefined(fieldMetadataItemUsedInDropdown)
? getRecordFilterOperandsForRecordFilterDefinition( ? getRecordFilterOperands({
filterDefinitionUsedInDropdown, filterType: getFilterTypeFromFieldType(
) fieldMetadataItemUsedInDropdown.type,
),
subFieldName: subFieldNameUsedInDropdown,
})
: []; : [];
const handleOperandChange = (newOperand: ViewFilterOperand) => { const handleOperandChange = (newOperand: ViewFilterOperand) => {
@@ -55,36 +67,48 @@ export const ObjectFilterDropdownOperandSelect = () => {
setSelectedOperandInDropdown(newOperand); setSelectedOperandInDropdown(newOperand);
if (isValuelessOperand && isDefined(filterDefinitionUsedInDropdown)) { if (isValuelessOperand && isDefined(fieldMetadataItemUsedInDropdown)) {
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: v4(), id: v4(),
fieldMetadataId: filterDefinitionUsedInDropdown?.fieldMetadataId ?? '', fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
displayValue: '', displayValue: '',
operand: newOperand, operand: newOperand,
value: '', value: '',
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
}); });
return; return;
} }
if ( if (
isDefined(filterDefinitionUsedInDropdown) && isDefined(fieldMetadataItemUsedInDropdown) &&
isDefined(selectedFilter) isDefined(selectedFilter)
) { ) {
const filterType = getFilterTypeFromFieldType(
fieldMetadataItemUsedInDropdown.type,
);
const { value, displayValue } = getInitialFilterValue( const { value, displayValue } = getInitialFilterValue(
filterDefinitionUsedInDropdown.type, filterType,
newOperand, newOperand,
selectedFilter.value, selectedFilter.value,
selectedFilter.displayValue, selectedFilter.displayValue,
); );
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter.id ? selectedFilter.id : v4(), id: selectedFilter.id ? selectedFilter.id : v4(),
fieldMetadataId: selectedFilter.fieldMetadataId, fieldMetadataId: selectedFilter.fieldMetadataId,
displayValue, displayValue,
operand: newOperand, operand: newOperand,
value, value,
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
}); });
} }
}; };
@@ -13,7 +13,8 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates'; import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState'; import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState';
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
@@ -32,8 +33,8 @@ type SelectOptionForFilter = FieldMetadataItemOption & {
}; };
export const ObjectFilterDropdownOptionSelect = () => { export const ObjectFilterDropdownOptionSelect = () => {
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const objectFilterDropdownSelectedOptionValues = useRecoilComponentValueV2( const objectFilterDropdownSelectedOptionValues = useRecoilComponentValueV2(
@@ -66,7 +67,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
const selectedItemId = useRecoilValue(selectedItemIdState); const selectedItemId = useRecoilValue(selectedItemIdState);
const fieldMetaDataId = filterDefinitionUsedInDropdown?.fieldMetadataId ?? ''; const fieldMetaDataId = fieldMetadataItemUsedInDropdown?.id ?? '';
const { selectOptions } = useOptionsForSelect(fieldMetaDataId); const { selectOptions } = useOptionsForSelect(fieldMetaDataId);
@@ -125,7 +126,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
: selectedOptions.map((option) => option.label).join(', '); : selectedOptions.map((option) => option.label).join(', ');
if ( if (
isDefined(filterDefinitionUsedInDropdown) && isDefined(fieldMetadataItemUsedInDropdown) &&
isDefined(selectedOperandInDropdown) isDefined(selectedOperandInDropdown)
) { ) {
const newFilterValue = const newFilterValue =
@@ -133,12 +134,16 @@ export const ObjectFilterDropdownOptionSelect = () => {
? JSON.stringify(selectedOptions.map((option) => option.value)) ? JSON.stringify(selectedOptions.map((option) => option.value))
: EMPTY_FILTER_VALUE; : EMPTY_FILTER_VALUE;
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ? selectedFilter.id : v4(), id: selectedFilter?.id ? selectedFilter.id : v4(),
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: filterDisplayValue, displayValue: filterDisplayValue,
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
value: newFilterValue, value: newFilterValue,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
@@ -1,6 +1,5 @@
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues'; import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues';
import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata'; import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata';
@@ -9,6 +8,8 @@ import { RatingInput } from '@/ui/field/input/components/RatingInput';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { formatFieldMetadataItemAsFilterDefinition } 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 { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
const convertFieldRatingValueToNumber = ( const convertFieldRatingValueToNumber = (
rating: Exclude<FieldRatingValue, null>, rating: Exclude<FieldRatingValue, null>,
@@ -37,8 +38,8 @@ export const ObjectFilterDropdownRatingInput = () => {
selectedOperandInDropdownComponentState, selectedOperandInDropdownComponentState,
); );
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const selectedFilter = useRecoilComponentValueV2( const selectedFilter = useRecoilComponentValueV2(
@@ -48,7 +49,7 @@ export const ObjectFilterDropdownRatingInput = () => {
const { applyRecordFilter } = useApplyRecordFilter(); const { applyRecordFilter } = useApplyRecordFilter();
return ( return (
filterDefinitionUsedInDropdown && fieldMetadataItemUsedInDropdown &&
selectedOperandInDropdown && ( selectedOperandInDropdown && (
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<RatingInput <RatingInput
@@ -58,13 +59,17 @@ export const ObjectFilterDropdownRatingInput = () => {
return; return;
} }
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter?.({ applyRecordFilter?.({
id: selectedFilter?.id ? selectedFilter.id : v4(), id: selectedFilter?.id ? selectedFilter.id : v4(),
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
value: convertFieldRatingValueToNumber(newValue), value: convertFieldRatingValueToNumber(newValue),
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: convertFieldRatingValueToNumber(newValue), displayValue: convertFieldRatingValueToNumber(newValue),
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
}} }}
@@ -1,8 +1,8 @@
import { useState } from 'react';
import { v4 } from 'uuid';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { getRelationObjectMetadataNameSingular } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import {
formatFieldMetadataItemAsFilterDefinition,
getRelationObjectMetadataNameSingular,
} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { ObjectFilterDropdownRecordPinnedItems } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordPinnedItems'; import { ObjectFilterDropdownRecordPinnedItems } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordPinnedItems';
import { CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID } from '@/object-record/object-filter-dropdown/constants/CurrentWorkspaceMemberSelectableItemId'; 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 { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
@@ -24,6 +24,7 @@ import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validat
import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/simpleRelationFilterValueSchema'; import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/simpleRelationFilterValueSchema';
import { isDefined } from 'twenty-shared'; import { isDefined } from 'twenty-shared';
import { IconUserCircle } from 'twenty-ui'; import { IconUserCircle } from 'twenty-ui';
import { v4 } from 'uuid';
export const EMPTY_FILTER_VALUE: string = JSON.stringify({ export const EMPTY_FILTER_VALUE: string = JSON.stringify({
isCurrentWorkspaceMemberSelected: false, isCurrentWorkspaceMemberSelected: false,
@@ -68,8 +69,6 @@ export const ObjectFilterDropdownRecordSelect = ({
const { currentViewWithCombinedFiltersAndSorts } = const { currentViewWithCombinedFiltersAndSorts } =
useGetCurrentView(viewComponentId); useGetCurrentView(viewComponentId);
const [fieldId] = useState(v4());
const { isCurrentWorkspaceMemberSelected } = jsonRelationFilterValueSchema const { isCurrentWorkspaceMemberSelected } = jsonRelationFilterValueSchema
.catch({ .catch({
isCurrentWorkspaceMemberSelected: false, isCurrentWorkspaceMemberSelected: false,
@@ -200,17 +199,21 @@ export const ObjectFilterDropdownRecordSelect = ({
currentViewWithCombinedFiltersAndSorts?.viewFilters.find( currentViewWithCombinedFiltersAndSorts?.viewFilters.find(
(viewFilter) => (viewFilter) =>
viewFilter.fieldMetadataId === viewFilter.fieldMetadataId ===
filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataItemUsedInFilterDropdown.id,
); );
const filterId = viewFilter?.id ?? fieldId; const filterId = viewFilter?.id ?? v4();
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInFilterDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ? selectedFilter.id : filterId, id: selectedFilter?.id ? selectedFilter.id : filterId,
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: filterDisplayValue, displayValue: filterDisplayValue,
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
value: newFilterValue, value: newFilterValue,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
@@ -1,6 +1,6 @@
import { ChangeEvent, useCallback, useState } from 'react'; import { ChangeEvent, useCallback, useState } from 'react';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
@@ -8,8 +8,8 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
export const ObjectFilterDropdownSearchInput = () => { export const ObjectFilterDropdownSearchInput = () => {
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const selectedOperandInDropdown = useRecoilComponentValueV2( const selectedOperandInDropdown = useRecoilComponentValueV2(
@@ -37,14 +37,14 @@ export const ObjectFilterDropdownSearchInput = () => {
[hasFocused], [hasFocused],
); );
return ( return (
filterDefinitionUsedInDropdown && fieldMetadataItemUsedInDropdown &&
selectedOperandInDropdown && ( selectedOperandInDropdown && (
<DropdownMenuSearchInput <DropdownMenuSearchInput
ref={handleInputRef} ref={handleInputRef}
autoFocus autoFocus
type="text" type="text"
value={objectFilterDropdownSearchInput} value={objectFilterDropdownSearchInput}
placeholder={filterDefinitionUsedInDropdown.label} placeholder={fieldMetadataItemUsedInDropdown.label}
onChange={(event: ChangeEvent<HTMLInputElement>) => { onChange={(event: ChangeEvent<HTMLInputElement>) => {
setObjectFilterDropdownSearchInput(event.target.value); setObjectFilterDropdownSearchInput(event.target.value);
}} }}
@@ -1,8 +1,9 @@
import { useState } from 'react'; import { useState } from 'react';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { useEmptyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useEmptyRecordFilter'; import { useEmptyRecordFilter } from '@/object-record/object-filter-dropdown/hooks/useEmptyRecordFilter';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState'; import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
@@ -50,8 +51,8 @@ export const ObjectFilterDropdownSourceSelect = ({
selectedOperandInDropdownComponentState, selectedOperandInDropdownComponentState,
); );
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const { applyRecordFilter } = useApplyRecordFilter(viewComponentId); const { applyRecordFilter } = useApplyRecordFilter(viewComponentId);
@@ -87,13 +88,15 @@ export const ObjectFilterDropdownSourceSelect = ({
(id) => id !== itemToSelect.id, (id) => id !== itemToSelect.id,
); );
if (!filterDefinitionUsedInDropdown) { if (!isDefined(fieldMetadataItemUsedInFilterDropdown)) {
throw new Error('Filter definition used in dropdown should be defined'); throw new Error(
'Field metadata item used in filter dropdown should be defined',
);
} }
if (newSelectedItemIds.length === 0) { if (newSelectedItemIds.length === 0) {
emptyRecordFilter(); emptyRecordFilter();
removeRecordFilter(filterDefinitionUsedInDropdown.fieldMetadataId); removeRecordFilter(fieldMetadataItemUsedInFilterDropdown.id);
deleteCombinedViewFilter(fieldId); deleteCombinedViewFilter(fieldId);
return; return;
} }
@@ -110,7 +113,7 @@ export const ObjectFilterDropdownSourceSelect = ({
: selectedItemNames.join(', '); : selectedItemNames.join(', ');
if ( if (
isDefined(filterDefinitionUsedInDropdown) && isDefined(fieldMetadataItemUsedInFilterDropdown) &&
isDefined(selectedOperandInDropdown) isDefined(selectedOperandInDropdown)
) { ) {
const newFilterValue = const newFilterValue =
@@ -122,17 +125,21 @@ export const ObjectFilterDropdownSourceSelect = ({
currentViewWithCombinedFiltersAndSorts?.viewFilters.find( currentViewWithCombinedFiltersAndSorts?.viewFilters.find(
(viewFilter) => (viewFilter) =>
viewFilter.fieldMetadataId === viewFilter.fieldMetadataId ===
filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataItemUsedInFilterDropdown.id,
); );
const filterId = viewFilter?.id ?? fieldId; const filterId = viewFilter?.id ?? fieldId;
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInFilterDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ? selectedFilter.id : filterId, id: selectedFilter?.id ? selectedFilter.id : filterId,
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
operand: selectedOperandInDropdown || ViewFilterOperand.Is, operand: selectedOperandInDropdown || ViewFilterOperand.Is,
displayValue: filterDisplayValue, displayValue: filterDisplayValue,
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
value: newFilterValue, value: newFilterValue,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
@@ -1,7 +1,7 @@
import { ChangeEvent, useCallback, useState } from 'react'; import { ChangeEvent, useCallback, useState } from 'react';
import { v4 } from 'uuid';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
@@ -9,13 +9,13 @@ import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApp
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { v4 } from 'uuid';
export const ObjectFilterDropdownTextSearchInput = () => { export const ObjectFilterDropdownTextSearchInput = () => {
const [filterId] = useState(v4());
const [hasFocused, setHasFocused] = useState(false); const [hasFocused, setHasFocused] = useState(false);
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
); );
const selectedOperandInDropdown = useRecoilComponentValueV2( const selectedOperandInDropdown = useRecoilComponentValueV2(
@@ -47,24 +47,28 @@ export const ObjectFilterDropdownTextSearchInput = () => {
[hasFocused], [hasFocused],
); );
return ( return (
filterDefinitionUsedInDropdown && fieldMetadataItemUsedInDropdown &&
selectedOperandInDropdown && ( selectedOperandInDropdown && (
<DropdownMenuSearchInput <DropdownMenuSearchInput
ref={handleInputRef} ref={handleInputRef}
autoFocus autoFocus
type="text" type="text"
placeholder={filterDefinitionUsedInDropdown.label} placeholder={fieldMetadataItemUsedInDropdown.label}
value={selectedFilter?.value ?? objectFilterDropdownSearchInput} value={selectedFilter?.value ?? objectFilterDropdownSearchInput}
onChange={(event: ChangeEvent<HTMLInputElement>) => { onChange={(event: ChangeEvent<HTMLInputElement>) => {
setObjectFilterDropdownSearchInput(event.target.value); setObjectFilterDropdownSearchInput(event.target.value);
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
field: fieldMetadataItemUsedInDropdown,
});
applyRecordFilter({ applyRecordFilter({
id: selectedFilter?.id ?? filterId, id: selectedFilter?.id ?? v4(),
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
value: event.target.value, value: event.target.value,
operand: selectedOperandInDropdown, operand: selectedOperandInDropdown,
displayValue: event.target.value, displayValue: event.target.value,
definition: filterDefinitionUsedInDropdown, definition: filterDefinition,
viewFilterGroupId: selectedFilter?.viewFilterGroupId, viewFilterGroupId: selectedFilter?.viewFilterGroupId,
}); });
}} }}
@@ -2,7 +2,7 @@ import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/ob
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const subFieldNameUsedInDropdownComponentState = createComponentStateV2< export const subFieldNameUsedInDropdownComponentState = createComponentStateV2<
string | null string | null | undefined
>({ >({
key: 'subFieldNameUsedInDropdownComponentState', key: 'subFieldNameUsedInDropdownComponentState',
defaultValue: null, defaultValue: null,
@@ -0,0 +1,7 @@
import { FieldActorValue } from '@/object-record/record-field/types/FieldMetadata';
export const isFilterOnActorSourceSubField = (
subFieldName?: string | null | undefined,
) => {
return subFieldName === ('source' satisfies keyof FieldActorValue);
};
@@ -47,6 +47,8 @@ describe('useRemoveRecordFilter', () => {
label: 'Test Field', label: 'Test Field',
iconName: 'IconText', iconName: 'IconText',
}, },
label: 'Test Field',
type: 'TEXT',
}; };
// First add a filter // First add a filter
@@ -96,6 +98,8 @@ describe('useRemoveRecordFilter', () => {
label: 'Test Field', label: 'Test Field',
iconName: 'IconText', iconName: 'IconText',
}, },
label: 'Test Field',
type: 'TEXT',
}; };
// Add a filter // Add a filter
@@ -41,6 +41,8 @@ describe('useUpsertRecordFilter', () => {
label: 'Test Field', label: 'Test Field',
iconName: 'IconText', iconName: 'IconText',
}, },
label: 'Test Field',
type: 'TEXT',
}; };
act(() => { act(() => {
@@ -79,6 +81,8 @@ describe('useUpsertRecordFilter', () => {
label: 'Test Field', label: 'Test Field',
iconName: 'IconText', iconName: 'IconText',
}, },
label: 'Test Field',
type: 'TEXT',
}; };
const updatedFilter: RecordFilter = { const updatedFilter: RecordFilter = {
@@ -93,6 +97,8 @@ describe('useUpsertRecordFilter', () => {
label: 'Test Field', label: 'Test Field',
iconName: 'IconText', iconName: 'IconText',
}, },
label: 'Test Field',
type: 'TEXT',
}; };
act(() => { act(() => {
@@ -17,16 +17,25 @@ export const useUpsertRecordFilter = () => {
currentRecordFiltersCallbackState, currentRecordFiltersCallbackState,
); );
// TODO: This is a temporary solution to ensure that the record filter is compatible with filter definitions
// Label and type will be set without definition
const recordFilterToSet: RecordFilter = {
...filter,
label: filter.definition.label,
type: filter.definition.type,
};
const foundRecordFilterInCurrentRecordFilters = const foundRecordFilterInCurrentRecordFilters =
currentRecordFilters.some( currentRecordFilters.some(
(existingFilter) => (existingFilter) =>
existingFilter.fieldMetadataId === filter.fieldMetadataId, existingFilter.fieldMetadataId ===
recordFilterToSet.fieldMetadataId,
); );
if (!foundRecordFilterInCurrentRecordFilters) { if (!foundRecordFilterInCurrentRecordFilters) {
set(currentRecordFiltersCallbackState, [ set(currentRecordFiltersCallbackState, [
...currentRecordFilters, ...currentRecordFilters,
filter, recordFilterToSet,
]); ]);
} else { } else {
set(currentRecordFiltersCallbackState, (currentRecordFilters) => { set(currentRecordFiltersCallbackState, (currentRecordFilters) => {
@@ -34,11 +43,12 @@ export const useUpsertRecordFilter = () => {
const indexOfFilterToUpdate = newCurrentRecordFilters.findIndex( const indexOfFilterToUpdate = newCurrentRecordFilters.findIndex(
(existingFilter) => (existingFilter) =>
existingFilter.fieldMetadataId === filter.fieldMetadataId, existingFilter.fieldMetadataId ===
recordFilterToSet.fieldMetadataId,
); );
newCurrentRecordFilters[indexOfFilterToUpdate] = { newCurrentRecordFilters[indexOfFilterToUpdate] = {
...filter, ...recordFilterToSet,
}; };
return newCurrentRecordFilters; return newCurrentRecordFilters;
@@ -1,3 +1,4 @@
import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
@@ -7,11 +8,12 @@ export type RecordFilter = {
fieldMetadataId: string; fieldMetadataId: string;
value: string; value: string;
displayValue: string; displayValue: string;
type?: FilterableFieldType;
viewFilterGroupId?: string; viewFilterGroupId?: string;
displayAvatarUrl?: string; displayAvatarUrl?: string;
operand: ViewFilterOperand; operand: ViewFilterOperand;
positionInViewFilterGroup?: number | null; positionInViewFilterGroup?: number | null;
definition: RecordFilterDefinition; definition: RecordFilterDefinition;
label?: string; label?: string;
subFieldName?: string; subFieldName?: string | null | undefined;
}; };
@@ -795,7 +795,7 @@ const computeFilterRecordGqlOperationFilter = (
); );
default: default:
throw new Error( throw new Error(
`Unknown operand ${filter.operand} for ${filter.definition.label} filter`, `Unknown operand ${filter.operand} for ${filter.label} filter`,
); );
} }
} }
@@ -0,0 +1,105 @@
import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField';
import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
import { ViewFilterOperand as RecordFilterOperand } from '@/views/types/ViewFilterOperand';
export type GetRecordFilterOperandsParams = {
filterType: FilterableFieldType;
subFieldName?: string | null | undefined;
};
export const getRecordFilterOperands = ({
filterType,
subFieldName,
}: GetRecordFilterOperandsParams): RecordFilterOperand[] => {
const emptyOperands = [
RecordFilterOperand.IsEmpty,
RecordFilterOperand.IsNotEmpty,
];
const relationOperands = [RecordFilterOperand.Is, RecordFilterOperand.IsNot];
switch (filterType) {
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 (isFilterOnActorSourceSubField(subFieldName)) {
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 [];
}
};
@@ -30,9 +30,7 @@ export const RecordTableEmptyStateSoftDelete = () => {
const handleButtonClick = async () => { const handleButtonClick = async () => {
const deletedFilter = tableFilters.find( const deletedFilter = tableFilters.find(
(filter) => (filter) => filter.label === 'Deleted' && filter.operand === 'isNotEmpty',
filter.definition.label === 'Deleted' &&
filter.operand === 'isNotEmpty',
); );
if (!deletedFilter) { if (!deletedFilter) {
@@ -1,5 +1,6 @@
import { useIcons } from 'twenty-ui'; import { useIcons } from 'twenty-ui';
import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
import { getOperandLabelShort } from '@/object-record/object-filter-dropdown/utils/getOperandLabel'; import { getOperandLabelShort } from '@/object-record/object-filter-dropdown/utils/getOperandLabel';
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip'; import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
@@ -14,13 +15,20 @@ export const EditableFilterChip = ({
onRemove, onRemove,
}: EditableFilterChipProps) => { }: EditableFilterChipProps) => {
const { getIcon } = useIcons(); const { getIcon } = useIcons();
const { fieldMetadataItem } = useFieldMetadataItemById(
viewFilter.fieldMetadataId,
);
const FieldMetadataItemIcon = getIcon(fieldMetadataItem.icon);
return ( return (
<SortOrFilterChip <SortOrFilterChip
key={viewFilter.id} key={viewFilter.id}
testId={viewFilter.id} testId={viewFilter.id}
labelKey={`${viewFilter.definition.label}${getOperandLabelShort(viewFilter.operand)}`} labelKey={`${viewFilter.label}${getOperandLabelShort(viewFilter.operand)}`}
labelValue={viewFilter.displayValue} labelValue={viewFilter.displayValue}
Icon={getIcon(viewFilter.definition.iconName)} Icon={FieldMetadataItemIcon}
onRemove={onRemove} onRemove={onRemove}
/> />
); );
@@ -1,5 +1,6 @@
import { useIcons } from 'twenty-ui'; import { useIcons } from 'twenty-ui';
import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
@@ -9,12 +10,12 @@ import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedVie
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
type VariantFilterChipProps = { type VariantFilterChipProps = {
viewFilter: RecordFilter; recordFilter: RecordFilter;
viewBarId: string; viewBarId: string;
}; };
export const VariantFilterChip = ({ export const VariantFilterChip = ({
viewFilter, recordFilter,
viewBarId, viewBarId,
}: VariantFilterChipProps) => { }: VariantFilterChipProps) => {
const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters(); const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters();
@@ -30,17 +31,23 @@ export const VariantFilterChip = ({
viewBarId, viewBarId,
}); });
const { fieldMetadataItem } = useFieldMetadataItemById(
recordFilter.fieldMetadataId,
);
const { removeRecordFilter } = useRemoveRecordFilter(); const { removeRecordFilter } = useRemoveRecordFilter();
const { getIcon } = useIcons(); const { getIcon } = useIcons();
const FieldMetadataItemIcon = getIcon(fieldMetadataItem.icon);
const handleRemoveClick = () => { const handleRemoveClick = () => {
deleteCombinedViewFilter(viewFilter.id); deleteCombinedViewFilter(recordFilter.id);
removeRecordFilter(viewFilter.fieldMetadataId); removeRecordFilter(recordFilter.fieldMetadataId);
if ( if (
viewFilter.definition.label === 'Deleted' && recordFilter.label === 'Deleted' &&
viewFilter.operand === 'isNotEmpty' recordFilter.operand === 'isNotEmpty'
) { ) {
toggleSoftDeleteFilterState(false); toggleSoftDeleteFilterState(false);
} }
@@ -48,11 +55,11 @@ export const VariantFilterChip = ({
return ( return (
<SortOrFilterChip <SortOrFilterChip
key={viewFilter.fieldMetadataId} key={recordFilter.fieldMetadataId}
testId={viewFilter.fieldMetadataId} testId={recordFilter.fieldMetadataId}
variant={viewFilter.variant} variant={recordFilter.variant}
labelValue={viewFilter.definition.label} labelValue={recordFilter.label ?? ''}
Icon={getIcon(viewFilter.definition.iconName)} Icon={FieldMetadataItemIcon}
onRemove={handleRemoveClick} onRemove={handleRemoveClick}
/> />
); );
@@ -193,7 +193,7 @@ export const ViewBarDetails = ({
{otherViewFilters.map((viewFilter) => ( {otherViewFilters.map((viewFilter) => (
<VariantFilterChip <VariantFilterChip
key={viewFilter.fieldMetadataId} key={viewFilter.fieldMetadataId}
viewFilter={viewFilter} recordFilter={viewFilter}
viewBarId={viewBarId} viewBarId={viewBarId}
/> />
))} ))}
@@ -4,7 +4,7 @@ import { useEffect } from 'react';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState'; import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState';
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState'; import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
@@ -21,8 +21,8 @@ export const ViewBarFilterEffect = ({
}: ViewBarFilterEffectProps) => { }: ViewBarFilterEffectProps) => {
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(); const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2( const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
filterDefinitionUsedInDropdownComponentState, fieldMetadataItemUsedInDropdownComponentSelector,
filterDropdownId, filterDropdownId,
); );
@@ -38,12 +38,11 @@ export const ViewBarFilterEffect = ({
); );
useEffect(() => { useEffect(() => {
if (filterDefinitionUsedInDropdown?.type === 'RELATION') { if (fieldMetadataItemUsedInDropdown?.type === 'RELATION') {
const viewFilterUsedInDropdown = const viewFilterUsedInDropdown =
currentViewWithCombinedFiltersAndSorts?.viewFilters.find( currentViewWithCombinedFiltersAndSorts?.viewFilters.find(
(filter) => (filter) =>
filter.fieldMetadataId === filter.fieldMetadataId === fieldMetadataItemUsedInDropdown?.id,
filterDefinitionUsedInDropdown?.fieldMetadataId,
); );
const { selectedRecordIds } = jsonRelationFilterValueSchema const { selectedRecordIds } = jsonRelationFilterValueSchema
@@ -57,14 +56,13 @@ export const ViewBarFilterEffect = ({
setObjectFilterDropdownSelectedRecordIds(selectedRecordIds); setObjectFilterDropdownSelectedRecordIds(selectedRecordIds);
} else if ( } else if (
isDefined(filterDefinitionUsedInDropdown) && isDefined(fieldMetadataItemUsedInDropdown) &&
['SELECT', 'MULTI_SELECT'].includes(filterDefinitionUsedInDropdown.type) ['SELECT', 'MULTI_SELECT'].includes(fieldMetadataItemUsedInDropdown.type)
) { ) {
const viewFilterUsedInDropdown = const viewFilterUsedInDropdown =
currentViewWithCombinedFiltersAndSorts?.viewFilters.find( currentViewWithCombinedFiltersAndSorts?.viewFilters.find(
(filter) => (filter) =>
filter.fieldMetadataId === filter.fieldMetadataId === fieldMetadataItemUsedInDropdown?.id,
filterDefinitionUsedInDropdown?.fieldMetadataId,
); );
const viewFilterSelectedRecords = isNonEmptyString( const viewFilterSelectedRecords = isNonEmptyString(
@@ -75,7 +73,7 @@ export const ViewBarFilterEffect = ({
setObjectFilterDropdownSelectedOptionValues(viewFilterSelectedRecords); setObjectFilterDropdownSelectedOptionValues(viewFilterSelectedRecords);
} }
}, [ }, [
filterDefinitionUsedInDropdown, fieldMetadataItemUsedInDropdown,
setObjectFilterDropdownSelectedRecordIds, setObjectFilterDropdownSelectedRecordIds,
setObjectFilterDropdownSelectedOptionValues, setObjectFilterDropdownSelectedOptionValues,
currentViewWithCombinedFiltersAndSorts, currentViewWithCombinedFiltersAndSorts,
@@ -1,7 +1,11 @@
import { act, renderHook } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react';
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import {
formatFieldMetadataItemAsFilterDefinition,
getFilterTypeFromFieldType,
} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@@ -39,7 +43,7 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
fieldMetadataId: mockFieldMetadataItem.id, fieldMetadataId: mockFieldMetadataItem.id,
operand: ViewFilterOperand.Contains, operand: ViewFilterOperand.Contains,
value: 'test', value: 'test',
displayValue: 'test', displayValue: mockFieldMetadataItem.label,
viewFilterGroupId: 'group-1', viewFilterGroupId: 'group-1',
positionInViewFilterGroup: 0, positionInViewFilterGroup: 0,
definition: mockFilterDefinition, definition: mockFilterDefinition,
@@ -99,7 +103,9 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
viewFilterGroupId: mockViewFilter.viewFilterGroupId, viewFilterGroupId: mockViewFilter.viewFilterGroupId,
positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup, positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup,
definition: mockFilterDefinition, definition: mockFilterDefinition,
}, label: mockViewFilter.displayValue,
type: getFilterTypeFromFieldType(mockFieldMetadataItem.type),
} satisfies RecordFilter,
]); ]);
}); });
@@ -1,7 +1,11 @@
import { act, renderHook } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react';
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import {
formatFieldMetadataItemAsFilterDefinition,
getFilterTypeFromFieldType,
} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition'; import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { ViewFilter } from '@/views/types/ViewFilter'; import { ViewFilter } from '@/views/types/ViewFilter';
@@ -35,7 +39,7 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => {
fieldMetadataId: mockFieldMetadataItem.id, fieldMetadataId: mockFieldMetadataItem.id,
operand: ViewFilterOperand.Contains, operand: ViewFilterOperand.Contains,
value: 'test', value: 'test',
displayValue: 'test', displayValue: mockFieldMetadataItem.label,
viewFilterGroupId: 'group-1', viewFilterGroupId: 'group-1',
positionInViewFilterGroup: 0, positionInViewFilterGroup: 0,
definition: mockAvailableFilterDefinition, definition: mockAvailableFilterDefinition,
@@ -72,7 +76,9 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => {
viewFilterGroupId: mockViewFilter.viewFilterGroupId, viewFilterGroupId: mockViewFilter.viewFilterGroupId,
positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup, positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup,
definition: mockAvailableFilterDefinition, definition: mockAvailableFilterDefinition,
}, label: mockViewFilter.displayValue,
type: getFilterTypeFromFieldType(mockFieldMetadataItem.type),
} satisfies RecordFilter,
]); ]);
}); });
@@ -10,6 +10,7 @@ import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinit
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { FieldMetadataType } from '~/generated/graphql'; import { FieldMetadataType } from '~/generated/graphql';
const baseDefinition = { const baseDefinition = {
@@ -65,6 +66,10 @@ describe('mapViewFiltersToFilters', () => {
...baseDefinition, ...baseDefinition,
type: 'FULL_NAME', type: 'FULL_NAME',
}, },
label: baseDefinition.label,
type: 'FULL_NAME',
positionInViewFilterGroup: undefined,
viewFilterGroupId: undefined,
}, },
]; ];
expect( expect(
@@ -26,6 +26,8 @@ export const mapViewFiltersToFilters = (
viewFilterGroupId: viewFilter.viewFilterGroupId, viewFilterGroupId: viewFilter.viewFilterGroupId,
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup, positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
definition: viewFilter.definition ?? availableFilterDefinition, definition: viewFilter.definition ?? availableFilterDefinition,
label: viewFilter.definition?.label ?? availableFilterDefinition.label,
type: viewFilter.definition?.type ?? availableFilterDefinition.type,
}; };
}) })
.filter(isDefined); .filter(isDefined);