diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx
index aa402d260..caf6db621 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx
@@ -1,15 +1,18 @@
import styled from '@emotion/styled';
import { useState } from 'react';
import { useRecoilValue } from 'recoil';
-import { useIcons } from 'twenty-ui';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
-import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
-import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
-import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
-import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
+import { ObjectFilterDropdownFilterSelectMenuItem } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem';
+import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
+import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
+import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
+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 { isDefined } from 'twenty-ui';
export const StyledInput = styled.input`
background: transparent;
@@ -39,20 +42,40 @@ export const StyledInput = styled.input`
export const ObjectFilterDropdownFilterSelect = () => {
const [searchText, setSearchText] = useState('');
- const {
- setFilterDefinitionUsedInDropdown,
- setSelectedOperandInDropdown,
- setObjectFilterDropdownSearchInput,
- availableFilterDefinitionsState,
- } = useFilterDropdown();
+
+ const { availableFilterDefinitionsState } = useFilterDropdown();
const availableFilterDefinitions = useRecoilValue(
availableFilterDefinitionsState,
);
- const { getIcon } = useIcons();
+ const sortedAvailableFilterDefinitions = [...availableFilterDefinitions]
+ .sort((a, b) => a.label.localeCompare(b.label))
+ .filter((item) =>
+ item.label.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()),
+ );
- const setHotkeyScope = useSetHotkeyScope();
+ const selectableListItemIds = sortedAvailableFilterDefinitions.map(
+ (item) => item.fieldMetadataId,
+ );
+
+ const { selectFilter } = useSelectFilter();
+
+ const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
+
+ const handleEnter = (itemId: string) => {
+ const selectedFilterDefinition = sortedAvailableFilterDefinitions.find(
+ (item) => item.fieldMetadataId === itemId,
+ );
+
+ if (!isDefined(selectedFilterDefinition)) {
+ return;
+ }
+
+ resetSelectedItem();
+
+ selectFilter({ filterDefinition: selectedFilterDefinition });
+ };
return (
<>
@@ -64,39 +87,27 @@ export const ObjectFilterDropdownFilterSelect = () => {
setSearchText(event.target.value)
}
/>
-
- {[...availableFilterDefinitions]
- .sort((a, b) => a.label.localeCompare(b.label))
- .filter((item) =>
- item.label
- .toLocaleLowerCase()
- .includes(searchText.toLocaleLowerCase()),
- )
- .map((availableFilterDefinition, index) => (
-
+
+
+ {sortedAvailableFilterDefinitions.map(
+ (availableFilterDefinition, index) => (
+
+
+
+ ),
+ )}
+
+
>
);
};
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx
new file mode 100644
index 000000000..eb04750c9
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem.tsx
@@ -0,0 +1,43 @@
+import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
+import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
+import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
+import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
+import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect';
+import { useRecoilValue } from 'recoil';
+import { useIcons } from 'twenty-ui';
+
+export type ObjectFilterDropdownFilterSelectMenuItemProps = {
+ filterDefinition: FilterDefinition;
+};
+
+export const ObjectFilterDropdownFilterSelectMenuItem = ({
+ filterDefinition,
+}: ObjectFilterDropdownFilterSelectMenuItemProps) => {
+ const { selectFilter } = useSelectFilter();
+
+ const { isSelectedItemIdSelector, resetSelectedItem } = useSelectableList(
+ OBJECT_FILTER_DROPDOWN_ID,
+ );
+
+ const isSelectedItem = useRecoilValue(
+ isSelectedItemIdSelector(filterDefinition.fieldMetadataId),
+ );
+
+ const { getIcon } = useIcons();
+
+ const handleClick = () => {
+ resetSelectedItem();
+
+ selectFilter({ filterDefinition });
+ };
+
+ return (
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx
index 9ced7ee64..213f828cf 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx
@@ -41,7 +41,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
selectableListScopeId: MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID,
});
- const { handleResetSelectedPosition } = useSelectableList(
+ const { resetSelectedItem } = useSelectableList(
MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID,
);
@@ -90,10 +90,10 @@ export const ObjectFilterDropdownOptionSelect = () => {
[Key.Escape],
() => {
closeDropdown();
- handleResetSelectedPosition();
+ resetSelectedItem();
},
RelationPickerHotkeyScope.RelationPicker,
- [closeDropdown, handleResetSelectedPosition],
+ [closeDropdown, resetSelectedItem],
);
const handleMultipleOptionSelectChange = (
@@ -137,7 +137,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
value: newFilterValue,
});
}
- handleResetSelectedPosition();
+ resetSelectedItem();
};
const optionsInDropdown = selectableOptions?.filter((option) =>
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilter.ts
new file mode 100644
index 000000000..3954d8d6d
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSelectFilter.ts
@@ -0,0 +1,40 @@
+import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
+import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
+import { getOperandsForFilterType } from '@/object-record/object-filter-dropdown/utils/getOperandsForFilterType';
+import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
+import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
+
+type SelectFilterParams = {
+ filterDefinition: FilterDefinition;
+};
+
+export const useSelectFilter = () => {
+ const {
+ setFilterDefinitionUsedInDropdown,
+ setSelectedOperandInDropdown,
+ setObjectFilterDropdownSearchInput,
+ } = useFilterDropdown();
+
+ const setHotkeyScope = useSetHotkeyScope();
+
+ const selectFilter = ({ filterDefinition }: SelectFilterParams) => {
+ setFilterDefinitionUsedInDropdown(filterDefinition);
+
+ if (
+ filterDefinition.type === 'RELATION' ||
+ filterDefinition.type === 'SELECT'
+ ) {
+ setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
+ }
+
+ setSelectedOperandInDropdown(
+ getOperandsForFilterType(filterDefinition.type)?.[0],
+ );
+
+ setObjectFilterDropdownSearchInput('');
+ };
+
+ return {
+ selectFilter,
+ };
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx
index c6134f911..f4c5745a4 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiSelectFieldInput.tsx
@@ -33,7 +33,7 @@ export const MultiSelectFieldInput = ({
const { selectedItemIdState } = useSelectableListStates({
selectableListScopeId: MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID,
});
- const { handleResetSelectedPosition } = useSelectableList(
+ const { resetSelectedItem } = useSelectableList(
MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID,
);
const { persistField, fieldDefinition, fieldValues, hotkeyScope } =
@@ -65,10 +65,10 @@ export const MultiSelectFieldInput = ({
Key.Escape,
() => {
onCancel?.();
- handleResetSelectedPosition();
+ resetSelectedItem();
},
hotkeyScope,
- [onCancel, handleResetSelectedPosition],
+ [onCancel, resetSelectedItem],
);
useListenClickOutside({
@@ -83,7 +83,7 @@ export const MultiSelectFieldInput = ({
if (weAreNotInAnHTMLInput && isDefined(onCancel)) {
onCancel();
}
- handleResetSelectedPosition();
+ resetSelectedItem();
},
});
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx
index d9082b850..86bea16ad 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx
@@ -27,7 +27,7 @@ export const SelectFieldInput = ({
const [filteredOptions, setFilteredOptions] = useState([]);
- const { handleResetSelectedPosition } = useSelectableList(
+ const { resetSelectedItem } = useSelectableList(
SINGLE_ENTITY_SELECT_BASE_LIST,
);
const clearField = useClearField();
@@ -44,17 +44,17 @@ export const SelectFieldInput = ({
const handleSubmit = (option: SelectOption) => {
onSubmit?.(() => persistField(option?.value));
- handleResetSelectedPosition();
+ resetSelectedItem();
};
useScopedHotkeys(
Key.Escape,
() => {
onCancel?.();
- handleResetSelectedPosition();
+ resetSelectedItem();
},
hotkeyScope,
- [onCancel, handleResetSelectedPosition],
+ [onCancel, resetSelectedItem],
);
const optionIds = [
@@ -74,7 +74,7 @@ export const SelectFieldInput = ({
);
if (isDefined(option)) {
onSubmit?.(() => persistField(option.value));
- handleResetSelectedPosition();
+ resetSelectedItem();
}
}}
>
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx
index 87c053220..f325edecc 100644
--- a/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/MultiRecordSelect.tsx
@@ -48,7 +48,7 @@ export const MultiRecordSelect = ({
const { objectRecordsIdsMultiSelectState, recordMultiSelectIsLoadingState } =
useObjectRecordMultiSelectScopedStates(relationPickerScopedId);
- const { handleResetSelectedPosition } = useSelectableList(
+ const { resetSelectedItem } = useSelectableList(
MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID,
);
const recordMultiSelectIsLoading = useRecoilValue(
@@ -79,10 +79,10 @@ export const MultiRecordSelect = ({
() => {
onSubmit?.();
goBackToPreviousHotkeyScope();
- handleResetSelectedPosition();
+ resetSelectedItem();
},
relationPickerScopedId,
- [onSubmit, goBackToPreviousHotkeyScope, handleResetSelectedPosition],
+ [onSubmit, goBackToPreviousHotkeyScope, resetSelectedItem],
);
const debouncedOnCreate = useDebouncedCallback(
@@ -123,7 +123,7 @@ export const MultiRecordSelect = ({
hotkeyScope={relationPickerScopedId}
onEnter={(selectedId) => {
onChange?.(selectedId);
- handleResetSelectedPosition();
+ resetSelectedItem();
}}
>
{objectRecordsIdsMultiSelect?.map((recordId) => {
@@ -133,7 +133,7 @@ export const MultiRecordSelect = ({
objectRecordId={recordId}
onChange={(recordId) => {
onChange?.(recordId);
- handleResetSelectedPosition();
+ resetSelectedItem();
}}
/>
);
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx
index 204467062..eef1523d1 100644
--- a/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/SelectableMenuItemSelect.tsx
@@ -27,7 +27,6 @@ export const SelectableMenuItemSelect = ({
);
const isSelectedItemId = useRecoilValue(isSelectedItemIdSelector(entity.id));
-
return (
{
- handleResetSelectedPosition();
+ resetSelectedItem();
onCancel?.();
},
hotkeyScope,
- [onCancel, handleResetSelectedPosition],
+ [onCancel, resetSelectedItem],
);
const selectableItemIds = entitiesInDropdown.map((entity) => entity.id);
@@ -134,7 +135,7 @@ export const SingleEntitySelectMenuItems = ({
);
onEntitySelected(entitiesInDropdown[entityIndex]);
}
- handleResetSelectedPosition();
+ resetSelectedItem();
}}
>
diff --git a/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx b/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx
index e8a286ad4..3914a4163 100644
--- a/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx
+++ b/packages/twenty-front/src/modules/object-record/select/components/MultipleRecordSelectDropdown.tsx
@@ -40,7 +40,7 @@ export const MultipleRecordSelectDropdown = ({
selectableListScopeId: selectableListId,
});
- const { handleResetSelectedPosition } = useSelectableList(selectableListId);
+ const { resetSelectedItem } = useSelectableList(selectableListId);
const selectedItemId = useRecoilValue(selectedItemIdState);
@@ -75,10 +75,10 @@ export const MultipleRecordSelectDropdown = ({
[Key.Escape],
() => {
closeDropdown();
- handleResetSelectedPosition();
+ resetSelectedItem();
},
hotkeyScope,
- [closeDropdown, handleResetSelectedPosition],
+ [closeDropdown, resetSelectedItem],
);
const showNoResult =
@@ -105,7 +105,7 @@ export const MultipleRecordSelectDropdown = ({
recordsInDropdown[record],
!recordIsSelectedInDropwdown,
);
- handleResetSelectedPosition();
+ resetSelectedItem();
}}
>
@@ -116,7 +116,7 @@ export const MultipleRecordSelectDropdown = ({
selected={record.isSelected}
isKeySelected={record.id === selectedItemId}
onSelectChange={(newCheckedValue) => {
- handleResetSelectedPosition();
+ resetSelectedItem();
handleRecordSelectChange(record, newCheckedValue);
}}
avatar={
diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx
index 7be321009..98da24f05 100644
--- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx
@@ -10,9 +10,7 @@ import { MouseEvent, useRef } from 'react';
import { Keys } from 'react-hotkeys-hook';
import { Key } from 'ts-key-enum';
-import { SINGLE_ENTITY_SELECT_BASE_LIST } from '@/object-record/relation-picker/constants/SingleEntitySelectBaseList';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
-import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@@ -69,9 +67,6 @@ export const Dropdown = ({
const { isDropdownOpen, toggleDropdown, closeDropdown, dropdownWidth } =
useDropdown(dropdownId);
- const { handleResetSelectedPosition } = useSelectableList(
- SINGLE_ENTITY_SELECT_BASE_LIST,
- );
const offsetMiddlewares = [];
if (isDefined(dropdownOffset.x)) {
@@ -108,7 +103,6 @@ export const Dropdown = ({
if (isDropdownOpen) {
closeDropdown();
- handleResetSelectedPosition();
}
},
});
@@ -122,10 +116,9 @@ export const Dropdown = ({
[Key.Escape],
() => {
closeDropdown();
- handleResetSelectedPosition();
},
dropdownHotkeyScope.scope,
- [closeDropdown, handleResetSelectedPosition],
+ [closeDropdown],
);
return (
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableItem.tsx b/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableItem.tsx
index c4678f4d2..de7114062 100644
--- a/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableItem.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableItem.tsx
@@ -2,6 +2,12 @@ import { ReactNode, useEffect, useRef } from 'react';
import { useRecoilValue } from 'recoil';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
+import styled from '@emotion/styled';
+
+const StyledContainer = styled.div`
+ height: 100%;
+ width: 100%;
+`;
export type SelectableItemProps = {
itemId: string;
@@ -27,8 +33,8 @@ export const SelectableItem = ({
}, [isSelectedItemId]);
return (
-
+
{children}
-
+
);
};
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableList.ts b/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableList.ts
index 89518de5d..3dadd58d1 100644
--- a/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableList.ts
+++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableList.ts
@@ -1,8 +1,4 @@
-import {
- useRecoilCallback,
- useResetRecoilState,
- useSetRecoilState,
-} from 'recoil';
+import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
@@ -24,16 +20,11 @@ export const useSelectableList = (selectableListId?: string) => {
selectableListOnEnterState,
);
- const resetSelectedItemIdState = useResetRecoilState(selectedItemIdState);
-
- const resetSelectedItem = () => {
- resetSelectedItemIdState();
- };
-
- const handleResetSelectedPosition = useRecoilCallback(
+ const resetSelectedItem = useRecoilCallback(
({ snapshot, set }) =>
() => {
const selectedItemId = getSnapshotValue(snapshot, selectedItemIdState);
+
if (isDefined(selectedItemId)) {
set(selectedItemIdState, null);
set(isSelectedItemIdSelector(selectedItemId), false);
@@ -44,11 +35,9 @@ export const useSelectableList = (selectableListId?: string) => {
return {
selectableListId: scopeId,
-
setSelectableItemIds,
isSelectedItemIdSelector,
setSelectableListOnEnter,
resetSelectedItem,
- handleResetSelectedPosition,
};
};
diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx
index 890322882..85d639138 100644
--- a/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx
+++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/internals/components/StyledMenuItemBase.tsx
@@ -8,12 +8,12 @@ export type MenuItemBaseProps = {
accent?: MenuItemAccent;
isKeySelected?: boolean;
isHoverBackgroundDisabled?: boolean;
+ hovered?: boolean;
};
export const StyledMenuItemBase = styled.div`
--horizontal-padding: ${({ theme }) => theme.spacing(1)};
--vertical-padding: ${({ theme }) => theme.spacing(2)};
-
align-items: center;
border-radius: ${({ theme }) => theme.border.radius.sm};