Refactor useDropdownV2 (#12875)
# What this PR does This PR introduces what’s needed to progressively refactor the useDropdown hooks we have. It removes useDropdownV2 and renames useDropdown used for multi-page dropdowns to useDropdownContextStateManagement ## The 3 useDropdown hooks There are currently 3 useDropdown hooks : One is used for managing states in some dropdowns that have multiple inner pages with contexts and without recoil. It is limited and would need a separate refactoring, thus I just renamed it. Then we have useDropdown and useDropdownV2, which followed our multiple versions of recoil state management wrappers. Now that the state management has been stabilized, we can merge everything on the last version. ## What this refactor will allow next This refactor will allow to refactor the legacy recoil state management, because useDropdown is depending on legacy recoil states with scopeId. Because there are only a dozen of those legacy states left, and the dropdown’s ones are the harder to refactor, because swapping them as-is causes a big QA, and if we have a big QA to do on all dropdowns, better refactor the whole dropdown management and have everything clean. After this refactor, we will be able to delete the legacy dropdown states, and proceed with the other legacy states, then removing all the legacy recoil state mangament. ## How do we allow progressive refactoring ? There are many places where useDropdown is used. To have an easier refactoring process, we want to merge multiple small pull requests so that it is easier to QA and review. For this we will maintain both legacy component state and component state V2 in parallel for isDropdownOpen, so that the new hooks `useOpenDropdown` , `useCloseDropdown` are doing the same thing than `useDropdown` and `useDropdownV2` . Thus for the moment, whether we use the legacy hooks or the new ones, the effects are the same. And we can have dropdowns operating on the old states and the new states living side by side in the app. ## QA Component | Status | Comments -- | -- | -- CommandMenuActionMenuDropdown | Ok | RecordIndexActionMenuDropdown | Ok | RecordShowRightDrawerOpenRecordButton | Ok | useCloseActionMenu | Ok | CommandMenuContextChipGroups | Ok | useCommandMenuCloseAnimationCompleteCleanup | Ok | ObjectOptionsDropdown | Ok | ObjectOptionsDropdownContent | Ok | ObjectOptionsDropdownFieldsContent | Ok | ObjectOptionsDropdownHiddenFieldsContent | Ok | ObjectOptionsDropdownHiddenRecordGroupsContent | Ok | ObjectOptionsDropdownLayoutContent | Ok | ObjectOptionsDropdownLayoutOpenInContent | Ok | ObjectOptionsDropdownMenuContent | Ok | ObjectOptionsDropdownRecordGroupFieldsContent | Ok | ObjectOptionsDropdownRecordGroupsContent | Ok | ObjectOptionsDropdownRecordGroupSortContent | Ok | RecordBoardColumnHeaderAggregateDropdown | Ok | AggregateDropdownContent | Ok | RecordBoardColumnHeaderAggregateDropdownFieldsContent | Ok | RecordBoardColumnHeaderAggregateDropdownMenuContent | Ok | RecordBoardColumnHeaderAggregateDropdownMenuContent | Ok | RecordBoardColumnHeaderAggregateDropdownOptionsContent | Ok | RecordBoard | Ok | Used closeAnyOpenDropdown instead for a better UX RecordBoardCard | Ok | useRecordBoardSelection | Ok | RecordTableColumnAggregateFooterDropdownContent | Ok | RecordTableColumnFooterWithDropdown | Ok | useOpenRecordFilterChipFromTableHeader | Ok | useCloseAnyOpenDropdown | Ok | useCloseDropdownFromOutside | Removed | Removed because unused useDropdownV2 | Removed | Removed because all calls have been removed useOpenDropdownFromOutside | Removed | Removed because unused useCloseAndResetViewPicker | Ok | WorkflowVariablesDropdown | Ok |
This commit is contained in:
+5
-3
@@ -8,7 +8,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
@@ -30,12 +30,14 @@ export const CommandMenuActionMenuDropdown = () => {
|
||||
|
||||
const dropdownId =
|
||||
getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId);
|
||||
const { toggleDropdown } = useDropdownV2();
|
||||
const { toggleDropdown } = useToggleDropdown();
|
||||
|
||||
const hotkeysConfig = {
|
||||
keys: ['ctrl+o', 'meta+o'],
|
||||
callback: () => {
|
||||
toggleDropdown(dropdownId);
|
||||
toggleDropdown({
|
||||
dropdownComponentInstanceIdFromProps: dropdownId,
|
||||
});
|
||||
},
|
||||
scope: AppHotkeyScope.CommandMenuOpen,
|
||||
dependencies: [toggleDropdown],
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
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';
|
||||
@@ -48,7 +48,7 @@ export const RecordIndexActionMenuDropdown = () => {
|
||||
);
|
||||
|
||||
const dropdownId = getActionMenuDropdownIdFromActionMenuId(actionMenuId);
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const actionMenuDropdownPosition = useRecoilValue(
|
||||
extractComponentState(
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
@@ -74,7 +74,7 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
||||
ActionMenuComponentInstanceContext,
|
||||
);
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const handleOpenRecord = useRecoilCallback(
|
||||
({ snapshot, reset }) =>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
|
||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -19,7 +19,7 @@ export const useCloseActionMenu = ({
|
||||
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const actionMenuId = useAvailableComponentInstanceIdOrThrow(
|
||||
ActionMenuComponentInstanceContext,
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/con
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
import {
|
||||
@@ -15,7 +15,7 @@ export const CommandMenuContextChipGroups = ({
|
||||
}: {
|
||||
contextChips: CommandMenuContextChipProps[];
|
||||
}) => {
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
if (contextChips.length === 0) {
|
||||
return null;
|
||||
|
||||
+2
-2
@@ -25,8 +25,8 @@ const mockResetContextStoreStates = jest.fn();
|
||||
const mockResetSelectedItem = jest.fn();
|
||||
const mockEmitSidePanelCloseEvent = jest.fn();
|
||||
|
||||
jest.mock('@/ui/layout/dropdown/hooks/useDropdownV2', () => ({
|
||||
useDropdownV2: () => ({
|
||||
jest.mock('@/ui/layout/dropdown/hooks/useCloseDropdown', () => ({
|
||||
useCloseDropdown: () => ({
|
||||
closeDropdown: mockCloseDropdown,
|
||||
}),
|
||||
}));
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuCl
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { emitSidePanelCloseEvent } from '@/ui/layout/right-drawer/utils/emitSidePanelCloseEvent';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
||||
@@ -27,7 +27,7 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
|
||||
const { resetContextStoreStates } = useResetContextStoreStates();
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const commandMenuCloseAnimationCompleteCleanup = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
export const useCurrentContentId = <T>() => {
|
||||
export const useDropdownContextCurrentContentId = <T>() => {
|
||||
const [currentContentId, setCurrentContentId] = useState<T | null>(null);
|
||||
|
||||
const [previousContentId, setPreviousContentId] = useState<T | null>(null);
|
||||
+8
-2
@@ -4,7 +4,13 @@ import { RecordTableColumnAggregateFooterDropdownContextValue } from '@/object-r
|
||||
import { useDropdown as useDropdownUi } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { Context, useCallback, useContext } from 'react';
|
||||
|
||||
export const useDropdown = <
|
||||
/**
|
||||
*
|
||||
* @deprecated This hook is deprecated because it uses context instead of recoil and synchronous hooks like we do in the application
|
||||
*
|
||||
* TODO: refactor this generic way to handle multiple pages in a dropdown with state management and specific code paths in a dedicated module, instead of using context with generic union types.
|
||||
*/
|
||||
export const useDropdownContextStateManagement = <
|
||||
T extends
|
||||
| RecordBoardColumnHeaderAggregateDropdownContextValue
|
||||
| RecordTableColumnAggregateFooterDropdownContextValue
|
||||
@@ -18,7 +24,7 @@ export const useDropdown = <
|
||||
|
||||
if (!dropdownContext) {
|
||||
throw new Error(
|
||||
`useDropdown must be used within a context provider (${context.Provider.name})`,
|
||||
`useDropdownContextStateManagement must be used within a context provider (${context.Provider.name})`,
|
||||
);
|
||||
}
|
||||
const dropdownId = dropdownContext.dropdownId;
|
||||
+3
-3
@@ -1,5 +1,4 @@
|
||||
import { DROPDOWN_OFFSET_Y } from '@/dropdown/constants/DropdownOffsetY';
|
||||
import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId';
|
||||
import { useDropdownContextCurrentContentId } from '@/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent';
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
@@ -9,6 +8,7 @@ import { RecordGroupReorderConfirmationModal } from '@/object-record/record-grou
|
||||
import { useRecordGroupReorderConfirmationModal } from '@/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||
import { DROPDOWN_OFFSET_Y } from '@/ui/layout/dropdown/constants/DropdownOffsetY';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
@@ -25,7 +25,7 @@ export const ObjectOptionsDropdown = ({
|
||||
viewType,
|
||||
}: ObjectOptionsDropdownProps) => {
|
||||
const { currentContentId, handleContentChange, handleResetContent } =
|
||||
useCurrentContentId<ObjectOptionsContentId>();
|
||||
useDropdownContextCurrentContentId<ObjectOptionsContentId>();
|
||||
|
||||
const { isDropdownOpen } = useDropdown(OBJECT_OPTIONS_DROPDOWN_ID);
|
||||
const {
|
||||
|
||||
+2
-2
@@ -7,10 +7,10 @@ import { ObjectOptionsDropdownMenuContent } from '@/object-record/object-options
|
||||
import { ObjectOptionsDropdownRecordGroupFieldsContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent';
|
||||
import { ObjectOptionsDropdownRecordGroupsContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent';
|
||||
import { ObjectOptionsDropdownRecordGroupSortContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupSortContent';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
|
||||
export const ObjectOptionsDropdownContent = () => {
|
||||
const { currentContentId } = useOptionsDropdown();
|
||||
const { currentContentId } = useObjectOptionsDropdown();
|
||||
|
||||
switch (currentContentId) {
|
||||
case 'layout':
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||
import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
@@ -20,7 +20,7 @@ export const ObjectOptionsDropdownFieldsContent = () => {
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
resetContent,
|
||||
} = useOptionsDropdown();
|
||||
} = useObjectOptionsDropdown();
|
||||
|
||||
const {
|
||||
handleColumnVisibilityChange,
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular';
|
||||
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||
import { useObjectOptionsForTable } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForTable';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
@@ -28,7 +28,7 @@ export const ObjectOptionsDropdownHiddenFieldsContent = () => {
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
closeDropdown,
|
||||
} = useOptionsDropdown();
|
||||
} = useObjectOptionsDropdown();
|
||||
|
||||
const { objectNamePlural } = useObjectNamePluralFromSingular({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
||||
|
||||
import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular';
|
||||
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { RecordGroupsVisibilityDropdownSection } from '@/object-record/record-group/components/RecordGroupsVisibilityDropdownSection';
|
||||
import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
@@ -30,7 +30,7 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
closeDropdown,
|
||||
} = useOptionsDropdown();
|
||||
} = useObjectOptionsDropdown();
|
||||
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
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';
|
||||
@@ -43,7 +43,7 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
||||
resetContent,
|
||||
onContentChange,
|
||||
dropdownId,
|
||||
} = useOptionsDropdown();
|
||||
} = useObjectOptionsDropdown();
|
||||
|
||||
const { isCompactModeActive, setAndPersistIsCompactModeActive } =
|
||||
useObjectOptionsForBoard({
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { useUpdateObjectViewOptions } from '@/object-record/object-options-dropdown/hooks/useUpdateObjectViewOptions';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
import { MenuItemSelect } from 'twenty-ui/navigation';
|
||||
|
||||
export const ObjectOptionsDropdownLayoutOpenInContent = () => {
|
||||
const { onContentChange } = useOptionsDropdown();
|
||||
const { onContentChange } = useObjectOptionsDropdown();
|
||||
const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState);
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
const { setAndPersistOpenRecordIn } = useUpdateObjectViewOptions();
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { ObjectOptionsDropdownMenuViewName } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuViewName';
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
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';
|
||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
@@ -33,7 +33,7 @@ import { MenuItem } from 'twenty-ui/navigation';
|
||||
export const ObjectOptionsDropdownMenuContent = () => {
|
||||
const { t } = useLingui();
|
||||
const { recordIndexId, objectMetadataItem, onContentChange, closeDropdown } =
|
||||
useOptionsDropdown();
|
||||
useObjectOptionsDropdown();
|
||||
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import { useEffect } from 'react';
|
||||
import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular';
|
||||
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||
@@ -42,7 +42,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
||||
onContentChange,
|
||||
resetContent,
|
||||
closeDropdown,
|
||||
} = useOptionsDropdown();
|
||||
} = useObjectOptionsDropdown();
|
||||
|
||||
const { objectNamePlural } = useObjectNamePluralFromSingular({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
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 { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
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';
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
import { MenuItemSelect } from 'twenty-ui/navigation';
|
||||
|
||||
export const ObjectOptionsDropdownRecordGroupSortContent = () => {
|
||||
const { currentContentId, onContentChange } = useOptionsDropdown();
|
||||
const { currentContentId, onContentChange } = useObjectOptionsDropdown();
|
||||
|
||||
const hiddenRecordGroupIds = useRecoilComponentValueV2(
|
||||
hiddenRecordGroupIdsComponentSelector,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
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 { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { RecordGroupsVisibilityDropdownSection } from '@/object-record/record-group/components/RecordGroupsVisibilityDropdownSection';
|
||||
import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
@@ -43,7 +43,7 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
onContentChange,
|
||||
resetContent,
|
||||
handleRecordGroupOrderChangeWithModal,
|
||||
} = useOptionsDropdown();
|
||||
} = useObjectOptionsDropdown();
|
||||
|
||||
const { currentView } = useGetCurrentViewOnly();
|
||||
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import { act } from 'react';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
|
||||
import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
@@ -61,7 +61,7 @@ describe('useOptionsDropdown', () => {
|
||||
{children}
|
||||
</ObjectOptionsDropdownContext.Provider>
|
||||
);
|
||||
return renderHook(() => useOptionsDropdown(), { wrapper });
|
||||
return renderHook(() => useObjectOptionsDropdown(), { wrapper });
|
||||
};
|
||||
|
||||
it('provides closeDropdown functionality from the context', () => {
|
||||
|
||||
+4
-4
@@ -1,15 +1,15 @@
|
||||
import { useDropdown } from '@/dropdown/hooks/useDropdown';
|
||||
import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement';
|
||||
import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export const useOptionsDropdown = () => {
|
||||
export const useObjectOptionsDropdown = () => {
|
||||
const context = useContext(ObjectOptionsDropdownContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('useOptionsDropdown must be used within a context');
|
||||
throw new Error('useObjectOptionsDropdown must be used within a context');
|
||||
}
|
||||
|
||||
const { closeDropdown } = useDropdown({
|
||||
const { closeDropdown } = useDropdownContextStateManagement({
|
||||
context: ObjectOptionsDropdownContext,
|
||||
});
|
||||
|
||||
+3
-6
@@ -4,7 +4,6 @@ import { useContext, useRef } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { ACTION_MENU_DROPDOWN_CLICK_OUTSIDE_ID } from '@/action-menu/constants/ActionMenuDropdownClickOutsideId';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { COMMAND_MENU_CLICK_OUTSIDE_ID } from '@/command-menu/constants/CommandMenuClickOutsideId';
|
||||
import { RecordBoardHeader } from '@/object-record/record-board/components/RecordBoardHeader';
|
||||
import { RecordBoardScrollToFocusedCardEffect } from '@/object-record/record-board/components/RecordBoardScrollToFocusedCardEffect';
|
||||
@@ -26,7 +25,7 @@ import { RECORD_INDEX_REMOVE_SORTING_MODAL_ID } from '@/object-record/record-ind
|
||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown';
|
||||
import { MODAL_BACKDROP_CLICK_OUTSIDE_ID } from '@/ui/layout/modal/constants/ModalBackdropClickOutsideId';
|
||||
import { useModal } from '@/ui/layout/modal/hooks/useModal';
|
||||
import { PAGE_ACTION_CONTAINER_CLICK_OUTSIDE_ID } from '@/ui/layout/page/constants/PageActionContainerClickOutsideId';
|
||||
@@ -81,15 +80,13 @@ export const RecordBoard = () => {
|
||||
RECORD_BOARD_CLICK_OUTSIDE_LISTENER_ID,
|
||||
);
|
||||
|
||||
const actionMenuId = getActionMenuIdFromRecordIndexId(recordBoardId);
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown();
|
||||
|
||||
const { deactivateBoardCard } = useActiveRecordBoardCard(recordBoardId);
|
||||
const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId);
|
||||
|
||||
const handleDragSelectionStart = () => {
|
||||
closeDropdown(actionMenuId);
|
||||
closeAnyOpenDropdown();
|
||||
|
||||
toggleClickOutside(false);
|
||||
};
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionM
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
@@ -28,7 +28,7 @@ export const useRecordBoardSelection = (recordBoardId?: string) => {
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const dropdownId = getActionMenuDropdownIdFromActionMenuId(
|
||||
getActionMenuIdFromRecordIndexId(instanceIdFromProps),
|
||||
|
||||
+10
-7
@@ -15,7 +15,7 @@ import { RecordBoardCardBody } from '@/object-record/record-board/record-board-c
|
||||
import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader';
|
||||
import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId';
|
||||
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement';
|
||||
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||
@@ -140,22 +140,25 @@ export const RecordBoardCard = () => {
|
||||
),
|
||||
);
|
||||
|
||||
const { openDropdown } = useDropdownV2();
|
||||
const { openDropdown } = useOpenDropdown();
|
||||
|
||||
const { openRecordFromIndexView } = useOpenRecordFromIndexView();
|
||||
const { activateBoardCard } = useActiveRecordBoardCard(recordBoardId);
|
||||
const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId);
|
||||
|
||||
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
||||
const handleContextMenuOpen = (event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
setIsCurrentCardSelected(true);
|
||||
setActionMenuDropdownPosition({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
});
|
||||
openDropdown(actionMenuDropdownId, {
|
||||
enableGlobalHotkeysWithModifiers: true,
|
||||
enableGlobalHotkeysConflictingWithKeyboard: false,
|
||||
openDropdown({
|
||||
dropdownComponentInstanceIdFromProps: actionMenuDropdownId,
|
||||
globalHotkeysConfig: {
|
||||
enableGlobalHotkeysWithModifiers: true,
|
||||
enableGlobalHotkeysConflictingWithKeyboard: false,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -185,7 +188,7 @@ export const RecordBoardCard = () => {
|
||||
return (
|
||||
<StyledBoardCardWrapper
|
||||
data-click-outside-id={RECORD_BOARD_CARD_CLICK_OUTSIDE_ID}
|
||||
onContextMenu={handleActionMenuDropdown}
|
||||
onContextMenu={handleContextMenuOpen}
|
||||
>
|
||||
<InView>
|
||||
<StyledBoardCard
|
||||
|
||||
+4
-3
@@ -1,5 +1,4 @@
|
||||
import { DROPDOWN_OFFSET_Y } from '@/dropdown/constants/DropdownOffsetY';
|
||||
import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId';
|
||||
import { useDropdownContextCurrentContentId } from '@/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext } from '@/object-record/record-board/contexts/RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext';
|
||||
import { RecordBoardColumnHeaderAggregateDropdownButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownButton';
|
||||
@@ -7,6 +6,7 @@ import { AggregateDropdownContent } from '@/object-record/record-board/record-bo
|
||||
import { RecordBoardColumnHeaderAggregateDropdownContext } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext';
|
||||
import { RecordBoardColumnHeaderAggregateContentId } from '@/object-record/record-board/types/RecordBoardColumnHeaderAggregateContentId';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DROPDOWN_OFFSET_Y } from '@/ui/layout/dropdown/constants/DropdownOffsetY';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
type RecordBoardColumnHeaderAggregateDropdownProps = {
|
||||
@@ -31,7 +31,8 @@ export const RecordBoardColumnHeaderAggregateDropdown = ({
|
||||
handleContentChange,
|
||||
handleResetContent,
|
||||
previousContentId,
|
||||
} = useCurrentContentId<RecordBoardColumnHeaderAggregateContentId>();
|
||||
} =
|
||||
useDropdownContextCurrentContentId<RecordBoardColumnHeaderAggregateContentId>();
|
||||
|
||||
return (
|
||||
<RecordBoardColumnHeaderAggregateDropdownComponentInstanceContext.Provider
|
||||
|
||||
+5
-4
@@ -1,4 +1,4 @@
|
||||
import { useDropdown } from '@/dropdown/hooks/useDropdown';
|
||||
import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement';
|
||||
import { RecordBoardColumnHeaderAggregateDropdownContext } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext';
|
||||
import { RecordBoardColumnHeaderAggregateDropdownFieldsContent } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownFieldsContent';
|
||||
import { RecordBoardColumnHeaderAggregateDropdownMenuContent } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownMenuContent';
|
||||
@@ -12,9 +12,10 @@ import { getAvailableFieldsIdsForAggregationFromObjectFields } from '@/object-re
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
export const AggregateDropdownContent = () => {
|
||||
const { currentContentId, objectMetadataItem } = useDropdown({
|
||||
context: RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
});
|
||||
const { currentContentId, objectMetadataItem } =
|
||||
useDropdownContextStateManagement({
|
||||
context: RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
});
|
||||
|
||||
switch (currentContentId) {
|
||||
case 'countAggregateOperationsOptions': {
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { useDropdown } from '@/dropdown/hooks/useDropdown';
|
||||
import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement';
|
||||
import { RecordBoardColumnHeaderAggregateDropdownContext } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext';
|
||||
import { aggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/aggregateOperationComponentState';
|
||||
import { availableFieldIdsForAggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState';
|
||||
@@ -27,7 +27,7 @@ export const RecordBoardColumnHeaderAggregateDropdownFieldsContent = () => {
|
||||
onContentChange,
|
||||
resetContent,
|
||||
previousContentId,
|
||||
} = useDropdown({
|
||||
} = useDropdownContextStateManagement({
|
||||
context: RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
});
|
||||
|
||||
|
||||
+6
-4
@@ -1,6 +1,6 @@
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useDropdown } from '@/dropdown/hooks/useDropdown';
|
||||
import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement';
|
||||
import {
|
||||
RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
RecordBoardColumnHeaderAggregateDropdownContextValue,
|
||||
@@ -17,9 +17,11 @@ export const RecordBoardColumnHeaderAggregateDropdownMenuContent = () => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const { onContentChange, closeDropdown } =
|
||||
useDropdown<RecordBoardColumnHeaderAggregateDropdownContextValue>({
|
||||
context: RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
});
|
||||
useDropdownContextStateManagement<RecordBoardColumnHeaderAggregateDropdownContextValue>(
|
||||
{
|
||||
context: RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
},
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
|
||||
+6
-4
@@ -1,4 +1,4 @@
|
||||
import { useDropdown } from '@/dropdown/hooks/useDropdown';
|
||||
import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement';
|
||||
import {
|
||||
RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
RecordBoardColumnHeaderAggregateDropdownContextValue,
|
||||
@@ -32,9 +32,11 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
|
||||
title: string;
|
||||
}) => {
|
||||
const { onContentChange, closeDropdown, resetContent } =
|
||||
useDropdown<RecordBoardColumnHeaderAggregateDropdownContextValue>({
|
||||
context: RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
});
|
||||
useDropdownContextStateManagement<RecordBoardColumnHeaderAggregateDropdownContextValue>(
|
||||
{
|
||||
context: RecordBoardColumnHeaderAggregateDropdownContext,
|
||||
},
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
|
||||
+5
-4
@@ -1,4 +1,4 @@
|
||||
import { useDropdown } from '@/dropdown/hooks/useDropdown';
|
||||
import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { DateAggregateOperations } from '@/object-record/record-table/constants/DateAggregateOperations';
|
||||
import { RecordTableColumnAggregateFooterDropdownSubmenuContent } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateDropdownSubmenuContent';
|
||||
@@ -14,9 +14,10 @@ import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
export const RecordTableColumnAggregateFooterDropdownContent = () => {
|
||||
const { t } = useLingui();
|
||||
const { currentContentId, fieldMetadataType } = useDropdown({
|
||||
context: RecordTableColumnAggregateFooterDropdownContext,
|
||||
});
|
||||
const { currentContentId, fieldMetadataType } =
|
||||
useDropdownContextStateManagement({
|
||||
context: RecordTableColumnAggregateFooterDropdownContext,
|
||||
});
|
||||
|
||||
const availableAggregateOperations =
|
||||
getAvailableAggregateOperationsForFieldMetadataType({
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId';
|
||||
import { useDropdownContextCurrentContentId } from '@/dropdown-context-state-management/hooks/useDropdownContextCurrentContentId';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||
import { RecordTableColumnAggregateFooterDropdownContent } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent';
|
||||
@@ -19,7 +19,7 @@ export const RecordTableColumnFooterWithDropdown = ({
|
||||
isFirstCell,
|
||||
}: RecordTableColumnFooterWithDropdownProps) => {
|
||||
const { currentContentId, handleContentChange, handleResetContent } =
|
||||
useCurrentContentId<RecordTableFooterAggregateContentId>();
|
||||
useDropdownContextCurrentContentId<RecordTableFooterAggregateContentId>();
|
||||
|
||||
const { fieldMetadataId } = useContext(
|
||||
RecordTableColumnAggregateFooterCellContext,
|
||||
|
||||
+7
-4
@@ -2,7 +2,7 @@ import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record
|
||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -20,7 +20,7 @@ export const useOpenRecordFilterChipFromTableHeader = () => {
|
||||
|
||||
const { upsertRecordFilter } = useUpsertRecordFilter();
|
||||
|
||||
const { openDropdown } = useDropdownV2();
|
||||
const { openDropdown } = useOpenDropdown();
|
||||
|
||||
const { setEditableFilterChipDropdownStates } =
|
||||
useSetEditableFilterChipDropdownStates();
|
||||
@@ -45,7 +45,10 @@ export const useOpenRecordFilterChipFromTableHeader = () => {
|
||||
|
||||
if (isDefined(existingNonAdvancedRecordFilter)) {
|
||||
setEditableFilterChipDropdownStates(existingNonAdvancedRecordFilter);
|
||||
openDropdown(existingNonAdvancedRecordFilter.id);
|
||||
openDropdown({
|
||||
dropdownComponentInstanceIdFromProps:
|
||||
existingNonAdvancedRecordFilter.id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,7 +59,7 @@ export const useOpenRecordFilterChipFromTableHeader = () => {
|
||||
upsertRecordFilter(newRecordFilter);
|
||||
|
||||
setEditableFilterChipDropdownStates(newRecordFilter);
|
||||
openDropdown(newRecordFilter.id);
|
||||
openDropdown({ dropdownComponentInstanceIdFromProps: newRecordFilter.id });
|
||||
};
|
||||
|
||||
return { openRecordFilterChipFromTableHeader };
|
||||
|
||||
@@ -2,7 +2,7 @@ import { DropdownOnToggleEffect } from '@/ui/layout/dropdown/components/Dropdown
|
||||
import { DropdownInternalContainer } from '@/ui/layout/dropdown/components/internal/DropdownInternalContainer';
|
||||
import { DROPDOWN_RESIZE_MIN_HEIGHT } from '@/ui/layout/dropdown/constants/DropdownResizeMinHeight';
|
||||
import { DROPDOWN_RESIZE_MIN_WIDTH } from '@/ui/layout/dropdown/constants/DropdownResizeMinWidth';
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext';
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { dropdownMaxHeightComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState';
|
||||
import { dropdownMaxWidthComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState';
|
||||
|
||||
+19
-3
@@ -3,20 +3,36 @@ import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
|
||||
import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
const dropdownId = 'test-dropdown-id';
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
return <RecoilRoot>{children}</RecoilRoot>;
|
||||
return (
|
||||
<RecoilRoot>
|
||||
<DropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: dropdownId }}
|
||||
>
|
||||
{children}
|
||||
</DropdownComponentInstanceContext.Provider>
|
||||
</RecoilRoot>
|
||||
);
|
||||
};
|
||||
|
||||
describe('useCloseAnyOpenDropdown', () => {
|
||||
it('should open dropdown and then close it with closeAnyOpenDropdown', async () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { openDropdown, isDropdownOpen } = useDropdown(dropdownId);
|
||||
const isDropdownOpen = useRecoilComponentValueV2(
|
||||
isDropdownOpenComponentStateV2,
|
||||
dropdownId,
|
||||
);
|
||||
|
||||
const { openDropdown } = useOpenDropdown();
|
||||
|
||||
const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown();
|
||||
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import { expect } from '@storybook/test';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { useCloseDropdownFromOutside } from '@/ui/layout/dropdown/hooks/useCloseDropdownFromOutside';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
|
||||
const dropdownId = 'test-dropdown-id';
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
return <RecoilRoot>{children}</RecoilRoot>;
|
||||
};
|
||||
|
||||
describe('useCloseDropdownFromOutside', () => {
|
||||
it('should close open dropdown', async () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { isDropdownOpen, openDropdown } = useDropdown(dropdownId);
|
||||
const { closeDropdownFromOutside } = useCloseDropdownFromOutside();
|
||||
|
||||
return { closeDropdownFromOutside, isDropdownOpen, openDropdown };
|
||||
},
|
||||
{
|
||||
wrapper: Wrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.current.isDropdownOpen).toBe(false);
|
||||
|
||||
act(() => {
|
||||
result.current.openDropdown();
|
||||
});
|
||||
|
||||
expect(result.current.isDropdownOpen).toBe(true);
|
||||
|
||||
act(() => {
|
||||
result.current.closeDropdownFromOutside(dropdownId);
|
||||
});
|
||||
|
||||
expect(result.current.isDropdownOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
import { useCloseDropdownFromOutside } from '@/ui/layout/dropdown/hooks/useCloseDropdownFromOutside';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
|
||||
import { previousDropdownFocusIdState } from '@/ui/layout/dropdown/states/previousDropdownFocusIdState';
|
||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||
@@ -6,7 +6,7 @@ import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useCloseAnyOpenDropdown = () => {
|
||||
const { closeDropdownFromOutside } = useCloseDropdownFromOutside();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const { removeFocusItemFromFocusStackById } =
|
||||
useRemoveFocusItemFromFocusStackById();
|
||||
@@ -33,14 +33,14 @@ export const useCloseAnyOpenDropdown = () => {
|
||||
const thereIsOneNestedDropdownOpen = isDefined(previousDropdownFocusId);
|
||||
|
||||
if (isDefined(activeDropdownFocusId)) {
|
||||
closeDropdownFromOutside(activeDropdownFocusId);
|
||||
closeDropdown(activeDropdownFocusId);
|
||||
removeFocusItemFromFocusStackById({
|
||||
focusId: activeDropdownFocusId,
|
||||
});
|
||||
}
|
||||
|
||||
if (thereIsOneNestedDropdownOpen) {
|
||||
closeDropdownFromOutside(previousDropdownFocusId);
|
||||
closeDropdown(previousDropdownFocusId);
|
||||
removeFocusItemFromFocusStackById({
|
||||
focusId: previousDropdownFocusId,
|
||||
});
|
||||
@@ -49,7 +49,7 @@ export const useCloseAnyOpenDropdown = () => {
|
||||
set(previousDropdownFocusIdState, null);
|
||||
set(activeDropdownFocusIdState, null);
|
||||
},
|
||||
[closeDropdownFromOutside, removeFocusItemFromFocusStackById],
|
||||
[closeDropdown, removeFocusItemFromFocusStackById],
|
||||
);
|
||||
|
||||
return { closeAnyOpenDropdown };
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2';
|
||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useCloseDropdown = () => {
|
||||
const { goBackToPreviousDropdownFocusId } =
|
||||
useGoBackToPreviousDropdownFocusId();
|
||||
|
||||
const { removeFocusItemFromFocusStackById } =
|
||||
useRemoveFocusItemFromFocusStackById();
|
||||
|
||||
const dropdownComponentInstanceIdFromContext =
|
||||
useAvailableComponentInstanceId(DropdownComponentInstanceContext);
|
||||
|
||||
const closeDropdown = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(dropdownComponentInstanceIdFromProps?: string) => {
|
||||
const dropdownComponentInstanceId =
|
||||
dropdownComponentInstanceIdFromProps ??
|
||||
dropdownComponentInstanceIdFromContext;
|
||||
|
||||
if (!isDefined(dropdownComponentInstanceId)) {
|
||||
throw new Error('Dropdown component instance ID is not defined');
|
||||
}
|
||||
|
||||
const isDropdownOpen = snapshot
|
||||
.getLoadable(
|
||||
isDropdownOpenComponentStateV2.atomFamily({
|
||||
instanceId: dropdownComponentInstanceId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
const isDropdownOpenLegacy = snapshot
|
||||
.getLoadable(
|
||||
isDropdownOpenComponentState({
|
||||
scopeId: dropdownComponentInstanceId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (isDropdownOpen || isDropdownOpenLegacy) {
|
||||
removeFocusItemFromFocusStackById({
|
||||
focusId: dropdownComponentInstanceId,
|
||||
});
|
||||
|
||||
goBackToPreviousDropdownFocusId();
|
||||
|
||||
set(
|
||||
isDropdownOpenComponentStateV2.atomFamily({
|
||||
instanceId: dropdownComponentInstanceId,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
|
||||
set(
|
||||
isDropdownOpenComponentState({
|
||||
scopeId: dropdownComponentInstanceId,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
}
|
||||
},
|
||||
[
|
||||
removeFocusItemFromFocusStackById,
|
||||
goBackToPreviousDropdownFocusId,
|
||||
dropdownComponentInstanceIdFromContext,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
closeDropdown,
|
||||
};
|
||||
};
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useCloseDropdownFromOutside = () => {
|
||||
const closeDropdownFromOutside = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(dropdownId: string) => {
|
||||
set(isDropdownOpenComponentState({ scopeId: dropdownId }), false);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return { closeDropdownFromOutside };
|
||||
};
|
||||
@@ -10,6 +10,13 @@ import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysCo
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated This hook is deprecated, use a specific hook instead :
|
||||
* - `useOpenDropdown`
|
||||
* - `useCloseDropdown`
|
||||
* - `useToggleDropdown`
|
||||
*/
|
||||
export const useDropdown = (dropdownId?: string) => {
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
const { removeFocusItemFromFocusStackById } =
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
|
||||
export const useDropdownV2 = () => {
|
||||
const { goBackToPreviousDropdownFocusId } =
|
||||
useGoBackToPreviousDropdownFocusId();
|
||||
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const { removeFocusItemFromFocusStackById } =
|
||||
useRemoveFocusItemFromFocusStackById();
|
||||
|
||||
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
||||
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
||||
|
||||
const closeDropdown = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(specificComponentId: string) => {
|
||||
const scopeId = specificComponentId;
|
||||
|
||||
const isDropdownOpen = snapshot
|
||||
.getLoadable(isDropdownOpenComponentState({ scopeId }))
|
||||
.getValue();
|
||||
|
||||
if (isDropdownOpen) {
|
||||
removeFocusItemFromFocusStackById({
|
||||
focusId: scopeId,
|
||||
});
|
||||
goBackToPreviousDropdownFocusId();
|
||||
set(
|
||||
isDropdownOpenComponentState({
|
||||
scopeId,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
}
|
||||
},
|
||||
[removeFocusItemFromFocusStackById, goBackToPreviousDropdownFocusId],
|
||||
);
|
||||
|
||||
const openDropdown = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(
|
||||
specificComponentId: string,
|
||||
globalHotkeysConfig?: Partial<GlobalHotkeysConfig>,
|
||||
) => {
|
||||
const scopeId = specificComponentId;
|
||||
|
||||
set(
|
||||
isDropdownOpenComponentState({
|
||||
scopeId,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
|
||||
setActiveDropdownFocusIdAndMemorizePrevious(specificComponentId);
|
||||
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: scopeId,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: scopeId,
|
||||
},
|
||||
globalHotkeysConfig,
|
||||
// TODO: Remove this once we've fully migrated away from hotkey scopes
|
||||
hotkeyScope: { scope: 'dropdown' } as HotkeyScope,
|
||||
memoizeKey: 'global',
|
||||
});
|
||||
},
|
||||
[pushFocusItemToFocusStack, setActiveDropdownFocusIdAndMemorizePrevious],
|
||||
);
|
||||
|
||||
const toggleDropdown = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(
|
||||
specificComponentId: string,
|
||||
globalHotkeysConfig?: Partial<GlobalHotkeysConfig>,
|
||||
) => {
|
||||
const scopeId = specificComponentId;
|
||||
const isDropdownOpen = snapshot
|
||||
.getLoadable(isDropdownOpenComponentState({ scopeId }))
|
||||
.getValue();
|
||||
|
||||
if (isDropdownOpen) {
|
||||
closeDropdown(specificComponentId);
|
||||
} else {
|
||||
openDropdown(specificComponentId, globalHotkeysConfig);
|
||||
}
|
||||
},
|
||||
[closeDropdown, openDropdown],
|
||||
);
|
||||
|
||||
return {
|
||||
closeDropdown,
|
||||
openDropdown,
|
||||
toggleDropdown,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type OpenDropdownArgs = {
|
||||
dropdownComponentInstanceIdFromProps?: string;
|
||||
globalHotkeysConfig?: Partial<GlobalHotkeysConfig>;
|
||||
};
|
||||
|
||||
export const useOpenDropdown = () => {
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
||||
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
||||
const dropdownComponentInstanceIdFromContext =
|
||||
useAvailableComponentInstanceId(DropdownComponentInstanceContext);
|
||||
|
||||
const openDropdown = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(args?: OpenDropdownArgs | null | undefined) => {
|
||||
const dropdownComponentInstanceId =
|
||||
args?.dropdownComponentInstanceIdFromProps ??
|
||||
dropdownComponentInstanceIdFromContext;
|
||||
|
||||
if (!isDefined(dropdownComponentInstanceId)) {
|
||||
throw new Error('Dropdown component instance ID is not defined');
|
||||
}
|
||||
|
||||
set(
|
||||
isDropdownOpenComponentState({
|
||||
scopeId: dropdownComponentInstanceId,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
|
||||
set(
|
||||
isDropdownOpenComponentStateV2.atomFamily({
|
||||
instanceId: dropdownComponentInstanceId,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
|
||||
setActiveDropdownFocusIdAndMemorizePrevious(
|
||||
dropdownComponentInstanceId,
|
||||
);
|
||||
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: dropdownComponentInstanceId,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: dropdownComponentInstanceId,
|
||||
},
|
||||
globalHotkeysConfig: args?.globalHotkeysConfig ?? undefined,
|
||||
// TODO: Remove this once we've fully migrated away from hotkey scopes
|
||||
hotkeyScope: { scope: 'dropdown' } as HotkeyScope,
|
||||
memoizeKey: 'global',
|
||||
});
|
||||
},
|
||||
[
|
||||
pushFocusItemToFocusStack,
|
||||
setActiveDropdownFocusIdAndMemorizePrevious,
|
||||
dropdownComponentInstanceIdFromContext,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
openDropdown,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2';
|
||||
import { GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig';
|
||||
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useToggleDropdown = () => {
|
||||
const dropdownComponentInstanceIdFromContext =
|
||||
useAvailableComponentInstanceId(DropdownComponentInstanceContext);
|
||||
|
||||
const { openDropdown } = useOpenDropdown();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const toggleDropdown = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
({
|
||||
dropdownComponentInstanceIdFromProps,
|
||||
globalHotkeysConfig,
|
||||
}: {
|
||||
dropdownComponentInstanceIdFromProps?: string;
|
||||
globalHotkeysConfig?: Partial<GlobalHotkeysConfig>;
|
||||
}) => {
|
||||
const dropdownComponentInstanceId =
|
||||
dropdownComponentInstanceIdFromProps ??
|
||||
dropdownComponentInstanceIdFromContext;
|
||||
|
||||
if (!isDefined(dropdownComponentInstanceId)) {
|
||||
throw new Error('Dropdown component instance ID is not defined');
|
||||
}
|
||||
|
||||
const isDropdownOpen = snapshot
|
||||
.getLoadable(
|
||||
isDropdownOpenComponentStateV2.atomFamily({
|
||||
instanceId: dropdownComponentInstanceId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
const isDropdownOpenLegacy = snapshot
|
||||
.getLoadable(
|
||||
isDropdownOpenComponentState({
|
||||
scopeId: dropdownComponentInstanceId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (isDropdownOpen || isDropdownOpenLegacy) {
|
||||
closeDropdown(dropdownComponentInstanceId);
|
||||
} else {
|
||||
openDropdown({
|
||||
dropdownComponentInstanceIdFromProps: dropdownComponentInstanceId,
|
||||
globalHotkeysConfig,
|
||||
});
|
||||
}
|
||||
},
|
||||
[closeDropdown, openDropdown, dropdownComponentInstanceIdFromContext],
|
||||
);
|
||||
|
||||
return {
|
||||
toggleDropdown,
|
||||
};
|
||||
};
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
import { createState } from 'twenty-ui/utilities';
|
||||
|
||||
export const activeDropdownFocusIdState = createState<string | null>({
|
||||
key: 'activeDropdownFocusIdState',
|
||||
defaultValue: null,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext';
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
|
||||
export const dropdownMaxHeightComponentState = createComponentStateV2<
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponeInstanceContext';
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
|
||||
export const dropdownMaxWidthComponentState = createComponentStateV2<
|
||||
|
||||
+3
@@ -1,5 +1,8 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
/**
|
||||
* @deprecated Use `isDropdownOpenComponentStateV2` instead.
|
||||
*/
|
||||
export const isDropdownOpenComponentState = createComponentState<boolean>({
|
||||
key: 'isDropdownOpenComponentState',
|
||||
defaultValue: false,
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
|
||||
export const isDropdownOpenComponentStateV2 = createComponentStateV2<boolean>({
|
||||
key: 'isDropdownOpenComponentStateV2',
|
||||
defaultValue: false,
|
||||
componentInstanceContext: DropdownComponentInstanceContext,
|
||||
});
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
import { createState } from 'twenty-ui/utilities';
|
||||
|
||||
export const previousDropdownFocusIdState = createState<string | null>({
|
||||
key: 'previousDropdownFocusIdState',
|
||||
defaultValue: null,
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
import { ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
export const useAvailableComponentInstanceId = <
|
||||
T extends { instanceId: string },
|
||||
>(
|
||||
Context: ComponentInstanceStateContext<T>,
|
||||
): string | null => {
|
||||
const instanceStateContext = useComponentInstanceStateContext(Context);
|
||||
|
||||
const instanceIdFromContext = instanceStateContext?.instanceId;
|
||||
|
||||
if (isNonEmptyString(instanceIdFromContext)) {
|
||||
return instanceIdFromContext;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerKanbanFieldDropdownId';
|
||||
@@ -17,7 +17,7 @@ export const useCloseAndResetViewPicker = () => {
|
||||
viewPickerIsPersistingComponentState,
|
||||
);
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const closeAndResetViewPicker = useCallback(() => {
|
||||
setViewPickerIsPersisting(false);
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import { WorkflowVariablesDropdownFieldItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems';
|
||||
@@ -51,7 +51,7 @@ export const WorkflowVariablesDropdown = ({
|
||||
const isDropdownOpen = useRecoilValue(
|
||||
extractComponentState(isDropdownOpenComponentState, dropdownId),
|
||||
);
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
const availableVariablesInWorkflowStep = useAvailableVariablesInWorkflowStep({
|
||||
objectNameSingularToSelect,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user