fix: filter and sort options to match order of table columns (#7392)

### ISSUE

- Closes #5960 

### Demo


https://github.com/user-attachments/assets/279b19cf-6841-4a63-82ed-423bc0eb4395

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Nabhag Motivaras
2024-10-10 20:35:22 +05:30
committed by GitHub
parent 2c927cfd7e
commit 539dc9506d
14 changed files with 573 additions and 277 deletions

View File

@ -1,38 +1,19 @@
import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect';
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
import { ObjectFilterDropdownTextSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput';
import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu';
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect';
import { ObjectFilterDropdownDateInput } from './ObjectFilterDropdownDateInput';
import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect';
import { ObjectFilterDropdownNumberInput } from './ObjectFilterDropdownNumberInput';
import { ObjectFilterDropdownOperandButton } from './ObjectFilterDropdownOperandButton';
import { ObjectFilterDropdownOperandSelect } from './ObjectFilterDropdownOperandSelect';
import { ObjectFilterDropdownOptionSelect } from './ObjectFilterDropdownOptionSelect';
const StyledContainer = styled.div`
position: relative;
`;
const StyledOperandSelectContainer = styled.div`
background: ${({ theme }) => theme.background.secondary};
box-shadow: ${({ theme }) => theme.boxShadow.light};
border-radius: ${({ theme }) => theme.border.radius.md};
left: 10px;
position: absolute;
top: 10px;
width: 100%;
z-index: 1000;
`;
type MultipleFiltersDropdownContentProps = {
filterDropdownId?: string;
};
@ -40,99 +21,38 @@ type MultipleFiltersDropdownContentProps = {
export const MultipleFiltersDropdownContent = ({
filterDropdownId,
}: MultipleFiltersDropdownContentProps) => {
const {
filterDefinitionUsedInDropdownState,
selectedOperandInDropdownState,
isObjectFilterDropdownOperandSelectUnfoldedState,
} = useFilterDropdown({ filterDropdownId });
const { filterDefinitionUsedInDropdownState } = useFilterDropdown({
filterDropdownId,
});
const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue(
isObjectFilterDropdownOperandSelectUnfoldedState,
const [objectFilterDropdownIsSelectingCompositeField] =
useRecoilComponentStateV2(
objectFilterDropdownIsSelectingCompositeFieldComponentState,
filterDropdownId,
);
const [objectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
objectFilterDropdownFilterIsSelectedComponentState,
filterDropdownId,
);
const filterDefinitionUsedInDropdown = useRecoilValue(
filterDefinitionUsedInDropdownState,
);
const selectedOperandInDropdown = useRecoilValue(
selectedOperandInDropdownState,
);
const shouldShowCompositeSelectionSubMenu =
objectFilterDropdownIsSelectingCompositeField;
const isConfigurable =
selectedOperandInDropdown &&
[
ViewFilterOperand.Is,
ViewFilterOperand.IsNotNull,
ViewFilterOperand.IsNot,
ViewFilterOperand.LessThan,
ViewFilterOperand.GreaterThan,
ViewFilterOperand.IsBefore,
ViewFilterOperand.IsAfter,
ViewFilterOperand.Contains,
ViewFilterOperand.DoesNotContain,
ViewFilterOperand.IsRelative,
].includes(selectedOperandInDropdown);
const shoudShowFilterInput = objectFilterDropdownFilterIsSelected;
return (
<StyledContainer>
{!filterDefinitionUsedInDropdown ? (
<ObjectFilterDropdownFilterSelect />
{shoudShowFilterInput ? (
<ObjectFilterDropdownFilterInput filterDropdownId={filterDropdownId} />
) : shouldShowCompositeSelectionSubMenu ? (
<ObjectFilterDropdownFilterSelectCompositeFieldSubMenu />
) : (
<>
<ObjectFilterDropdownOperandButton />
{isObjectFilterDropdownOperandSelectUnfolded && (
<StyledOperandSelectContainer>
<ObjectFilterDropdownOperandSelect />
</StyledOperandSelectContainer>
)}
{isConfigurable && selectedOperandInDropdown && (
<>
{[
'TEXT',
'EMAIL',
'EMAILS',
'PHONE',
'FULL_NAME',
'LINK',
'LINKS',
'ADDRESS',
'ACTOR',
'ARRAY',
'PHONES',
].includes(filterDefinitionUsedInDropdown.type) &&
!isActorSourceCompositeFilter(
filterDefinitionUsedInDropdown,
) && <ObjectFilterDropdownTextSearchInput />}
{['NUMBER', 'CURRENCY'].includes(
filterDefinitionUsedInDropdown.type,
) && <ObjectFilterDropdownNumberInput />}
{filterDefinitionUsedInDropdown.type === 'RATING' && (
<ObjectFilterDropdownRatingInput />
)}
{['DATE_TIME', 'DATE'].includes(
filterDefinitionUsedInDropdown.type,
) && <ObjectFilterDropdownDateInput />}
{filterDefinitionUsedInDropdown.type === 'RELATION' && (
<>
<ObjectFilterDropdownSearchInput />
<ObjectFilterDropdownRecordSelect />
</>
)}
{isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
<>
<DropdownMenuSeparator />
<ObjectFilterDropdownSourceSelect />
</>
)}
{filterDefinitionUsedInDropdown.type === 'SELECT' && (
<>
<ObjectFilterDropdownSearchInput />
<ObjectFilterDropdownOptionSelect />
</>
)}
</>
)}
</>
<ObjectFilterDropdownFilterSelect />
)}
<MultipleFiltersDropdownFilterOnFilterChangedEffect
filterDefinitionUsedInDropdownType={

View File

@ -1,6 +1,7 @@
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton';
@ -29,12 +30,16 @@ export const ObjectFilterDropdownButton = ({
}
return (
<ObjectFilterDropdownScope filterScopeId={filterDropdownId}>
{hasOnlyOneEntityFilter ? (
<SingleEntityObjectFilterDropdownButton hotkeyScope={hotkeyScope} />
) : (
<MultipleFiltersDropdownButton hotkeyScope={hotkeyScope} />
)}
</ObjectFilterDropdownScope>
<ObjectFilterDropdownComponentInstanceContext.Provider
value={{ instanceId: filterDropdownId }}
>
<ObjectFilterDropdownScope filterScopeId={filterDropdownId}>
{hasOnlyOneEntityFilter ? (
<SingleEntityObjectFilterDropdownButton hotkeyScope={hotkeyScope} />
) : (
<MultipleFiltersDropdownButton hotkeyScope={hotkeyScope} />
)}
</ObjectFilterDropdownScope>
</ObjectFilterDropdownComponentInstanceContext.Provider>
);
};

View File

@ -0,0 +1,132 @@
import { useRecoilValue } from 'recoil';
import { ObjectFilterDropdownDateInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput';
import { ObjectFilterDropdownNumberInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput';
import { ObjectFilterDropdownOperandButton } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandButton';
import { ObjectFilterDropdownOperandSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect';
import { ObjectFilterDropdownOptionSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect';
import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect';
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
import { ObjectFilterDropdownTextSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-ui';
const StyledOperandSelectContainer = styled.div`
background: ${({ theme }) => theme.background.secondary};
box-shadow: ${({ theme }) => theme.boxShadow.light};
border-radius: ${({ theme }) => theme.border.radius.md};
left: 10px;
position: absolute;
top: 10px;
width: 100%;
z-index: 1000;
`;
type ObjectFilterDropdownFilterInputProps = {
filterDropdownId?: string;
};
export const ObjectFilterDropdownFilterInput = ({
filterDropdownId,
}: ObjectFilterDropdownFilterInputProps) => {
const {
filterDefinitionUsedInDropdownState,
selectedOperandInDropdownState,
isObjectFilterDropdownOperandSelectUnfoldedState,
} = useFilterDropdown({ filterDropdownId });
const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue(
isObjectFilterDropdownOperandSelectUnfoldedState,
);
const filterDefinitionUsedInDropdown = useRecoilValue(
filterDefinitionUsedInDropdownState,
);
const selectedOperandInDropdown = useRecoilValue(
selectedOperandInDropdownState,
);
const isConfigurable =
selectedOperandInDropdown &&
[
ViewFilterOperand.Is,
ViewFilterOperand.IsNotNull,
ViewFilterOperand.IsNot,
ViewFilterOperand.LessThan,
ViewFilterOperand.GreaterThan,
ViewFilterOperand.IsBefore,
ViewFilterOperand.IsAfter,
ViewFilterOperand.Contains,
ViewFilterOperand.DoesNotContain,
ViewFilterOperand.IsRelative,
].includes(selectedOperandInDropdown);
if (!isDefined(filterDefinitionUsedInDropdown)) {
return null;
}
return (
<>
<ObjectFilterDropdownOperandButton />
{isObjectFilterDropdownOperandSelectUnfolded && (
<StyledOperandSelectContainer>
<ObjectFilterDropdownOperandSelect />
</StyledOperandSelectContainer>
)}
{isConfigurable && selectedOperandInDropdown && (
<>
{[
'TEXT',
'EMAIL',
'EMAILS',
'PHONE',
'FULL_NAME',
'LINK',
'LINKS',
'ADDRESS',
'ACTOR',
'ARRAY',
'PHONES',
].includes(filterDefinitionUsedInDropdown.type) &&
!isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
<ObjectFilterDropdownTextSearchInput />
)}
{['NUMBER', 'CURRENCY'].includes(
filterDefinitionUsedInDropdown.type,
) && <ObjectFilterDropdownNumberInput />}
{filterDefinitionUsedInDropdown.type === 'RATING' && (
<ObjectFilterDropdownRatingInput />
)}
{['DATE_TIME', 'DATE'].includes(
filterDefinitionUsedInDropdown.type,
) && <ObjectFilterDropdownDateInput />}
{filterDefinitionUsedInDropdown.type === 'RELATION' && (
<>
<ObjectFilterDropdownSearchInput />
<ObjectFilterDropdownRecordSelect />
</>
)}
{isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
<>
<DropdownMenuSeparator />
<ObjectFilterDropdownSourceSelect />
</>
)}
{filterDefinitionUsedInDropdown.type === 'SELECT' && (
<>
<ObjectFilterDropdownSearchInput />
<ObjectFilterDropdownOptionSelect />
</>
)}
</>
)}
</>
);
};

View File

@ -1,27 +1,23 @@
import styled from '@emotion/styled';
import { useState } from 'react';
import { useContext } from 'react';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu';
import { ObjectFilterDropdownFilterSelectMenuItem } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem';
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
import { useRecoilValue } from 'recoil';
import { isDefined, useIcons } from 'twenty-ui';
import { getOperandsForFilterDefinition } from '../utils/getOperandsForFilterType';
import { isDefined } from 'twenty-ui';
export const StyledInput = styled.input`
background: transparent;
@ -50,15 +46,7 @@ export const StyledInput = styled.input`
`;
export const ObjectFilterDropdownFilterSelect = () => {
const [subMenuFieldType, setSubMenuFieldType] =
useState<CompositeFilterableFieldType | null>(null);
const [firstLevelFilterDefinition, setFirstLevelFilterDefinition] =
useState<FilterDefinition | null>(null);
const {
setFilterDefinitionUsedInDropdown,
setSelectedOperandInDropdown,
setObjectFilterDropdownSearchInput,
objectFilterDropdownSearchInputState,
} = useFilterDropdown();
@ -70,16 +58,41 @@ export const ObjectFilterDropdownFilterSelect = () => {
const availableFilterDefinitions = useRecoilComponentValueV2(
availableFilterDefinitionsComponentState,
);
const { recordIndexId } = useContext(RecordIndexRootPropsContext);
const { hiddenTableColumnsSelector, visibleTableColumnsSelector } =
useRecordTableStates(recordIndexId);
const sortedAvailableFilterDefinitions = [...availableFilterDefinitions]
.sort((a, b) => a.label.localeCompare(b.label))
.filter((item) =>
const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector());
const visibleColumnsIds = visibleTableColumns.map(
(column) => column.fieldMetadataId,
);
const hiddenTableColumns = useRecoilValue(hiddenTableColumnsSelector());
const hiddenColumnIds = hiddenTableColumns.map(
(column) => column.fieldMetadataId,
);
const filteredSearchInputFilterDefinitions =
availableFilterDefinitions.filter((item) =>
item.label
.toLocaleLowerCase()
.includes(objectFilterDropdownSearchInput.toLocaleLowerCase()),
);
const selectableListItemIds = sortedAvailableFilterDefinitions.map(
const visibleColumnsFilterDefinitions = filteredSearchInputFilterDefinitions
.sort((a, b) => {
return (
visibleColumnsIds.indexOf(a.fieldMetadataId) -
visibleColumnsIds.indexOf(b.fieldMetadataId)
);
})
.filter((item) => visibleColumnsIds.includes(item.fieldMetadataId));
const hiddenColumnsFilterDefinitions = filteredSearchInputFilterDefinitions
.sort((a, b) => a.label.localeCompare(b.label))
.filter((item) => hiddenColumnIds.includes(item.fieldMetadataId));
const selectableListItemIds = availableFilterDefinitions.map(
(item) => item.fieldMetadataId,
);
@ -88,7 +101,7 @@ export const ObjectFilterDropdownFilterSelect = () => {
const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
const handleEnter = (itemId: string) => {
const selectedFilterDefinition = sortedAvailableFilterDefinitions.find(
const selectedFilterDefinition = availableFilterDefinitions.find(
(item) => item.fieldMetadataId === itemId,
);
@ -101,96 +114,56 @@ export const ObjectFilterDropdownFilterSelect = () => {
selectFilter({ filterDefinition: selectedFilterDefinition });
};
const setHotkeyScope = useSetHotkeyScope();
const { getIcon } = useIcons();
const handleSelectFilter = (availableFilterDefinition: FilterDefinition) => {
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
if (
availableFilterDefinition.type === 'RELATION' ||
availableFilterDefinition.type === 'SELECT'
) {
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
}
setSelectedOperandInDropdown(
getOperandsForFilterDefinition(availableFilterDefinition)[0],
);
setObjectFilterDropdownSearchInput('');
};
const handleSubMenuBack = () => {
setSubMenuFieldType(null);
setFirstLevelFilterDefinition(null);
};
const shouldShowFirstLevelMenu = !isDefined(subMenuFieldType);
const shoudShowSeparator =
visibleColumnsFilterDefinitions.length > 0 &&
hiddenColumnsFilterDefinitions.length > 0;
return (
<>
{shouldShowFirstLevelMenu ? (
<>
<StyledInput
value={objectFilterDropdownSearchInput}
autoFocus
placeholder="Search fields"
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
setObjectFilterDropdownSearchInput(event.target.value)
}
/>
<SelectableList
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
selectableItemIdArray={selectableListItemIds}
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
onEnter={handleEnter}
>
<DropdownMenuItemsContainer>
{[...availableFilterDefinitions]
.sort((a, b) => a.label.localeCompare(b.label))
.filter((item) =>
item.label
.toLocaleLowerCase()
.includes(
objectFilterDropdownSearchInput.toLocaleLowerCase(),
),
)
.map((availableFilterDefinition, index) => (
<SelectableItem
itemId={availableFilterDefinition.fieldMetadataId}
>
<MenuItem
key={`select-filter-${index}`}
testId={`select-filter-${index}`}
onClick={() => {
if (isCompositeField(availableFilterDefinition.type)) {
setSubMenuFieldType(availableFilterDefinition.type);
setFirstLevelFilterDefinition(
availableFilterDefinition,
);
} else {
handleSelectFilter(availableFilterDefinition);
}
}}
LeftIcon={getIcon(availableFilterDefinition.iconName)}
text={availableFilterDefinition.label}
hasSubMenu={isCompositeField(
availableFilterDefinition.type,
)}
/>
</SelectableItem>
))}
</DropdownMenuItemsContainer>
</SelectableList>
</>
) : (
<ObjectFilterDropdownFilterSelectCompositeFieldSubMenu
fieldType={subMenuFieldType}
firstLevelFieldDefinition={firstLevelFilterDefinition}
onBack={handleSubMenuBack}
/>
)}
<StyledInput
value={objectFilterDropdownSearchInput}
autoFocus
placeholder="Search fields"
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
setObjectFilterDropdownSearchInput(event.target.value)
}
/>
<SelectableList
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
selectableItemIdArray={selectableListItemIds}
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
onEnter={handleEnter}
>
<DropdownMenuItemsContainer>
{visibleColumnsFilterDefinitions.map(
(visibleFilterDefinition, index) => (
<SelectableItem
itemId={visibleFilterDefinition.fieldMetadataId}
key={`visible-select-filter-${index}`}
>
<ObjectFilterDropdownFilterSelectMenuItem
filterDefinition={visibleFilterDefinition}
/>
</SelectableItem>
),
)}
</DropdownMenuItemsContainer>
{shoudShowSeparator && <DropdownMenuSeparator />}
<DropdownMenuItemsContainer>
{hiddenColumnsFilterDefinitions.map(
(hiddenFilterDefinition, index) => (
<SelectableItem
itemId={hiddenFilterDefinition.fieldMetadataId}
key={`hidden-select-filter-${index}`}
>
<ObjectFilterDropdownFilterSelectMenuItem
filterDefinition={hiddenFilterDefinition}
/>
</SelectableItem>
),
)}
</DropdownMenuItemsContainer>
</SelectableList>
</>
);
};

View File

@ -1,6 +1,8 @@
import { StyledInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState';
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
@ -9,24 +11,33 @@ import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/con
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useState } from 'react';
import { IconApps, IconChevronLeft, useIcons } from 'twenty-ui';
import { IconApps, IconChevronLeft, isDefined, useIcons } from 'twenty-ui';
type ObjectFilterDropdownFilterSelectCompositeFieldSubMenuProps = {
fieldType: CompositeFilterableFieldType;
firstLevelFieldDefinition: FilterDefinition | null;
onBack: () => void;
};
export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
fieldType,
firstLevelFieldDefinition,
onBack,
}: ObjectFilterDropdownFilterSelectCompositeFieldSubMenuProps) => {
export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
const [searchText, setSearchText] = useState('');
const { getIcon } = useIcons();
const [
objectFilterDropdownFirstLevelFilterDefinition,
setObjectFilterDropdownFirstLevelFilterDefinition,
] = useRecoilComponentStateV2(
objectFilterDropdownFirstLevelFilterDefinitionComponentState,
);
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
objectFilterDropdownFilterIsSelectedComponentState,
);
const [
objectFilterDropdownSubMenuFieldType,
setObjectFilterDropdownSubMenuFieldType,
] = useRecoilComponentStateV2(
objectFilterDropdownSubMenuFieldTypeComponentState,
);
const {
setFilterDefinitionUsedInDropdown,
setSelectedOperandInDropdown,
@ -42,11 +53,26 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
);
setObjectFilterDropdownSearchInput('');
setObjectFilterDropdownFilterIsSelected(true);
}
};
const handleSubMenuBack = () => {
setFilterDefinitionUsedInDropdown(null);
setObjectFilterDropdownSubMenuFieldType(null);
setObjectFilterDropdownFirstLevelFilterDefinition(null);
};
if (
!isDefined(objectFilterDropdownSubMenuFieldType) ||
!isDefined(objectFilterDropdownFirstLevelFilterDefinition)
) {
return null;
}
const options = SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS[
fieldType
objectFilterDropdownSubMenuFieldType
].filterableSubFields
.sort((a, b) => a.localeCompare(b))
.filter((item) =>
@ -55,8 +81,11 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
return (
<>
<DropdownMenuHeader StartIcon={IconChevronLeft} onClick={onBack}>
{getFilterableFieldTypeLabel(fieldType)}
<DropdownMenuHeader
StartIcon={IconChevronLeft}
onClick={handleSubMenuBack}
>
{getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)}
</DropdownMenuHeader>
<StyledInput
value={searchText}
@ -71,25 +100,34 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
key={`select-filter-${-1}`}
testId={`select-filter-${-1}`}
onClick={() => {
handleSelectFilter(firstLevelFieldDefinition);
handleSelectFilter(objectFilterDropdownFirstLevelFilterDefinition);
}}
LeftIcon={IconApps}
text={`Any ${getFilterableFieldTypeLabel(fieldType)} field`}
text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`}
/>
{options.map((subFieldName, index) => (
<MenuItem
key={`select-filter-${index}`}
testId={`select-filter-${index}`}
onClick={() =>
firstLevelFieldDefinition &&
handleSelectFilter({
...firstLevelFieldDefinition,
label: getCompositeSubFieldLabel(fieldType, subFieldName),
compositeFieldName: subFieldName,
})
}
text={getCompositeSubFieldLabel(fieldType, subFieldName)}
LeftIcon={getIcon(firstLevelFieldDefinition?.iconName)}
onClick={() => {
if (isDefined(objectFilterDropdownFirstLevelFilterDefinition)) {
handleSelectFilter({
...objectFilterDropdownFirstLevelFilterDefinition,
label: getCompositeSubFieldLabel(
objectFilterDropdownSubMenuFieldType,
subFieldName,
),
compositeFieldName: subFieldName,
});
}
}}
text={getCompositeSubFieldLabel(
objectFilterDropdownSubMenuFieldType,
subFieldName,
)}
LeftIcon={getIcon(
objectFilterDropdownFirstLevelFilterDefinition?.iconName,
)}
/>
))}
</DropdownMenuItemsContainer>

View File

@ -1,9 +1,20 @@
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState';
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
import { getOperandsForFilterDefinition } from '@/object-record/object-filter-dropdown/utils/getOperandsForFilterType';
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useRecoilValue } from 'recoil';
import { useIcons } from 'twenty-ui';
@ -16,6 +27,24 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
}: ObjectFilterDropdownFilterSelectMenuItemProps) => {
const { selectFilter } = useSelectFilter();
const [, setObjectFilterDropdownFirstLevelFilterDefinition] =
useRecoilComponentStateV2(
objectFilterDropdownFirstLevelFilterDefinitionComponentState,
);
const [, setObjectFilterDropdownSubMenuFieldType] = useRecoilComponentStateV2(
objectFilterDropdownSubMenuFieldTypeComponentState,
);
const [, setObjectFilterDropdownIsSelectingCompositeField] =
useRecoilComponentStateV2(
objectFilterDropdownIsSelectingCompositeFieldComponentState,
);
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
objectFilterDropdownFilterIsSelectedComponentState,
);
const { isSelectedItemIdSelector, resetSelectedItem } = useSelectableList(
OBJECT_FILTER_DROPDOWN_ID,
);
@ -24,12 +53,52 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
isSelectedItemIdSelector(filterDefinition.fieldMetadataId),
);
const isACompositeField = isCompositeField(filterDefinition.type);
const {
setFilterDefinitionUsedInDropdown,
setSelectedOperandInDropdown,
setObjectFilterDropdownSearchInput,
} = useFilterDropdown();
const setHotkeyScope = useSetHotkeyScope();
const handleSelectFilter = (availableFilterDefinition: FilterDefinition) => {
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
if (
availableFilterDefinition.type === 'RELATION' ||
availableFilterDefinition.type === 'SELECT'
) {
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
}
setSelectedOperandInDropdown(
getOperandsForFilterDefinition(availableFilterDefinition)[0],
);
setObjectFilterDropdownSearchInput('');
setObjectFilterDropdownFilterIsSelected(true);
};
const { getIcon } = useIcons();
const handleClick = () => {
resetSelectedItem();
selectFilter({ filterDefinition });
if (isACompositeField) {
// TODO: create isCompositeFilterableFieldType type guard
setObjectFilterDropdownSubMenuFieldType(
filterDefinition.type as CompositeFilterableFieldType,
);
setObjectFilterDropdownFirstLevelFilterDefinition(filterDefinition);
setObjectFilterDropdownIsSelectingCompositeField(true);
} else {
handleSelectFilter(filterDefinition);
}
};
return (
@ -39,6 +108,7 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
onClick={handleClick}
LeftIcon={getIcon(filterDefinition.iconName)}
text={filterDefinition.label}
hasSubMenu={isACompositeField}
/>
);
};

View File

@ -3,10 +3,15 @@ import { Meta, StoryObj } from '@storybook/react';
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton';
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
import { within } from '@storybook/test';
import { useSetRecoilState } from 'recoil';
import { ComponentDecorator } from 'twenty-ui';
import { FieldMetadataType } from '~/generated/graphql';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
@ -25,6 +30,43 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
instanceId,
);
const { tableColumnsState } = useRecordTableStates(instanceId);
const setTableColumns = useSetRecoilState(tableColumnsState);
setTableColumns([
{
fieldMetadataId: '1',
iconName: 'IconUser',
label: 'Text',
type: FieldMetadataType.Text,
isVisible: true,
metadata: {
fieldName: 'text',
},
} as ColumnDefinition<any>,
{
fieldMetadataId: '3',
iconName: 'IconNumber',
label: 'Number',
type: FieldMetadataType.Number,
isVisible: true,
metadata: {
fieldName: 'number',
},
} as ColumnDefinition<any>,
{
fieldMetadataId: '4',
iconName: 'IconCalendar',
label: 'Date',
type: FieldMetadataType.DateTime,
isVisible: true,
metadata: {
fieldName: 'date',
},
} as ColumnDefinition<any>,
]);
setAvailableFilterDefinitions([
{
fieldMetadataId: '1',
@ -32,12 +74,6 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
label: 'Text',
type: FieldMetadataType.Text,
},
{
fieldMetadataId: '2',
iconName: 'Icon123',
label: 'Email',
type: FieldMetadataType.Emails,
},
{
fieldMetadataId: '3',
iconName: 'IconNumber',
@ -52,11 +88,19 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
},
]);
return (
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
<ObjectFilterDropdownScope filterScopeId={instanceId}>
<Story />
</ObjectFilterDropdownScope>
</ViewComponentInstanceContext.Provider>
<ObjectFilterDropdownComponentInstanceContext.Provider
value={{ instanceId }}
>
<RecordTableScopeInternalContext.Provider
value={{ scopeId: instanceId, onColumnsChange: () => {} }}
>
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
<ObjectFilterDropdownScope filterScopeId={instanceId}>
<Story />
</ObjectFilterDropdownScope>
</ViewComponentInstanceContext.Provider>
</RecordTableScopeInternalContext.Provider>
</ObjectFilterDropdownComponentInstanceContext.Provider>
);
},
ObjectMetadataItemsDecorator,

View File

@ -4,6 +4,9 @@ import { useFilterDropdownStates } from '@/object-record/object-filter-dropdown/
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { ObjectFilterDropdownScopeInternalContext } from '../scopes/scope-internal-context/ObjectFilterDropdownScopeInternalContext';
import { Filter } from '../types/Filter';
@ -54,6 +57,18 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => {
],
);
const setObjectFilterDropdownFilterIsSelectedCallbackState =
useRecoilComponentCallbackStateV2(
objectFilterDropdownFilterIsSelectedComponentState,
props?.filterDropdownId,
);
const setObjectFilterDropdownIsSelectingCompositeFieldCallbackState =
useRecoilComponentCallbackStateV2(
objectFilterDropdownIsSelectingCompositeFieldComponentState,
props?.filterDropdownId,
);
const resetFilter = useRecoilCallback(
({ set }) =>
() => {
@ -62,6 +77,11 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => {
set(selectedFilterState, undefined);
set(filterDefinitionUsedInDropdownState, null);
set(selectedOperandInDropdownState, null);
set(setObjectFilterDropdownFilterIsSelectedCallbackState, false);
set(
setObjectFilterDropdownIsSelectingCompositeFieldCallbackState,
false,
);
},
[
filterDefinitionUsedInDropdownState,
@ -69,6 +89,8 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => {
objectFilterDropdownSelectedRecordIdsState,
selectedFilterState,
selectedOperandInDropdownState,
setObjectFilterDropdownFilterIsSelectedCallbackState,
setObjectFilterDropdownIsSelectingCompositeFieldCallbackState,
],
);

View File

@ -0,0 +1,4 @@
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
export const ObjectFilterDropdownComponentInstanceContext =
createComponentInstanceContext();

View File

@ -0,0 +1,9 @@
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const objectFilterDropdownFilterIsSelectedComponentState =
createComponentStateV2<boolean>({
key: 'objectFilterDropdownFilterIsSelectedComponentState',
defaultValue: false,
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
});

View File

@ -0,0 +1,10 @@
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const objectFilterDropdownFirstLevelFilterDefinitionComponentState =
createComponentStateV2<FilterDefinition | null>({
key: 'objectFilterDropdownFirstLevelFilterDefinitionComponentState',
defaultValue: null,
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
});

View File

@ -0,0 +1,9 @@
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const objectFilterDropdownIsSelectingCompositeFieldComponentState =
createComponentStateV2<boolean>({
key: 'objectFilterDropdownIsSelectingCompositeFieldComponentState',
defaultValue: false,
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
});

View File

@ -0,0 +1,10 @@
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const objectFilterDropdownSubMenuFieldTypeComponentState =
createComponentStateV2<CompositeFilterableFieldType | null>({
key: 'objectFilterDropdownSubMenuFieldTypeComponentState',
defaultValue: null,
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
});

View File

@ -5,14 +5,17 @@ import { IconChevronDown, useIcons } from 'twenty-ui';
import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId';
import { useObjectSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useObjectSortDropdown';
import { ObjectSortDropdownScope } from '@/object-record/object-sort-dropdown/scopes/ObjectSortDropdownScope';
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useContext } from 'react';
import { SORT_DIRECTIONS } from '../types/SortDirection';
export const StyledInput = styled.input`
@ -94,6 +97,43 @@ export const ObjectSortDropdownButton = ({
const { getIcon } = useIcons();
const { recordIndexId } = useContext(RecordIndexRootPropsContext);
const { hiddenTableColumnsSelector, visibleTableColumnsSelector } =
useRecordTableStates(recordIndexId);
const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector());
const visibleColumnsIds = visibleTableColumns.map(
(column) => column.fieldMetadataId,
);
const hiddenTableColumns = useRecoilValue(hiddenTableColumnsSelector());
const hiddenColumnIds = hiddenTableColumns.map(
(column) => column.fieldMetadataId,
);
const filteredSearchInputSortDefinitions = availableSortDefinitions.filter(
(item) =>
item.label
.toLocaleLowerCase()
.includes(objectSortDropdownSearchInput.toLocaleLowerCase()),
);
const visibleColumnsSortDefinitions = filteredSearchInputSortDefinitions
.sort((a, b) => {
return (
visibleColumnsIds.indexOf(a.fieldMetadataId) -
visibleColumnsIds.indexOf(b.fieldMetadataId)
);
})
.filter((item) => visibleColumnsIds.includes(item.fieldMetadataId));
const hiddenColumnsSortDefinitions = filteredSearchInputSortDefinitions
.sort((a, b) => a.label.localeCompare(b.label))
.filter((item) => hiddenColumnIds.includes(item.fieldMetadataId));
const shoudShowSeparator =
visibleColumnsSortDefinitions.length > 0 &&
hiddenColumnsSortDefinitions.length > 0;
return (
<ObjectSortDropdownScope sortScopeId={sortDropdownId}>
<Dropdown
@ -142,27 +182,37 @@ export const ObjectSortDropdownButton = ({
}
/>
<DropdownMenuItemsContainer>
{[...availableSortDefinitions]
.sort((a, b) => a.label.localeCompare(b.label))
.filter((item) =>
item.label
.toLocaleLowerCase()
.includes(
objectSortDropdownSearchInput.toLocaleLowerCase(),
),
)
.map((availableSortDefinition, index) => (
{visibleColumnsSortDefinitions.map(
(visibleSortDefinition, index) => (
<MenuItem
testId={`select-sort-${index}`}
testId={`visible-select-sort-${index}`}
key={index}
onClick={() => {
setObjectSortDropdownSearchInput('');
handleAddSort(availableSortDefinition);
handleAddSort(visibleSortDefinition);
}}
LeftIcon={getIcon(availableSortDefinition.iconName)}
text={availableSortDefinition.label}
LeftIcon={getIcon(visibleSortDefinition.iconName)}
text={visibleSortDefinition.label}
/>
))}
),
)}
</DropdownMenuItemsContainer>
{shoudShowSeparator && <DropdownMenuSeparator />}
<DropdownMenuItemsContainer>
{hiddenColumnsSortDefinitions.map(
(hiddenSortDefinition, index) => (
<MenuItem
testId={`hidden-select-sort-${index}`}
key={index}
onClick={() => {
setObjectSortDropdownSearchInput('');
handleAddSort(hiddenSortDefinition);
}}
LeftIcon={getIcon(hiddenSortDefinition.iconName)}
text={hiddenSortDefinition.label}
/>
),
)}
</DropdownMenuItemsContainer>
</StyledContainer>
</>