diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDropdownItem.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDropdownItem.tsx
index 53206e658..1eb31bbea 100644
--- a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDropdownItem.tsx
+++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDropdownItem.tsx
@@ -1,5 +1,10 @@
import { ActionDisplayProps } from '@/action-menu/actions/display/components/ActionDisplay';
import { getActionLabel } from '@/action-menu/utils/getActionLabel';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
+import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
+import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
+import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useNavigate } from 'react-router-dom';
import { isDefined } from 'twenty-shared/utils';
import { MenuItem } from 'twenty-ui/navigation';
@@ -22,12 +27,25 @@ export const ActionDropdownItem = ({
}
};
+ const selectableListInstanceId = useAvailableComponentInstanceIdOrThrow(
+ SelectableListComponentInstanceContext,
+ );
+
+ const isSelected = useRecoilComponentFamilyValueV2(
+ isSelectedItemIdComponentFamilySelector,
+ action.key,
+ selectableListInstanceId,
+ );
+
return (
-
+
+
+
);
};
diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionListItem.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionListItem.tsx
index f617c394c..106a8f9ce 100644
--- a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionListItem.tsx
+++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionListItem.tsx
@@ -1,9 +1,7 @@
import { ActionDisplayProps } from '@/action-menu/actions/display/components/ActionDisplay';
import { getActionLabel } from '@/action-menu/utils/getActionLabel';
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
-import { useSelectableListListenToEnterHotkeyOnItem } from '@/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem';
-import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useNavigate } from 'react-router-dom';
import { isDefined } from 'twenty-shared/utils';
@@ -25,14 +23,8 @@ export const ActionListItem = ({
}
};
- useSelectableListListenToEnterHotkeyOnItem({
- hotkeyScope: AppHotkeyScope.CommandMenuOpen,
- itemId: action.key,
- onEnter: handleClick,
- });
-
return (
-
+
-
+
);
};
diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/__stories__/ActionDisplay.stories.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/__stories__/ActionDisplay.stories.tsx
index 5e47940aa..c71e704bb 100644
--- a/packages/twenty-front/src/modules/action-menu/actions/display/components/__stories__/ActionDisplay.stories.tsx
+++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/__stories__/ActionDisplay.stories.tsx
@@ -114,6 +114,13 @@ export const AsDropdownItem: Story = {
onClick: addToFavoritesMock,
},
decorators: [
+ (Story) => (
+
+
+
+ ),
(Story) => (
= {
title: 'Modules/ActionMenu/Actions/Display/ActionDropdownItem',
component: ActionDropdownItem,
- decorators: [ComponentDecorator, RouterDecorator],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ComponentDecorator,
+ RouterDecorator,
+ ],
};
export default meta;
diff --git a/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx b/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx
index ff1b2cd7f..3592a1d2f 100644
--- a/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx
+++ b/packages/twenty-front/src/modules/action-menu/components/CommandMenuActionMenuDropdown.tsx
@@ -7,6 +7,8 @@ import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-men
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
@@ -41,6 +43,16 @@ export const CommandMenuActionMenuDropdown = () => {
[toggleDropdown],
);
+ const recordSelectionActions = actions.filter(
+ (action) => action.scope === ActionScope.RecordSelection,
+ );
+
+ const selectableItemIdArray = recordSelectionActions.map(
+ (action) => action.key,
+ );
+
+ const { setSelectedItemId } = useSelectableList(actionMenuId);
+
return (
{
}
dropdownPlacement="top-end"
dropdownOffset={{ y: parseInt(theme.spacing(2), 10) }}
+ onOpen={() => {
+ setSelectedItemId(selectableItemIdArray[0]);
+ }}
dropdownComponents={
- {actions
- .filter((action) => action.scope === ActionScope.RecordSelection)
- .map((action) => (
+
+ {recordSelectionActions.map((action) => (
))}
+
}
/>
diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx
index 4f83c112f..6fc83086d 100644
--- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx
+++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx
@@ -9,8 +9,12 @@ import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/get
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
-import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
+import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
import styled from '@emotion/styled';
import { useContext } from 'react';
@@ -42,7 +46,7 @@ export const RecordIndexActionMenuDropdown = () => {
);
const dropdownId = getActionMenuDropdownIdFromActionMenuId(actionMenuId);
- const { closeDropdown } = useDropdown(dropdownId);
+ const { closeDropdown } = useDropdownV2();
const actionMenuDropdownPosition = useRecoilValue(
extractComponentState(
@@ -53,6 +57,16 @@ export const RecordIndexActionMenuDropdown = () => {
const { openCommandMenu } = useCommandMenu();
+ const selectedItemIdArray = [
+ ...recordIndexActions.map((action) => action.key),
+ 'more-actions',
+ ];
+
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ dropdownId,
+ );
+
return (
{
dropdownComponents={
- {recordIndexActions.map((action) => (
-
- ))}
-
}
diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx
index b42156df6..350bc4565 100644
--- a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx
+++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx
@@ -7,7 +7,6 @@ import { useMatchingCommandMenuActions } from '@/command-menu/hooks/useMatchingC
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
@@ -89,9 +88,7 @@ export const CommandMenu = () => {
>
{isDefined(previousContextStoreCurrentObjectMetadataItemId) && (
-
-
-
+
)}
diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx
index 31577da2e..84cdefc83 100644
--- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx
+++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx
@@ -4,8 +4,6 @@ import { ActionGroupConfig } from '@/command-menu/components/CommandMenu';
import { CommandMenuDefaultSelectionEffect } from '@/command-menu/components/CommandMenuDefaultSelectionEffect';
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
-import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
-import { useResetPreviousCommandMenuContext } from '@/command-menu/hooks/useResetPreviousCommandMenuContext';
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
@@ -64,9 +62,6 @@ export const CommandMenuList = ({
loading = false,
noResults = false,
}: CommandMenuListProps) => {
- const { resetPreviousCommandMenuContext } =
- useResetPreviousCommandMenuContext();
-
const setHasUserSelectedCommand = useSetRecoilState(
hasUserSelectedCommandState,
);
@@ -82,12 +77,6 @@ export const CommandMenuList = ({
selectableListInstanceId="command-menu-list"
hotkeyScope={AppHotkeyScope.CommandMenuOpen}
selectableItemIdArray={selectableItemIds}
- onEnter={(itemId) => {
- if (itemId === RESET_CONTEXT_TO_SELECTION) {
- resetPreviousCommandMenuContext();
- return;
- }
- }}
onSelect={() => {
setHasUserSelectedCommand(true);
}}
diff --git a/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx b/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx
index 1912072bd..5b4b557b8 100644
--- a/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx
+++ b/packages/twenty-front/src/modules/command-menu/components/ResetContextToSelectionCommandButton.tsx
@@ -6,6 +6,7 @@ import { useResetPreviousCommandMenuContext } from '@/command-menu/hooks/useRese
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { t } from '@lingui/core/macro';
import { useRecoilValue } from 'recoil';
@@ -42,17 +43,22 @@ export const ResetContextToSelectionCommandButton = () => {
}
return (
-
- }
- onClick={resetPreviousCommandMenuContext}
- />
+
+
+ }
+ onClick={resetPreviousCommandMenuContext}
+ />
+
);
};
diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx
index 5c54c53ae..6c09a5580 100644
--- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx
+++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx
@@ -8,6 +8,18 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMe
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
+import { CommandMenuHotkeyScope } from '@/command-menu/types/CommandMenuHotkeyScope';
+
+const mockGoBackToPreviousHotkeyScope = jest.fn();
+const mockSetHotkeyScopeAndMemorizePreviousScope = jest.fn();
+
+jest.mock('@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope', () => ({
+ usePreviousHotkeyScope: () => ({
+ goBackToPreviousHotkeyScope: mockGoBackToPreviousHotkeyScope,
+ setHotkeyScopeAndMemorizePreviousScope:
+ mockSetHotkeyScopeAndMemorizePreviousScope,
+ }),
+}));
const Wrapper = ({ children }: { children: React.ReactNode }) => (
@@ -47,6 +59,10 @@ const renderHooks = () => {
};
describe('useCommandMenu', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
it('should open and close the command menu', () => {
const { result } = renderHooks();
@@ -55,6 +71,12 @@ describe('useCommandMenu', () => {
});
expect(result.current.isCommandMenuOpened).toBe(true);
+ expect(mockSetHotkeyScopeAndMemorizePreviousScope).toHaveBeenCalledWith(
+ CommandMenuHotkeyScope.CommandMenuFocused,
+ {
+ commandMenuOpen: true,
+ },
+ );
act(() => {
result.current.commandMenu.closeCommandMenu();
@@ -73,6 +95,12 @@ describe('useCommandMenu', () => {
});
expect(result.current.isCommandMenuOpened).toBe(true);
+ expect(mockSetHotkeyScopeAndMemorizePreviousScope).toHaveBeenCalledWith(
+ CommandMenuHotkeyScope.CommandMenuFocused,
+ {
+ commandMenuOpen: true,
+ },
+ );
act(() => {
result.current.commandMenu.toggleCommandMenu();
@@ -80,4 +108,21 @@ describe('useCommandMenu', () => {
expect(result.current.isCommandMenuOpened).toBe(false);
});
+
+ it('should call goBackToPreviousHotkeyScope when closing the command menu', () => {
+ const { result } = renderHooks();
+
+ act(() => {
+ result.current.commandMenu.openCommandMenu();
+ });
+
+ expect(result.current.isCommandMenuOpened).toBe(true);
+ expect(mockGoBackToPreviousHotkeyScope).not.toHaveBeenCalled();
+
+ act(() => {
+ result.current.commandMenu.closeCommandMenu();
+ });
+
+ expect(mockGoBackToPreviousHotkeyScope).toHaveBeenCalledTimes(1);
+ });
});
diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx
index cc7165222..d8a5993f6 100644
--- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx
+++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenuCloseAnimationCompleteCleanup.test.tsx
@@ -23,7 +23,6 @@ import { IconList } from 'twenty-ui/display';
const mockCloseDropdown = jest.fn();
const mockResetContextStoreStates = jest.fn();
const mockResetSelectedItem = jest.fn();
-const mockGoBackToPreviousHotkeyScope = jest.fn();
const mockEmitRightDrawerCloseEvent = jest.fn();
jest.mock('@/ui/layout/dropdown/hooks/useDropdownV2', () => ({
@@ -44,12 +43,6 @@ jest.mock('@/ui/layout/selectable-list/hooks/useSelectableList', () => ({
}),
}));
-jest.mock('@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope', () => ({
- usePreviousHotkeyScope: () => ({
- goBackToPreviousHotkeyScope: mockGoBackToPreviousHotkeyScope,
- }),
-}));
-
jest.mock('@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent', () => ({
emitRightDrawerCloseEvent: () => {
mockEmitRightDrawerCloseEvent();
@@ -231,7 +224,6 @@ describe('useCommandMenuCloseAnimationCompleteCleanup', () => {
expect(mockCloseDropdown).toHaveBeenCalledTimes(1);
expect(mockResetContextStoreStates).toHaveBeenCalledTimes(2);
expect(mockResetSelectedItem).toHaveBeenCalledTimes(1);
- expect(mockGoBackToPreviousHotkeyScope).toHaveBeenCalledTimes(1);
expect(mockEmitRightDrawerCloseEvent).toHaveBeenCalledTimes(1);
expect(mockCloseDropdown).toHaveBeenCalledWith(
diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts
index 70d926f60..fd5e57453 100644
--- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts
+++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts
@@ -2,11 +2,13 @@ import { useRecoilCallback } from 'recoil';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
+import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown';
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
+import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useCallback } from 'react';
import { IconDotsVertical } from 'twenty-ui/display';
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
@@ -14,16 +16,26 @@ import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
export const useCommandMenu = () => {
const { navigateCommandMenu } = useNavigateCommandMenu();
const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown();
+ const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope(
+ COMMAND_MENU_COMPONENT_INSTANCE_ID,
+ );
const closeCommandMenu = useRecoilCallback(
- ({ set }) =>
+ ({ set, snapshot }) =>
() => {
- set(isCommandMenuOpenedState, false);
- set(isCommandMenuClosingState, true);
- set(isDragSelectionStartEnabledState, true);
- closeAnyOpenDropdown();
+ const isCommandMenuOpened = snapshot
+ .getLoadable(isCommandMenuOpenedState)
+ .getValue();
+
+ if (isCommandMenuOpened) {
+ set(isCommandMenuOpenedState, false);
+ set(isCommandMenuClosingState, true);
+ set(isDragSelectionStartEnabledState, true);
+ closeAnyOpenDropdown();
+ goBackToPreviousHotkeyScope();
+ }
},
- [closeAnyOpenDropdown],
+ [closeAnyOpenDropdown, goBackToPreviousHotkeyScope],
);
const openCommandMenu = useCallback(() => {
diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts
index f46d77cfe..11f5927ab 100644
--- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts
+++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup.ts
@@ -18,7 +18,6 @@ import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRi
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
-import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowServerlessFunctionTabListComponentId';
import { WorkflowServerlessFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowServerlessFunctionTabId';
import { useRecoilCallback } from 'recoil';
@@ -26,10 +25,6 @@ import { useRecoilCallback } from 'recoil';
export const useCommandMenuCloseAnimationCompleteCleanup = () => {
const { resetSelectedItem } = useSelectableList('command-menu-list');
- const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope(
- COMMAND_MENU_COMPONENT_INSTANCE_ID,
- );
-
const { resetContextStoreStates } = useResetContextStoreStates();
const { closeDropdown } = useDropdownV2();
@@ -56,7 +51,6 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
set(commandMenuNavigationStackState, []);
resetSelectedItem();
set(hasUserSelectedCommandState, false);
- goBackToPreviousHotkeyScope();
emitRightDrawerCloseEvent();
set(isCommandMenuClosingState, false);
@@ -81,12 +75,7 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
);
}
},
- [
- closeDropdown,
- goBackToPreviousHotkeyScope,
- resetContextStoreStates,
- resetSelectedItem,
- ],
+ [closeDropdown, resetContextStoreStates, resetSelectedItem],
);
return {
diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx
index 8f3e4e095..e194f5b29 100644
--- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx
+++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx
@@ -1,17 +1,14 @@
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
-import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
-
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
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 { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
-import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
@@ -22,7 +19,6 @@ import { ObjectFilterDropdownFilterSelectMenuItemV2 } from '@/object-record/obje
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
-import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
@@ -37,8 +33,10 @@ export const AdvancedFilterFieldSelectMenu = ({
}: AdvancedFilterFieldSelectMenuProps) => {
const { recordIndexId } = useRecordIndexContextOrThrow();
- const { closeAdvancedFilterFieldSelectDropdown } =
- useAdvancedFilterFieldSelectDropdown(recordFilterId);
+ const {
+ closeAdvancedFilterFieldSelectDropdown,
+ advancedFilterFieldSelectDropdownId,
+ } = useAdvancedFilterFieldSelectDropdown(recordFilterId);
const [objectFilterDropdownSearchInput] = useRecoilComponentStateV2(
objectFilterDropdownSearchInputComponentState,
@@ -76,12 +74,10 @@ export const AdvancedFilterFieldSelectMenu = ({
(fieldMetadataItem) => !visibleColumnsIds.includes(fieldMetadataItem.id),
);
- const selectableFieldMetadataItemIds = filterableFieldMetadataItems.map(
- (fieldMetadataItem) => fieldMetadataItem.id,
+ const { resetSelectedItem } = useSelectableList(
+ advancedFilterFieldSelectDropdownId,
);
- const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
-
const { selectFieldUsedInAdvancedFilterDropdown } =
useSelectFieldUsedInAdvancedFilterDropdown();
@@ -98,18 +94,6 @@ export const AdvancedFilterFieldSelectMenu = ({
fieldMetadataItemIdUsedInDropdownComponentState,
);
- const handleEnter = (fieldMetadataItemId: string) => {
- const selectedFieldMetadataItem = filterableFieldMetadataItems.find(
- (fieldMetadataItem) => fieldMetadataItem.id === fieldMetadataItemId,
- );
-
- if (!isDefined(selectedFieldMetadataItem)) {
- return;
- }
-
- handleFieldMetadataItemSelect(selectedFieldMetadataItem);
- };
-
const handleFieldMetadataItemSelect = (
selectedFieldMetadataItem: FieldMetadataItem,
) => {
@@ -138,41 +122,55 @@ export const AdvancedFilterFieldSelectMenu = ({
visibleColumnsFieldMetadataItems.length > 0 &&
hiddenColumnsFieldMetadataItems.length > 0;
+ const selectableItemIdArray = [
+ ...visibleColumnsFieldMetadataItems.map(
+ (fieldMetadataItem) => fieldMetadataItem.id,
+ ),
+ ...hiddenColumnsFieldMetadataItems.map(
+ (fieldMetadataItem) => fieldMetadataItem.id,
+ ),
+ ];
+
return (
<>
{visibleColumnsFieldMetadataItems.map(
(visibleFieldMetadataItem, index) => (
- {
+ handleFieldMetadataItemSelect(visibleFieldMetadataItem);
+ }}
>
-
+
),
)}
{shouldShowSeparator && }
{hiddenColumnsFieldMetadataItems.map(
(hiddenFieldMetadataItem, index) => (
- {
+ handleFieldMetadataItemSelect(hiddenFieldMetadataItem);
+ }}
>
-
+
),
)}
diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx
index 97bfeb526..f26e9654f 100644
--- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx
+++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx
@@ -11,6 +11,9 @@ import { SelectControl } from '@/ui/input/components/SelectControl';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import styled from '@emotion/styled';
@@ -85,6 +88,11 @@ export const AdvancedFilterRecordFilterOperandSelect = ({
})
: [];
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ dropdownId,
+ );
+
if (isDisabled === true) {
return (
- {operandsForFilterType.map((filterOperand, index) => (
- {
- handleOperandChange(filterOperand);
- }}
- text={getOperandLabel(filterOperand)}
- />
- ))}
+ operand,
+ )}
+ selectableListInstanceId={dropdownId}
+ >
+ {operandsForFilterType.map((filterOperand, index) => (
+ {
+ handleOperandChange(filterOperand);
+ }}
+ >
+ {
+ handleOperandChange(filterOperand);
+ }}
+ text={getOperandLabel(filterOperand)}
+ />
+
+ ))}
+
}
dropdownHotkeyScope={{ scope: dropdownId }}
diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
index c6a7161ff..13cb22dfd 100644
--- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
+++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
@@ -15,6 +15,9 @@ import { isCompositeFieldTypeSubFieldsFilterable } from '@/object-record/record-
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { IconApps, IconChevronLeft, useIcons } from 'twenty-ui/display';
import { MenuItem } from 'twenty-ui/navigation';
@@ -72,6 +75,14 @@ export const AdvancedFilterSubFieldSelectMenu = ({
setObjectFilterDropdownIsSelectingCompositeField(false);
};
+ const { advancedFilterFieldSelectDropdownId } =
+ useAdvancedFilterFieldSelectDropdown(recordFilterId);
+
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ advancedFilterFieldSelectDropdownId,
+ );
+
if (!isDefined(objectFilterDropdownSubMenuFieldType)) {
return null;
}
@@ -86,6 +97,11 @@ export const AdvancedFilterSubFieldSelectMenu = ({
fieldMetadataItemUsedInDropdown.type,
);
+ const selectableItemIdArray = [
+ '-1',
+ ...options.map((subFieldName) => subFieldName),
+ ];
+
return (
<>
- {
- handleSelectFilter(fieldMetadataItemUsedInDropdown);
- }}
- LeftIcon={IconApps}
- text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`}
- />
- {subFieldsAreFilterable &&
- options.map((subFieldName, index) => (
+
+ {
+ handleSelectFilter(fieldMetadataItemUsedInDropdown);
+ }}
+ >
{
- if (isDefined(fieldMetadataItemUsedInDropdown)) {
+ handleSelectFilter(fieldMetadataItemUsedInDropdown);
+ }}
+ LeftIcon={IconApps}
+ text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`}
+ />
+
+ {subFieldsAreFilterable &&
+ options.map((subFieldName, index) => (
+ {
handleSelectFilter(
fieldMetadataItemUsedInDropdown,
subFieldName,
);
- }
- }}
- text={getCompositeSubFieldLabel(
- objectFilterDropdownSubMenuFieldType,
- subFieldName,
- )}
- LeftIcon={getIcon(fieldMetadataItemUsedInDropdown?.icon)}
- />
- ))}
+ }}
+ >
+ {
+ handleSelectFilter(
+ fieldMetadataItemUsedInDropdown,
+ subFieldName,
+ );
+ }}
+ text={getCompositeSubFieldLabel(
+ objectFilterDropdownSubMenuFieldType,
+ subFieldName,
+ )}
+ LeftIcon={getIcon(fieldMetadataItemUsedInDropdown?.icon)}
+ />
+
+ ))}
+
>
);
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx
index 6fb77ac0b..f17f0a66e 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect.tsx
@@ -94,9 +94,6 @@ export const ObjectFilterDropdownBooleanSelect = () => {
selectableListInstanceId="boolean-select"
selectableItemIdArray={options.map((option) => option.toString())}
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
- onEnter={(itemId) => {
- handleOptionSelect(itemId === 'true');
- }}
>
{options.map((option) => (
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 34d630beb..0e3963eb2 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
@@ -11,14 +11,9 @@ import { objectFilterDropdownSearchInputComponentState } from '@/object-record/o
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
-import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
-import { useSelectFilterUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterUsedInDropdown';
-import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
@@ -96,36 +91,6 @@ export const ObjectFilterDropdownFilterSelect = ({
(fieldMetadataItem) => !visibleColumnsIds.includes(fieldMetadataItem.id),
);
- const selectableFieldMetadataItemIds = filterableFieldMetadataItems.map(
- (fieldMetadataItem) => fieldMetadataItem.id,
- );
-
- const { selectFilterUsedInDropdown } = useSelectFilterUsedInDropdown();
-
- const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
- fieldMetadataItemIdUsedInDropdownComponentState,
- );
-
- const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
-
- const handleEnter = (fieldMetadataItemId: string) => {
- const selectedFieldMetadataItem = filterableFieldMetadataItems.find(
- (fieldMetadataItem) => fieldMetadataItem.id === fieldMetadataItemId,
- );
-
- if (!isDefined(selectedFieldMetadataItem)) {
- return;
- }
-
- resetSelectedItem();
-
- selectFilterUsedInDropdown({
- fieldMetadataItemId,
- });
-
- setFieldMetadataItemIdUsedInDropdown(fieldMetadataItemId);
- };
-
const shouldShowSeparator =
visibleColumnsFieldMetadataItems.length > 0 &&
hiddenColumnsFieldMetadataItems.length > 0;
@@ -137,6 +102,15 @@ export const ObjectFilterDropdownFilterSelect = ({
const { t } = useLingui();
+ const selectableFieldMetadataItemIds = [
+ ...visibleColumnsFieldMetadataItems.map(
+ (fieldMetadataItem) => fieldMetadataItem.id,
+ ),
+ ...hiddenColumnsFieldMetadataItems.map(
+ (fieldMetadataItem) => fieldMetadataItem.id,
+ ),
+ ];
+
return (
<>
- {visibleColumnsFieldMetadataItems.map(
- (visibleFieldMetadataItem, index) => (
-
-
-
- ),
- )}
+ {visibleColumnsFieldMetadataItems.map((visibleFieldMetadataItem) => (
+
+ ))}
{shouldShowSeparator && }
- {hiddenColumnsFieldMetadataItems.map(
- (hiddenFieldMetadataItem, index) => (
-
-
-
- ),
- )}
+ {hiddenColumnsFieldMetadataItems.map((hiddenFieldMetadataItem) => (
+
+ ))}
{shouldShowAdvancedFilterButton && }
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx
index 14e5e27c4..855586469 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx
@@ -1,5 +1,6 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
+import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
@@ -9,6 +10,7 @@ import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-rec
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
+import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
@@ -19,6 +21,9 @@ import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/con
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
@@ -130,6 +135,10 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
setObjectFilterDropdownFilterIsSelected(false);
setSubFieldNameUsedInDropdown(null);
};
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ OBJECT_FILTER_DROPDOWN_ID,
+ );
if (!isDefined(objectFilterDropdownSubMenuFieldType)) {
return null;
@@ -170,35 +179,65 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
}
/> */}
- {
- handleSelectFilter(fieldMetadataItemUsedInDropdown);
- }}
- LeftIcon={IconApps}
- text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`}
- />
- {subFieldsAreFilterable &&
- options.map((subFieldName, index) => (
+
+ {
+ handleSelectFilter(fieldMetadataItemUsedInDropdown);
+ }}
+ >
{
- if (isDefined(fieldMetadataItemUsedInDropdown)) {
+ handleSelectFilter(fieldMetadataItemUsedInDropdown);
+ }}
+ LeftIcon={IconApps}
+ text={`Any ${getFilterableFieldTypeLabel(
+ objectFilterDropdownSubMenuFieldType,
+ )} field`}
+ />
+
+
+ {subFieldsAreFilterable &&
+ options.map((subFieldName, index) => (
+ {
handleSelectFilter(
fieldMetadataItemUsedInDropdown,
subFieldName,
);
- }
- }}
- text={getCompositeSubFieldLabel(
- objectFilterDropdownSubMenuFieldType,
- subFieldName,
- )}
- LeftIcon={getIcon(fieldMetadataItemUsedInDropdown?.icon)}
- />
- ))}
+ }}
+ >
+ {
+ if (isDefined(fieldMetadataItemUsedInDropdown)) {
+ handleSelectFilter(
+ fieldMetadataItemUsedInDropdown,
+ subFieldName,
+ );
+ }
+ }}
+ text={getCompositeSubFieldLabel(
+ objectFilterDropdownSubMenuFieldType,
+ subFieldName,
+ )}
+ LeftIcon={getIcon(fieldMetadataItemUsedInDropdown?.icon)}
+ />
+
+ ))}
+
>
);
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
index ad6a6142e..be665e28f 100644
--- 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
@@ -14,6 +14,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
@@ -23,7 +24,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
-import { MenuItemSelect } from 'twenty-ui/navigation';
+import { MenuItem } from 'twenty-ui/navigation';
export type ObjectFilterDropdownFilterSelectMenuItemProps = {
fieldMetadataItemToSelect: FieldMetadataItem;
@@ -132,13 +133,17 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
};
return (
-
+
+
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItemV2.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItemV2.tsx
index 267725671..bd7b4e59e 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItemV2.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItemV2.tsx
@@ -6,7 +6,7 @@ import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectab
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useIcons } from 'twenty-ui/display';
-import { MenuItemSelect } from 'twenty-ui/navigation';
+import { MenuItem } from 'twenty-ui/navigation';
export type ObjectFilterDropdownFilterSelectMenuItemV2Props = {
fieldMetadataItemToSelect: FieldMetadataItem;
@@ -37,9 +37,8 @@ export const ObjectFilterDropdownFilterSelectMenuItemV2 = ({
};
return (
- {
selectableListInstanceId={componentInstanceId}
selectableItemIdArray={objectRecordsIds}
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
- onEnter={(itemId) => {
- const option = optionsInDropdown.find((option) => option.id === itemId);
- if (isDefined(option)) {
- handleMultipleOptionSelectChange(option, !option.isSelected);
- }
- }}
>
{optionsInDropdown?.map((option) => (
diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx
index f00ae7e47..e53339e53 100644
--- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutContent.tsx
@@ -1,13 +1,18 @@
+import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
import { useSetViewTypeFromLayoutOptionsMenu } from '@/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu';
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
+import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
@@ -74,6 +79,18 @@ export const ObjectOptionsDropdownLayoutContent = () => {
const isDefaultView = currentView?.key === 'INDEX';
const nbsp = '\u00A0';
+ const selectableItemIdArray = [
+ ViewType.Table,
+ ...(isDefaultView ? [] : [ViewType.Kanban]),
+ ViewOpenRecordInType.SIDE_PANEL,
+ ...(currentView?.type === ViewType.Kanban ? ['Group', 'Compact view'] : []),
+ ];
+
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ OBJECT_OPTIONS_DROPDOWN_ID,
+ );
+
return (
<>
{
>
{t`Layout`}
+
{!!currentView && (
- {
- if (currentView?.type !== ViewType.Table) {
- await setAndPersistViewType(ViewType.Table);
- }
- }}
- />
-
- {nbsp}·{nbsp}
-
- >
- ) : availableFieldsForKanban.length === 0 ? (
- t`Create Select...`
- ) : undefined
- }
- selected={currentView?.type === ViewType.Kanban}
- onClick={handleSelectKanbanViewType}
- />
-
- onContentChange('layoutOpenIn')}
- LeftIcon={
- recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL
- ? IconLayoutSidebarRight
- : IconLayoutNavbar
- }
- text={t`Open in`}
- contextualText={
- recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL
- ? t`Side Panel`
- : t`Record Page`
- }
- hasSubMenu
- />
- {currentView?.type === ViewType.Kanban && (
- <>
-
- isDefined(recordGroupFieldMetadata)
- ? onContentChange('recordGroups')
- : onContentChange('recordGroupFields')
+
+ {
+ setAndPersistViewType(ViewType.Table);
+ }}
+ >
+ {
+ if (currentView?.type !== ViewType.Table) {
+ await setAndPersistViewType(ViewType.Table);
+ }
+ }}
+ />
+
+ {
+ setAndPersistViewType(ViewType.Kanban);
+ }}
+ >
+
+ {nbsp}·{nbsp}
+
+ >
+ ) : availableFieldsForKanban.length === 0 ? (
+ t`Create Select...`
+ ) : undefined
+ }
+ selected={currentView?.type === ViewType.Kanban}
+ onClick={handleSelectKanbanViewType}
+ />
+
+
+ {
+ onContentChange('layoutOpenIn');
+ }}
+ >
+
+
+ {currentView?.type === ViewType.Kanban && (
+ <>
+ {
+ isDefined(recordGroupFieldMetadata)
+ ? onContentChange('recordGroups')
+ : onContentChange('recordGroupFields');
+ }}
+ >
+
+ isDefined(recordGroupFieldMetadata)
+ ? onContentChange('recordGroups')
+ : onContentChange('recordGroupFields')
+ }
+ LeftIcon={IconLayoutList}
+ text={t`Group`}
+ contextualText={recordGroupFieldMetadata?.label}
+ hasSubMenu
+ />
+
-
- setAndPersistIsCompactModeActive(
- !isCompactModeActive,
- currentView,
- )
- }
- toggled={isCompactModeActive}
- text={t`Compact view`}
- toggleSize="small"
- />
- >
- )}
+ {
+ setAndPersistIsCompactModeActive(
+ !isCompactModeActive,
+ currentView,
+ );
+ }}
+ >
+
+ setAndPersistIsCompactModeActive(
+ !isCompactModeActive,
+ currentView,
+ )
+ }
+ toggled={isCompactModeActive}
+ text={t`Compact view`}
+ toggleSize="small"
+ />
+
+ >
+ )}
+
)}
>
diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx
index d7cabe7d7..cefa938bb 100644
--- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownLayoutOpenInContent.tsx
@@ -1,9 +1,15 @@
+import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
import { useUpdateObjectViewOptions } from '@/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions';
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
+import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
import { t } from '@lingui/core/macro';
@@ -21,6 +27,16 @@ export const ObjectOptionsDropdownLayoutOpenInContent = () => {
const { currentView } = useGetCurrentViewOnly();
const { setAndPersistOpenRecordIn } = useUpdateObjectViewOptions();
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ OBJECT_OPTIONS_DROPDOWN_ID,
+ );
+
+ const selectableItemIdArray = [
+ ViewOpenRecordInType.SIDE_PANEL,
+ ViewOpenRecordInType.RECORD_PAGE,
+ ];
+
return (
<>
{
{t`Open in`}
-
- setAndPersistOpenRecordIn(
- ViewOpenRecordInType.SIDE_PANEL,
- currentView,
- )
- }
- />
-
- setAndPersistOpenRecordIn(
- ViewOpenRecordInType.RECORD_PAGE,
- currentView,
- )
- }
- />
+
+
+ setAndPersistOpenRecordIn(
+ ViewOpenRecordInType.SIDE_PANEL,
+ currentView,
+ )
+ }
+ >
+
+ setAndPersistOpenRecordIn(
+ ViewOpenRecordInType.SIDE_PANEL,
+ currentView,
+ )
+ }
+ />
+
+
+ setAndPersistOpenRecordIn(
+ ViewOpenRecordInType.RECORD_PAGE,
+ currentView,
+ )
+ }
+ >
+
+ setAndPersistOpenRecordIn(
+ ViewOpenRecordInType.RECORD_PAGE,
+ currentView,
+ )
+ }
+ focused={selectedItemId === ViewOpenRecordInType.RECORD_PAGE}
+ />
+
+
>
);
diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx
index 7caa6457c..2857d1fc5 100644
--- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx
@@ -1,6 +1,7 @@
import { Key } from 'ts-key-enum';
import { ObjectOptionsDropdownMenuViewName } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName';
+import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
@@ -9,6 +10,9 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
@@ -75,92 +79,155 @@ export const ObjectOptionsDropdownMenuContent = () => {
const isDefaultView = currentView?.key === 'INDEX';
+ const selectableItemIdArray = [
+ 'Layout',
+ 'Fields',
+ ...(isDefaultView ? [] : ['Group']),
+ 'Copy link to view',
+ ...(isDefaultView ? [] : ['Delete view']),
+ ];
+
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ OBJECT_OPTIONS_DROPDOWN_ID,
+ );
+
return (
<>
{currentView && (
)}
-
- onContentChange('layout')}
- LeftIcon={viewTypeIconMapping(currentView?.type ?? ViewType.Table)}
- text={t`Layout`}
- contextualText={`${capitalize(currentView?.type ?? '')}`}
- hasSubMenu
- />
-
-
-
-
- onContentChange('fields')}
- LeftIcon={IconListDetails}
- text={t`Fields`}
- contextualText={`${visibleBoardFields.length} shown`}
- hasSubMenu
- />
-
-
- {!isGroupByEnabled && (
-
- )}
+
+
+ onContentChange('layout')}
+ >
+ onContentChange('layout')}
+ LeftIcon={viewTypeIconMapping(
+ currentView?.type ?? ViewType.Table,
+ )}
+ text={t`Layout`}
+ contextualText={`${capitalize(currentView?.type ?? '')}`}
+ hasSubMenu
+ />
+
+
- {
- const currentUrl = window.location.href;
- navigator.clipboard.writeText(currentUrl);
- enqueueSnackBar('Link copied to clipboard', {
- variant: SnackBarVariant.Success,
- icon: ,
- duration: 2000,
- });
- }}
- LeftIcon={IconCopy}
- text={t`Copy link to view`}
- />
-
- {currentView?.key === 'INDEX' && (
-
- )}
-
+
+ onContentChange('fields')}
+ >
+ onContentChange('fields')}
+ LeftIcon={IconListDetails}
+ text={t`Fields`}
+ contextualText={`${visibleBoardFields.length} shown`}
+ hasSubMenu
+ />
+
+
+
+ {!isGroupByEnabled && (
+
+ )}
+
+
+ {
+ const currentUrl = window.location.href;
+ navigator.clipboard.writeText(currentUrl);
+ enqueueSnackBar('Link copied to clipboard', {
+ variant: SnackBarVariant.Success,
+ icon: ,
+ duration: 2000,
+ });
+ }}
+ >
+ {
+ const currentUrl = window.location.href;
+ navigator.clipboard.writeText(currentUrl);
+ enqueueSnackBar('Link copied to clipboard', {
+ variant: SnackBarVariant.Success,
+ icon: ,
+ duration: 2000,
+ });
+ }}
+ LeftIcon={IconCopy}
+ text={t`Copy link to view`}
+ />
+
+
+ {currentView?.key === 'INDEX' && (
+
+ )}
+
+
>
);
};
diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx
index 30120a903..e0f7468a4 100644
--- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent.tsx
@@ -1,14 +1,19 @@
import { useEffect } from 'react';
+import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort';
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
+import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
+import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
-import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import {
IconChevronLeft,
IconHandMove,
@@ -32,6 +37,11 @@ export const ObjectOptionsDropdownRecordGroupSortContent = () => {
setRecordGroupSort(sort);
};
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ OBJECT_OPTIONS_DROPDOWN_ID,
+ );
+
useEffect(() => {
if (
currentContentId === 'hiddenRecordGroups' &&
@@ -41,6 +51,12 @@ export const ObjectOptionsDropdownRecordGroupSortContent = () => {
}
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
+ const selectableItemIdArray = [
+ RecordGroupSort.Manual,
+ RecordGroupSort.Alphabetical,
+ RecordGroupSort.ReverseAlphabetical,
+ ];
+
return (
<>
{
Sort
- handleRecordGroupSortChange(RecordGroupSort.Manual)}
- LeftIcon={IconHandMove}
- text={RecordGroupSort.Manual}
- selected={recordGroupSort === RecordGroupSort.Manual}
- />
-
- handleRecordGroupSortChange(RecordGroupSort.Alphabetical)
- }
- LeftIcon={IconSortAZ}
- text={RecordGroupSort.Alphabetical}
- selected={recordGroupSort === RecordGroupSort.Alphabetical}
- />
-
- handleRecordGroupSortChange(RecordGroupSort.ReverseAlphabetical)
- }
- LeftIcon={IconSortZA}
- text={RecordGroupSort.ReverseAlphabetical}
- selected={recordGroupSort === RecordGroupSort.ReverseAlphabetical}
- />
+
+ handleRecordGroupSortChange(RecordGroupSort.Manual)}
+ >
+
+ handleRecordGroupSortChange(RecordGroupSort.Manual)
+ }
+ LeftIcon={IconHandMove}
+ text={RecordGroupSort.Manual}
+ selected={recordGroupSort === RecordGroupSort.Manual}
+ focused={selectedItemId === RecordGroupSort.Manual}
+ />
+
+
+ handleRecordGroupSortChange(RecordGroupSort.Alphabetical)
+ }
+ >
+
+ handleRecordGroupSortChange(RecordGroupSort.Alphabetical)
+ }
+ LeftIcon={IconSortAZ}
+ text={RecordGroupSort.Alphabetical}
+ selected={recordGroupSort === RecordGroupSort.Alphabetical}
+ focused={selectedItemId === RecordGroupSort.Alphabetical}
+ />
+
+
+ handleRecordGroupSortChange(RecordGroupSort.ReverseAlphabetical)
+ }
+ >
+
+ handleRecordGroupSortChange(RecordGroupSort.ReverseAlphabetical)
+ }
+ LeftIcon={IconSortZA}
+ text={RecordGroupSort.ReverseAlphabetical}
+ selected={recordGroupSort === RecordGroupSort.ReverseAlphabetical}
+ focused={selectedItemId === RecordGroupSort.ReverseAlphabetical}
+ />
+
+
>
);
diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx
index e68e87892..d9d78a1a4 100644
--- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx
@@ -1,5 +1,6 @@
import { useEffect } from 'react';
+import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
import { RecordGroupReorderConfirmationModal } from '@/object-record/record-group/components/RecordGroupReorderConfirmationModal';
import { RecordGroupsVisibilityDropdownSection } from '@/object-record/record-group/components/RecordGroupsVisibilityDropdownSection';
@@ -10,10 +11,14 @@ import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-gr
import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector';
import { recordIndexRecordGroupHideComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentFamilyState';
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
+import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
+import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
@@ -89,6 +94,17 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
}
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ OBJECT_OPTIONS_DROPDOWN_ID,
+ );
+
+ const selectableItemIdArray = [
+ ...(currentView?.key !== 'INDEX' ? ['GroupBy', 'Sort'] : []),
+ 'HideEmptyGroups',
+ ...(hiddenRecordGroupIds.length > 0 ? ['HiddenGroups'] : []),
+ ];
+
return (
<>
{
Group
- {currentView?.key !== 'INDEX' && (
- <>
- onContentChange('recordGroupFields')}
- LeftIcon={IconLayoutList}
- text={t`Group by`}
- contextualText={recordGroupFieldMetadata?.label}
- hasSubMenu
+
+ {currentView?.key !== 'INDEX' && (
+ <>
+ onContentChange('recordGroupFields')}
+ >
+ onContentChange('recordGroupFields')}
+ LeftIcon={IconLayoutList}
+ text={t`Group by`}
+ contextualText={recordGroupFieldMetadata?.label}
+ hasSubMenu
+ />
+
+ onContentChange('recordGroupSort')}
+ >
+ onContentChange('recordGroupSort')}
+ LeftIcon={IconSortDescending}
+ text={t`Sort`}
+ contextualText={recordGroupSort}
+ hasSubMenu
+ />
+
+ >
+ )}
+ handleHideEmptyRecordGroupChange()}
+ >
+
- onContentChange('recordGroupSort')}
- LeftIcon={IconSortDescending}
- text={t`Sort`}
- contextualText={recordGroupSort}
- hasSubMenu
- />
- >
- )}
-
+
+
{visibleRecordGroupIds.length > 0 && (
<>
@@ -145,11 +185,16 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
<>
- onContentChange('hiddenRecordGroups')}
- LeftIcon={IconEyeOff}
- text={`Hidden ${recordGroupFieldMetadata?.label ?? ''}`}
- />
+ onContentChange('hiddenRecordGroups')}
+ >
+ onContentChange('hiddenRecordGroups')}
+ LeftIcon={IconEyeOff}
+ text={`Hidden ${recordGroupFieldMetadata?.label ?? ''}`}
+ />
+
>
)}
diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
index c70bde46b..59b1c4bf0 100644
--- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
@@ -24,16 +24,19 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
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 { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
+import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
+import { useTheme } from '@emotion/react';
import { Trans, useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
-import { v4 } from 'uuid';
-import { useTheme } from '@emotion/react';
import { IconChevronDown, useIcons } from 'twenty-ui/display';
import { MenuItem } from 'twenty-ui/navigation';
+import { v4 } from 'uuid';
export const StyledInput = styled.input`
background: transparent;
@@ -191,6 +194,21 @@ export const ObjectSortDropdownButton = ({
const theme = useTheme();
+ const selectableItemIdArray = [
+ ...visibleFieldMetadataItems.map((item) => item.id),
+ ...hiddenFieldMetadataItems.map((item) => item.id),
+ ];
+
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ OBJECT_SORT_DROPDOWN_ID,
+ );
+
+ const setSelectedItemId = useSetRecoilComponentStateV2(
+ selectedItemIdComponentState,
+ OBJECT_SORT_DROPDOWN_ID,
+ );
+
return (
{
+ handleButtonClick();
+ setSelectedItemId(selectableItemIdArray[0]);
+ }}
isUnfolded={isDropdownOpen}
>
Sort
}
dropdownComponents={
- <>
+
{isRecordSortDirectionMenuUnfolded && (
{RECORD_SORT_DIRECTIONS.map((sortDirection, index) => (
handleSortDirectionClick(sortDirection)}
text={
sortDirection === 'asc' ? t`Ascending` : t`Descending`
@@ -244,27 +270,39 @@ export const ObjectSortDropdownButton = ({
{visibleFieldMetadataItems.map(
(visibleFieldMetadataItem, index) => (
- handleAddSort(visibleFieldMetadataItem)}
- LeftIcon={getIcon(visibleFieldMetadataItem.icon)}
- text={visibleFieldMetadataItem.label}
- />
+ handleAddSort(visibleFieldMetadataItem)}
+ >
+ handleAddSort(visibleFieldMetadataItem)}
+ LeftIcon={getIcon(visibleFieldMetadataItem.icon)}
+ text={visibleFieldMetadataItem.label}
+ />
+
),
)}
{shouldShowSeparator && }
{hiddenFieldMetadataItems.map((hiddenFieldMetadataItem, index) => (
- handleAddSort(hiddenFieldMetadataItem)}
- LeftIcon={getIcon(hiddenFieldMetadataItem.icon)}
- text={hiddenFieldMetadataItem.label}
- />
+ handleAddSort(hiddenFieldMetadataItem)}
+ >
+ handleAddSort(hiddenFieldMetadataItem)}
+ LeftIcon={getIcon(hiddenFieldMetadataItem.icon)}
+ text={hiddenFieldMetadataItem.label}
+ />
+
))}
- >
+
}
onClose={handleDropdownButtonClose}
/>
diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts
index 975b79e72..fc7a42347 100644
--- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts
+++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useRecordBoardSelection.ts
@@ -4,9 +4,8 @@ import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/get
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
-import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
+import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
-import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
export const useRecordBoardSelection = (recordBoardId: string) => {
@@ -22,17 +21,16 @@ export const useRecordBoardSelection = (recordBoardId: string) => {
recordBoardId,
);
- const isActionMenuDropdownOpenState = extractComponentState(
- isDropdownOpenComponentState,
- getActionMenuDropdownIdFromActionMenuId(
- getActionMenuIdFromRecordIndexId(recordBoardId),
- ),
+ const { closeDropdown } = useDropdownV2();
+
+ const dropdownId = getActionMenuDropdownIdFromActionMenuId(
+ getActionMenuIdFromRecordIndexId(recordBoardId),
);
const resetRecordSelection = useRecoilCallback(
({ snapshot, set }) =>
() => {
- set(isActionMenuDropdownOpenState, false);
+ closeDropdown(dropdownId);
const recordIds = getSnapshotValue(
snapshot,
@@ -44,7 +42,8 @@ export const useRecordBoardSelection = (recordBoardId: string) => {
}
},
[
- isActionMenuDropdownOpenState,
+ closeDropdown,
+ dropdownId,
recordBoardSelectedRecordIdsSelector,
isRecordBoardCardSelectedFamilyState,
],
@@ -67,17 +66,17 @@ export const useRecordBoardSelection = (recordBoardId: string) => {
);
const checkIfLastUnselectAndCloseDropdown = useRecoilCallback(
- ({ snapshot, set }) =>
+ ({ snapshot }) =>
() => {
const recordIds = getSnapshotValue(
snapshot,
recordBoardSelectedRecordIdsSelector,
);
if (recordIds.length === 0) {
- set(isActionMenuDropdownOpenState, false);
+ closeDropdown(dropdownId);
}
},
- [recordBoardSelectedRecordIdsSelector, isActionMenuDropdownOpenState],
+ [recordBoardSelectedRecordIdsSelector, closeDropdown, dropdownId],
);
return {
diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx
index f0c4c614c..d066372b3 100644
--- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx
@@ -7,6 +7,7 @@ import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/r
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
+import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
import { RecordBoardCardBody } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBody';
import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader';
@@ -121,7 +122,9 @@ export const RecordBoardCard = () => {
x: event.clientX,
y: event.clientY,
});
- openDropdown(actionMenuDropdownId);
+ openDropdown(actionMenuDropdownId, {
+ scope: ActionMenuDropdownHotkeyScope.ActionMenuDropdown,
+ });
};
const handleCardClick = () => {
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx
index 2cd868675..57de829e8 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker.tsx
@@ -15,7 +15,7 @@ import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@@ -28,7 +28,7 @@ import { Key } from 'ts-key-enum';
import { isDefined } from 'twenty-shared/utils';
import { IconPlus } from 'twenty-ui/display';
-export const StyledSelectableItem = styled(SelectableItem)`
+export const StyledSelectableItem = styled(SelectableListItem)`
height: 100%;
width: 100%;
`;
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx
index fdeae6e97..09ac4c196 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx
@@ -3,10 +3,10 @@ import styled from '@emotion/styled';
import { useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId } from '@/object-record/record-picker/hooks/useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId';
import { MultipleRecordPickerMenuItemContent } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent';
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { isDefined } from 'twenty-shared/utils';
-export const StyledSelectableItem = styled(SelectableItem)`
+export const StyledSelectableItem = styled(SelectableListItem)`
height: 100%;
width: 100%;
`;
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx
index b20094847..b99e01728 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx
@@ -6,7 +6,7 @@ import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/re
import { multipleRecordPickerIsSelectedComponentFamilySelector } from '@/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerIsSelectedComponentFamilySelector';
import { getMultipleRecordPickerSelectableListId } from '@/object-record/record-picker/multiple-record-picker/utils/getMultipleRecordPickerSelectableListId';
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
@@ -14,7 +14,7 @@ import { Avatar } from 'twenty-ui/display';
import { MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
import { SearchRecord } from '~/generated-metadata/graphql';
-export const StyledSelectableItem = styled(SelectableItem)`
+export const StyledSelectableItem = styled(SelectableListItem)`
height: 100%;
width: 100%;
`;
@@ -62,6 +62,7 @@ export const MultipleRecordPickerMenuItemContent = ({
handleSelectChange(!isRecordSelectedWithObjectItem)}
>
handleSelectChange(isSelected)}
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx
index 60f4a256e..08995df3d 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItems.tsx
@@ -4,21 +4,19 @@ import { MultipleRecordPickerMenuItem } from '@/object-record/record-picker/mult
import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext';
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
import { multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector } from '@/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerPickableRecordIdsMatchingSearchComponentSelector';
-import { multipleRecordPickerSinglePickableMorphItemComponentFamilySelector } from '@/object-record/record-picker/multiple-record-picker/states/selectors/multipleRecordPickerSinglePickableMorphItemComponentFamilySelector';
import { MultipleRecordPickerHotkeyScope } from '@/object-record/record-picker/multiple-record-picker/types/MultipleRecordPickerHotkeyScope';
import { getMultipleRecordPickerSelectableListId } from '@/object-record/record-picker/multiple-record-picker/utils/getMultipleRecordPickerSelectableListId';
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useRecoilCallback } from 'recoil';
-import { isDefined } from 'twenty-shared/utils';
-export const StyledSelectableItem = styled(SelectableItem)`
+export const StyledSelectableItem = styled(SelectableListItem)`
height: 100%;
width: 100%;
`;
@@ -45,11 +43,6 @@ export const MultipleRecordPickerMenuItems = ({
const { resetSelectedItem } = useSelectableList(
selectableListComponentInstanceId,
);
- const singlePickableMorphItemFamilySelector =
- useRecoilComponentCallbackStateV2(
- multipleRecordPickerSinglePickableMorphItemComponentFamilySelector,
- componentInstanceId,
- );
const multipleRecordPickerPickableMorphItemsState =
useRecoilComponentCallbackStateV2(
@@ -82,42 +75,12 @@ export const MultipleRecordPickerMenuItems = ({
[multipleRecordPickerPickableMorphItemsState],
);
- const handleEnter = useRecoilCallback(
- ({ snapshot }) => {
- return (selectedId: string) => {
- const pickableMorphItem = snapshot
- .getLoadable(singlePickableMorphItemFamilySelector(selectedId))
- .getValue();
-
- if (!isDefined(pickableMorphItem)) {
- return;
- }
-
- const selectedMorphItem = {
- ...pickableMorphItem,
- isSelected: !pickableMorphItem.isSelected,
- };
-
- handleChange(selectedMorphItem);
- onChange?.(selectedMorphItem);
- resetSelectedItem();
- };
- },
- [
- handleChange,
- onChange,
- resetSelectedItem,
- singlePickableMorphItemFamilySelector,
- ],
- );
-
return (
{pickableRecordIds.map((recordId) => {
return (
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx
index 42f222787..ab47a54a6 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerSearchInput.tsx
@@ -1,19 +1,11 @@
-import styled from '@emotion/styled';
-
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
import { MultipleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/multiple-record-picker/states/contexts/MultipleRecordPickerComponentInstanceContext';
import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useCallback } from 'react';
-export const StyledSelectableItem = styled(SelectableItem)`
- height: 100%;
- width: 100%;
-`;
-
export const MultipleRecordPickerSearchInput = () => {
const componentInstanceId = useAvailableComponentInstanceIdOrThrow(
MultipleRecordPickerComponentInstanceContext,
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx
index c0c477b58..023347ef3 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx
@@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
import { getSingleRecordPickerSelectableListId } from '@/object-record/record-picker/single-record-picker/utils/getSingleRecordPickerSelectableListId';
-import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
@@ -16,7 +16,7 @@ type SingleRecordPickerMenuItemProps = {
selectedRecord?: SingleRecordPickerRecord;
};
-const StyledSelectableItem = styled(SelectableItem)`
+const StyledSelectableItem = styled(SelectableListItem)`
width: 100%;
`;
@@ -40,14 +40,19 @@ export const SingleRecordPickerMenuItem = ({
);
return (
-
+ {
+ onRecordSelected(record);
+ }}
+ >
onRecordSelected(record)}
text={record.name}
selected={selectedRecord?.id === record.id}
- hovered={isSelectedItemId}
+ focused={isSelectedItemId}
avatar={
{
- const recordIndex = recordsInDropdown.findIndex(
- (record) => record.id === itemId,
- );
- setSelectedRecordId(itemId);
- onRecordSelected(recordsInDropdown[recordIndex]);
- resetSelectedItem();
- }}
>
{loading && !isFiltered ? (
@@ -128,17 +121,25 @@ export const SingleRecordPickerMenuItems = ({
case 'select-none': {
return (
emptyLabel && (
- {
+ itemId={record.id}
+ onEnter={() => {
setSelectedRecordId(undefined);
onRecordSelected();
}}
- LeftIcon={EmptyIcon}
- text={emptyLabel}
- selected={isUndefined(selectedRecordId)}
- hovered={isSelectedSelectNoneButton}
- />
+ >
+ {
+ setSelectedRecordId(undefined);
+ onRecordSelected();
+ }}
+ LeftIcon={EmptyIcon}
+ text={emptyLabel}
+ selected={isUndefined(selectedRecordId)}
+ focused={isSelectedSelectNoneButton}
+ />
+
)
);
}
diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts
index e1bacd329..0e3eff0fc 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts
+++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts
@@ -2,15 +2,15 @@ import { useRecoilCallback } from 'recoil';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
+import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
+import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
-import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
-import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
+import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
-
export const useTriggerActionMenuDropdown = ({
recordTableId,
}: {
@@ -25,18 +25,17 @@ export const useTriggerActionMenuDropdown = ({
recordTableId,
);
+ const actionMenuDropdownId =
+ getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId);
+
const recordIndexActionMenuDropdownPositionState = extractComponentState(
recordIndexActionMenuDropdownPositionComponentState,
- getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId),
+ actionMenuDropdownId,
);
- const isActionMenuDropdownOpenState = extractComponentState(
- isDropdownOpenComponentState,
- getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId),
- );
+ const { openDropdown } = useDropdown(actionMenuDropdownId);
- const { setActiveDropdownFocusIdAndMemorizePrevious } =
- useSetActiveDropdownFocusIdAndMemorizePrevious();
+ const { closeCommandMenu } = useCommandMenu();
const triggerActionMenuDropdown = useRecoilCallback(
({ set, snapshot }) =>
@@ -57,19 +56,17 @@ export const useTriggerActionMenuDropdown = ({
set(isRowSelectedFamilyState(recordId), true);
}
- set(isActionMenuDropdownOpenState, true);
+ closeCommandMenu();
- const actionMenuDropdownId =
- getActionMenuDropdownIdFromActionMenuId(actionMenuInstanceId);
-
- setActiveDropdownFocusIdAndMemorizePrevious(actionMenuDropdownId);
+ openDropdown({
+ scope: ActionMenuDropdownHotkeyScope.ActionMenuDropdown,
+ });
},
[
- isActionMenuDropdownOpenState,
- isRowSelectedFamilyState,
recordIndexActionMenuDropdownPositionState,
- setActiveDropdownFocusIdAndMemorizePrevious,
- actionMenuInstanceId,
+ isRowSelectedFamilyState,
+ closeCommandMenu,
+ openDropdown,
],
);
diff --git a/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx b/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx
index dcedda2d9..29087acbb 100644
--- a/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx
+++ b/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx
@@ -7,6 +7,7 @@ import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
+import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@@ -93,43 +94,38 @@ export const MultipleSelectDropdown = ({
selectableListInstanceId={selectableListId}
selectableItemIdArray={selectableItemIds}
hotkeyScope={hotkeyScope}
- onEnter={(itemId) => {
- const item = itemsInDropdown.findIndex(
- (entity) => entity.id === itemId,
- );
- const itemIsSelectedInDropwdown = filteredSelectedItems.find(
- (entity) => entity.id === itemId,
- );
- handleItemSelectChange(
- itemsInDropdown[item],
- !itemIsSelectedInDropwdown,
- );
- resetSelectedItem();
- }}
>
{itemsInDropdown?.map((item) => {
return (
- {
+ {
resetSelectedItem();
- handleItemSelectChange(item, newCheckedValue);
+ handleItemSelectChange(item, !item.isSelected);
}}
- avatar={
-
- }
- />
+ >
+ {
+ resetSelectedItem();
+ handleItemSelectChange(item, newCheckedValue);
+ }}
+ avatar={
+
+ }
+ />
+
);
})}
{showNoResult && }
diff --git a/packages/twenty-front/src/modules/ui/field/input/components/MultiSelectInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/MultiSelectInput.tsx
index 94b107793..9a95f2d55 100644
--- a/packages/twenty-front/src/modules/ui/field/input/components/MultiSelectInput.tsx
+++ b/packages/twenty-front/src/modules/ui/field/input/components/MultiSelectInput.tsx
@@ -101,14 +101,6 @@ export const MultiSelectInput = ({
selectableListInstanceId={selectableListComponentInstanceId}
selectableItemIdArray={optionIds}
hotkeyScope={hotkeyScope}
- onEnter={(itemId) => {
- const option = filteredOptionsInDropDown.find(
- (option) => option.value === itemId,
- );
- if (isDefined(option)) {
- onOptionSelected(formatNewSelectedOptions(option.value));
- }
- }}
>
{
- onChange({ iconKey, Icon: getIcon(iconKey) });
- closeDropdown();
- }}
>
({
? selectContainerRef.current?.clientWidth
: dropdownWidth;
+ const selectableItemIdArray = filteredOptions.map((option) => option.label);
+
+ const selectedItemId = useRecoilComponentValueV2(
+ selectedItemIdComponentState,
+ dropdownId,
+ );
+
return (
({
)}
{!!filteredOptions.length && (
- {filteredOptions.map((option) => (
- {
- onChange?.(option.value);
- onBlur?.();
- closeDropdown();
- }}
- />
- ))}
+
+ {filteredOptions.map((option) => (
+ {
+ onChange?.(option.value);
+ onBlur?.();
+ closeDropdown();
+ }}
+ >
+ {
+ onChange?.(option.value);
+ onBlur?.();
+ closeDropdown();
+ }}
+ />
+
+ ))}
+
)}
{!!callToActionButton && !!filteredOptions.length && (
diff --git a/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx b/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx
index a3be42613..674c60c7a 100644
--- a/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx
+++ b/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx
@@ -7,9 +7,9 @@ import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useLis
import { useEffect, useMemo, useRef, useState } from 'react';
import { Key } from 'ts-key-enum';
import { isDefined } from 'twenty-shared/utils';
-import { MenuItemSelectTag } from 'twenty-ui/navigation';
-import { SelectOption } from 'twenty-ui/input';
import { TagColor } from 'twenty-ui/components';
+import { SelectOption } from 'twenty-ui/input';
+import { MenuItemSelectTag } from 'twenty-ui/navigation';
interface SelectInputProps {
onOptionSelected: (selectedOption: SelectOption) => void;
@@ -107,7 +107,6 @@ export const SelectInput = ({
{onClear && clearLabel && (
handleOptionChange(option)}
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableList.tsx b/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableList.tsx
index 6361efca1..34ecf3796 100644
--- a/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableList.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableList.tsx
@@ -2,8 +2,8 @@ import { ReactNode, useEffect } from 'react';
import { useSelectableListHotKeys } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListHotKeys';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
+import { SelectableListContextProvider } from '@/ui/layout/selectable-list/states/contexts/SelectableListContext';
import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/states/selectableItemIdsComponentState';
-import { selectableListOnEnterComponentState } from '@/ui/layout/selectable-list/states/selectableListOnEnterComponentState';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { isDefined } from 'twenty-shared/utils';
import { arrayToChunks } from '~/utils/array/arrayToChunks';
@@ -14,7 +14,6 @@ type SelectableListProps = {
selectableItemIdMatrix?: string[][];
onSelect?: (selected: string) => void;
hotkeyScope: string;
- onEnter?: (itemId: string) => void;
selectableListInstanceId: string;
};
@@ -24,25 +23,15 @@ export const SelectableList = ({
selectableItemIdArray,
selectableItemIdMatrix,
selectableListInstanceId,
- onEnter,
onSelect,
}: SelectableListProps) => {
useSelectableListHotKeys(selectableListInstanceId, hotkeyScope, onSelect);
- const setSelectableListOnEnter = useSetRecoilComponentStateV2(
- selectableListOnEnterComponentState,
- selectableListInstanceId,
- );
-
const setSelectableItemIds = useSetRecoilComponentStateV2(
selectableItemIdsComponentState,
selectableListInstanceId,
);
- useEffect(() => {
- setSelectableListOnEnter(() => onEnter);
- }, [onEnter, setSelectableListOnEnter]);
-
useEffect(() => {
if (!selectableItemIdArray && !selectableItemIdMatrix) {
throw new Error(
@@ -65,7 +54,9 @@ export const SelectableList = ({
instanceId: selectableListInstanceId,
}}
>
- {children}
+
+ {children}
+
);
};
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/SelectableListItem.tsx
similarity index 60%
rename from packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableItem.tsx
rename to packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableListItem.tsx
index 1e7c89d94..a4e1b02db 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/SelectableListItem.tsx
@@ -1,25 +1,29 @@
import { ReactNode, useEffect, useRef } from 'react';
+import { SelectableListItemHotkeyEffect } from '@/ui/layout/selectable-list/components/SelectableListItemHotkeyEffect';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import styled from '@emotion/styled';
+import { isDefined } from 'twenty-shared/utils';
const StyledContainer = styled.div`
height: 100%;
width: 100%;
`;
-export type SelectableItemProps = {
+export type SelectableListItemProps = {
itemId: string;
children: ReactNode;
className?: string;
+ onEnter?: () => void;
};
-export const SelectableItem = ({
+export const SelectableListItem = ({
itemId,
children,
className,
-}: SelectableItemProps) => {
+ onEnter,
+}: SelectableListItemProps) => {
const isSelectedItemId = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
itemId,
@@ -34,8 +38,13 @@ export const SelectableItem = ({
}, [isSelectedItemId]);
return (
-
- {children}
-
+ <>
+ {isSelectedItemId && isDefined(onEnter) && (
+
+ )}
+
+ {children}
+
+ >
);
};
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableListItemHotkeyEffect.tsx b/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableListItemHotkeyEffect.tsx
new file mode 100644
index 000000000..c53b18842
--- /dev/null
+++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/components/SelectableListItemHotkeyEffect.tsx
@@ -0,0 +1,19 @@
+import { useSelectableListListenToEnterHotkeyOnItem } from '@/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem';
+import { useSelectableListContextOrThrow } from '@/ui/layout/selectable-list/states/contexts/SelectableListContext';
+
+export const SelectableListItemHotkeyEffect = ({
+ itemId,
+ onEnter,
+}: {
+ itemId: string;
+ onEnter: () => void;
+}) => {
+ const { hotkeyScope } = useSelectableListContextOrThrow();
+
+ useSelectableListListenToEnterHotkeyOnItem({
+ hotkeyScope,
+ itemId,
+ onEnter,
+ });
+ return null;
+};
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/internal/useSelectableListHotKeys.ts b/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/internal/useSelectableListHotKeys.ts
index 66df15c7f..1c5cf7355 100644
--- a/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/internal/useSelectableListHotKeys.ts
+++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/internal/useSelectableListHotKeys.ts
@@ -3,7 +3,6 @@ import { useRecoilCallback } from 'recoil';
import { Key } from 'ts-key-enum';
import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/states/selectableItemIdsComponentState';
-import { selectableListOnEnterComponentState } from '@/ui/layout/selectable-list/states/selectableListOnEnterComponentState';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@@ -147,35 +146,4 @@ export const useSelectableListHotKeys = (
hotkeyScope,
[],
);
-
- useScopedHotkeys(
- Key.Enter,
- useRecoilCallback(
- ({ snapshot }) =>
- () => {
- const selectedItemId = getSnapshotValue(
- snapshot,
- selectedItemIdComponentState.atomFamily({
- instanceId: instanceId,
- }),
- );
- const onEnter = getSnapshotValue(
- snapshot,
- selectableListOnEnterComponentState.atomFamily({
- instanceId: instanceId,
- }),
- );
-
- if (isNonEmptyString(selectedItemId)) {
- onEnter?.(selectedItemId);
- }
- },
- [instanceId],
- ),
- hotkeyScope,
- [],
- {
- preventDefault: false,
- },
- );
};
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem.ts b/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem.ts
index b870dee64..dd8b20146 100644
--- a/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem.ts
+++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/hooks/useSelectableListListenToEnterHotkeyOnItem.ts
@@ -39,8 +39,5 @@ export const useSelectableListListenToEnterHotkeyOnItem = ({
),
hotkeyScope,
[itemId, onEnter],
- {
- preventDefault: false,
- },
);
};
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/states/contexts/SelectableListContext.tsx b/packages/twenty-front/src/modules/ui/layout/selectable-list/states/contexts/SelectableListContext.tsx
new file mode 100644
index 000000000..7c8d757b5
--- /dev/null
+++ b/packages/twenty-front/src/modules/ui/layout/selectable-list/states/contexts/SelectableListContext.tsx
@@ -0,0 +1,8 @@
+import { createRequiredContext } from '~/utils/createRequiredContext';
+
+export type SelectableListContextValue = {
+ hotkeyScope: string;
+};
+
+export const [SelectableListContextProvider, useSelectableListContextOrThrow] =
+ createRequiredContext('SelectableListContext');
diff --git a/packages/twenty-front/src/modules/ui/layout/selectable-list/states/selectableListOnEnterComponentState.ts b/packages/twenty-front/src/modules/ui/layout/selectable-list/states/selectableListOnEnterComponentState.ts
deleted file mode 100644
index 356553596..000000000
--- a/packages/twenty-front/src/modules/ui/layout/selectable-list/states/selectableListOnEnterComponentState.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
-import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
-
-export const selectableListOnEnterComponentState = createComponentStateV2<
- ((itemId: string) => void) | undefined
->({
- key: 'selectableListOnEnterComponentState',
- defaultValue: undefined,
- componentInstanceContext: SelectableListComponentInstanceContext,
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx
index 0a0cf94be..5fa9e0a3f 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx
@@ -141,7 +141,7 @@ export const WorkflowVariablesDropdownFieldItems = ({
handleSelectField(key)}
text={subStep.label || key}
hasSubMenu={!subStep.isLeaf}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownObjectItems.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownObjectItems.tsx
index 389ebe1cf..3829e3d84 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownObjectItems.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownObjectItems.tsx
@@ -121,7 +121,7 @@ export const WorkflowVariablesDropdownObjectItems = ({
{shouldDisplaySubStepObject && displayedSubStepObject?.label && (
handleSelectField(key)}
text={value.label || key}
hasSubMenu={!value.isLeaf}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownWorkflowStepItems.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownWorkflowStepItems.tsx
index e8ea1357b..69f68a64d 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownWorkflowStepItems.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownWorkflowStepItems.tsx
@@ -55,7 +55,7 @@ export const WorkflowVariablesDropdownWorkflowStepItems = ({
onSelect(item.id)}
text={item.name}
LeftIcon={item.icon ? getIcon(item.icon) : undefined}
diff --git a/packages/twenty-ui/src/navigation/menu-item/components/MenuItem.tsx b/packages/twenty-ui/src/navigation/menu-item/components/MenuItem.tsx
index ef566fe98..d3c4ed196 100644
--- a/packages/twenty-ui/src/navigation/menu-item/components/MenuItem.tsx
+++ b/packages/twenty-ui/src/navigation/menu-item/components/MenuItem.tsx
@@ -35,6 +35,7 @@ export type MenuItemProps = {
text: ReactNode;
contextualText?: ReactNode;
hasSubMenu?: boolean;
+ focused?: boolean;
};
export const MenuItem = ({
@@ -53,6 +54,7 @@ export const MenuItem = ({
contextualText,
hasSubMenu = false,
disabled = false,
+ focused = false,
}: MenuItemProps) => {
const theme = useTheme();
const showIconButtons = Array.isArray(iconButtons) && iconButtons.length > 0;
@@ -75,6 +77,7 @@ export const MenuItem = ({
isIconDisplayedOnHoverOnly={isIconDisplayedOnHoverOnly}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
+ focused={focused}
>
`
- ${({ theme, selected, disabled, hovered }) => {
- if (selected) {
- return css`
- background: ${theme.background.transparent.light};
- &:hover {
- background: ${theme.background.transparent.medium};
- }
- `;
- } else if (disabled === true) {
+ ${({ theme, disabled, focused }) => {
+ if (disabled === true) {
return css`
background: inherit;
&:hover {
@@ -30,7 +22,7 @@ export const StyledMenuItemSelect = styled(StyledMenuItemBase)<{
cursor: default;
`;
- } else if (hovered === true) {
+ } else if (focused === true) {
return css`
background: ${theme.background.transparent.light};
`;
@@ -46,7 +38,7 @@ type MenuItemSelectProps = {
className?: string;
onClick?: () => void;
disabled?: boolean;
- hovered?: boolean;
+ focused?: boolean;
hasSubMenu?: boolean;
contextualText?: ReactNode;
};
@@ -59,7 +51,7 @@ export const MenuItemSelect = ({
className,
onClick,
disabled,
- hovered,
+ focused,
hasSubMenu = false,
contextualText,
}: MenuItemSelectProps) => {
@@ -69,9 +61,8 @@ export const MenuItemSelect = ({
void;
disabled?: boolean;
- hovered?: boolean;
+ focused?: boolean;
testId?: string;
};
@@ -28,7 +28,7 @@ export const MenuItemSelectAvatar = ({
className,
onClick,
disabled,
- hovered,
+ focused,
testId,
}: MenuItemSelectAvatarProps) => {
const theme = useTheme();
@@ -37,9 +37,8 @@ export const MenuItemSelectAvatar = ({
void;
disabled?: boolean;
- hovered?: boolean;
+ focused?: boolean;
color: ThemeColor;
variant?: ColorSampleVariant;
};
@@ -39,7 +39,7 @@ export const MenuItemSelectColor = ({
className,
onClick,
disabled,
- hovered,
+ focused,
variant = 'default',
}: MenuItemSelectColorProps) => {
const theme = useTheme();
@@ -48,9 +48,8 @@ export const MenuItemSelectColor = ({
diff --git a/packages/twenty-ui/src/navigation/menu-item/components/MenuItemSelectTag.tsx b/packages/twenty-ui/src/navigation/menu-item/components/MenuItemSelectTag.tsx
index 515f208a5..35b5380c6 100644
--- a/packages/twenty-ui/src/navigation/menu-item/components/MenuItemSelectTag.tsx
+++ b/packages/twenty-ui/src/navigation/menu-item/components/MenuItemSelectTag.tsx
@@ -11,7 +11,8 @@ import { ThemeColor } from '@ui/theme';
import { StyledMenuItemSelect } from './MenuItemSelect';
type MenuItemSelectTagProps = {
- selected: boolean;
+ selected?: boolean;
+ focused?: boolean;
isKeySelected?: boolean;
className?: string;
onClick?: () => void;
@@ -24,6 +25,7 @@ type MenuItemSelectTagProps = {
export const MenuItemSelectTag = ({
color,
selected,
+ focused,
isKeySelected,
className,
onClick,
@@ -36,7 +38,7 @@ export const MenuItemSelectTag = ({
diff --git a/packages/twenty-ui/src/navigation/menu-item/components/MenuItemToggle.tsx b/packages/twenty-ui/src/navigation/menu-item/components/MenuItemToggle.tsx
index 813d9e357..1458ed03e 100644
--- a/packages/twenty-ui/src/navigation/menu-item/components/MenuItemToggle.tsx
+++ b/packages/twenty-ui/src/navigation/menu-item/components/MenuItemToggle.tsx
@@ -17,6 +17,7 @@ const StyledToggleContainer = styled.label`
`;
type MenuItemToggleProps = {
+ focused?: boolean;
LeftIcon?: IconComponent;
toggled: boolean;
text: string;
@@ -26,6 +27,7 @@ type MenuItemToggleProps = {
};
export const MenuItemToggle = ({
+ focused,
LeftIcon,
text,
toggled,
@@ -35,7 +37,7 @@ export const MenuItemToggle = ({
}: MenuItemToggleProps) => {
const inputId = useId();
return (
-
+
diff --git a/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx b/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx
index d67bb7af0..9e8806fb4 100644
--- a/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx
+++ b/packages/twenty-ui/src/navigation/menu-item/internals/components/StyledMenuItemBase.tsx
@@ -13,6 +13,7 @@ export type MenuItemBaseProps = {
isHoverBackgroundDisabled?: boolean;
hovered?: boolean;
disabled?: boolean;
+ focused?: boolean;
};
export const StyledMenuItemBase = styled.div`
@@ -72,6 +73,12 @@ export const StyledMenuItemBase = styled.div`
}
}}
+ ${({ focused, theme }) =>
+ focused &&
+ css`
+ background: ${theme.background.transparent.light};
+ `};
+
position: relative;
user-select: none;