Fixed sub-field filter dropdown content and icons (#12516)
This PR improves the sub-field selection UX in advanced filters. - Now using the icon of the field instead of the field type - Now using the label of the field instead of the field type - Removed now useless constant ICON_NAME_BY_ANY_SUB_FIELD - Now selects a default value (any or default sub-field for type) when clicking on the field, instead of waiting for the user to select the sub-field Fixes https://github.com/twentyhq/core-team-issues/issues/1005
This commit is contained in:
@ -106,17 +106,17 @@ export const AdvancedFilterFieldSelectMenu = ({
|
||||
selectedFieldMetadataItem.type,
|
||||
);
|
||||
|
||||
selectFieldUsedInAdvancedFilterDropdown({
|
||||
fieldMetadataItemId: selectedFieldMetadataItem.id,
|
||||
recordFilterId,
|
||||
});
|
||||
|
||||
if (isCompositeFieldType(filterType)) {
|
||||
setObjectFilterDropdownSubMenuFieldType(filterType);
|
||||
|
||||
setFieldMetadataItemIdUsedInDropdown(selectedFieldMetadataItem.id);
|
||||
setObjectFilterDropdownIsSelectingCompositeField(true);
|
||||
} else {
|
||||
selectFieldUsedInAdvancedFilterDropdown({
|
||||
fieldMetadataItemId: selectedFieldMetadataItem.id,
|
||||
recordFilterId,
|
||||
});
|
||||
|
||||
closeAdvancedFilterFieldSelectDropdown();
|
||||
}
|
||||
};
|
||||
|
||||
@ -10,12 +10,9 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor
|
||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
||||
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
||||
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
|
||||
import { DEFAULT_ANY_SUB_FIELD_ICON_NAME } from '@/object-record/record-filter/constants/DefaultAnySubFieldIconName';
|
||||
import { ICON_NAME_BY_ANY_SUB_FIELD } from '@/object-record/record-filter/constants/IconNameByAnySubField';
|
||||
import { ICON_NAME_BY_SUB_FIELD } from '@/object-record/record-filter/constants/IconNameBySubField';
|
||||
import { areCompositeTypeSubFieldsFilterable } from '@/object-record/record-filter/utils/areCompositeTypeSubFieldsFilterable';
|
||||
import { isCompositeTypeFilterableByAnySubField } from '@/object-record/record-filter/utils/isCompositeTypeFilterableByAnySubField';
|
||||
import { isCompositeTypeNonFilterableByAnySubField } from '@/object-record/record-filter/utils/isCompositeTypeNonFilterableByAnySubField';
|
||||
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
||||
import { CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
@ -103,7 +100,7 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
||||
|
||||
const compositeFieldTypeIsFilterableByAnySubField =
|
||||
isDefined(fieldMetadataItemUsedInDropdown) &&
|
||||
isCompositeTypeFilterableByAnySubField(
|
||||
!isCompositeTypeNonFilterableByAnySubField(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
);
|
||||
|
||||
@ -112,16 +109,6 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
||||
...subFieldNames.map((subFieldName) => subFieldName),
|
||||
];
|
||||
|
||||
const iconNameForAnySubField = isDefined(fieldMetadataItemUsedInDropdown)
|
||||
? ICON_NAME_BY_ANY_SUB_FIELD[fieldMetadataItemUsedInDropdown?.type]
|
||||
: (null ?? null);
|
||||
|
||||
const anySubFieldIcon = getIcon(
|
||||
iconNameForAnySubField ??
|
||||
fieldMetadataItemUsedInDropdown?.icon ??
|
||||
DEFAULT_ANY_SUB_FIELD_ICON_NAME,
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownContent>
|
||||
<DropdownMenuHeader
|
||||
@ -132,7 +119,7 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
||||
/>
|
||||
}
|
||||
>
|
||||
{getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)}
|
||||
{fieldMetadataItemUsedInDropdown?.label}
|
||||
</DropdownMenuHeader>
|
||||
<DropdownMenuItemsContainer>
|
||||
<SelectableList
|
||||
@ -155,7 +142,7 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
||||
onClick={() => {
|
||||
handleSelectFilter(fieldMetadataItemUsedInDropdown);
|
||||
}}
|
||||
LeftIcon={anySubFieldIcon}
|
||||
LeftIcon={getIcon(fieldMetadataItemUsedInDropdown.icon)}
|
||||
text={`Any ${fieldMetadataItemUsedInDropdown.label} field`}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
|
||||
@ -6,10 +6,13 @@ import { objectFilterDropdownSearchInputComponentState } from '@/object-record/o
|
||||
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 { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { isCompositeTypeNonFilterableByAnySubField } from '@/object-record/record-filter/utils/isCompositeTypeNonFilterableByAnySubField';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
|
||||
@ -81,7 +84,13 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
const firstOperand = getRecordFilterOperands({
|
||||
filterType,
|
||||
subFieldName,
|
||||
})[0];
|
||||
})?.[0];
|
||||
|
||||
if (!isDefined(firstOperand)) {
|
||||
throw new Error(
|
||||
`No valid operand found for filter type: ${filterType} and subFieldName: ${subFieldName}`,
|
||||
);
|
||||
}
|
||||
|
||||
setSelectedOperandInDropdown(firstOperand);
|
||||
|
||||
@ -94,6 +103,27 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
(recordFilter) => recordFilter.id === recordFilterId,
|
||||
);
|
||||
|
||||
const isCompositeFilterOnAnySubField =
|
||||
isCompositeFieldType(filterType) && !isDefined(subFieldName);
|
||||
const compositeFilterNonFilterableByAnySubField =
|
||||
isCompositeTypeNonFilterableByAnySubField(filterType);
|
||||
|
||||
let subFieldNameForNonFilterableWithAny:
|
||||
| CompositeFieldSubFieldName
|
||||
| undefined
|
||||
| null = subFieldName;
|
||||
|
||||
if (
|
||||
isCompositeFilterOnAnySubField &&
|
||||
compositeFilterNonFilterableByAnySubField
|
||||
) {
|
||||
subFieldNameForNonFilterableWithAny =
|
||||
getDefaultSubFieldNameForCompositeFilterableFieldType(filterType);
|
||||
}
|
||||
|
||||
const subFieldNameToUse =
|
||||
subFieldName ?? subFieldNameForNonFilterableWithAny;
|
||||
|
||||
const newAdvancedFilter = {
|
||||
id: recordFilterId,
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
@ -105,10 +135,10 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
existingRecordFilter?.positionInRecordFilterGroup,
|
||||
type: filterType,
|
||||
label: fieldMetadataItem.label,
|
||||
subFieldName,
|
||||
subFieldName: subFieldNameToUse,
|
||||
} satisfies RecordFilter;
|
||||
|
||||
setSubFieldNameUsedInDropdown(subFieldName);
|
||||
setSubFieldNameUsedInDropdown(subFieldNameToUse);
|
||||
|
||||
setObjectFilterDropdownSearchInput('');
|
||||
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
export const ICON_NAME_BY_ANY_SUB_FIELD: Partial<
|
||||
Record<FieldMetadataType, string>
|
||||
> = {
|
||||
[FieldMetadataType.LINKS]: 'IconLink',
|
||||
[FieldMetadataType.EMAILS]: 'IconMail',
|
||||
[FieldMetadataType.PHONES]: 'IconPhone',
|
||||
[FieldMetadataType.ADDRESS]: 'IconMap',
|
||||
[FieldMetadataType.ACTOR]: 'IconCreativeCommonsSa',
|
||||
[FieldMetadataType.FULL_NAME]: 'IconUser',
|
||||
[FieldMetadataType.POSITION]: 'IconBriefcase',
|
||||
};
|
||||
@ -8,8 +8,8 @@ const COMPOSITE_TYPES_NON_FILTERABLE_WITH_ANY = [
|
||||
type CompositeTypeNonFilterableWithAny =
|
||||
(typeof COMPOSITE_TYPES_NON_FILTERABLE_WITH_ANY)[number];
|
||||
|
||||
export const isCompositeTypeFilterableByAnySubField = (
|
||||
export const isCompositeTypeNonFilterableByAnySubField = (
|
||||
fieldType: FieldType,
|
||||
): fieldType is CompositeTypeNonFilterableWithAny => {
|
||||
return !COMPOSITE_TYPES_NON_FILTERABLE_WITH_ANY.includes(fieldType as any);
|
||||
return COMPOSITE_TYPES_NON_FILTERABLE_WITH_ANY.includes(fieldType as any);
|
||||
};
|
||||
Reference in New Issue
Block a user