Replaced useDropdown calls by useCloseDropdown, useOpenDropdown and useToggleDropdown (#12958)

This PR replaces the many calls of useDropdown by the new standalone
hooks : useCloseDropdown, useOpenDropdown and useToggleDropdown.

This will allow to remove useDropdown and then the dropdown recoil
component state v1.

A big round of QA has been made, with some bugs caught along the way.

Closes https://github.com/twentyhq/core-team-issues/issues/1155
Closes https://github.com/twentyhq/core-team-issues/issues/618

## QA

Component|Status|Comment
|---|---|---|
CurrentWorkspaceMemberFavorites|Ok|
FavoriteFolderPickerFooter|Ok|
AdvancedFilterAddFilterRuleSelect|Ok|
AdvancedFilterRecordFilterGroupOptionsDropdown|Ok|
AdvancedFilterRecordFilterOperandSelectContent|Ok|
AdvancedFilterRecordFilterOptionsDropdown|Ok|
useAdvancedFilterFieldSelectDropdown|Ok|
ObjectFilterDropdownBooleanSelect|Ok|
ObjectFilterDropdownOptionSelect|Ok|
ObjectOptionsDropdown|Ok|
ObjectOptionsDropdownLayoutContent|Ok|
ObjectSortDropdownButton|Ok|
useCloseSortDropdown|Ok|
FormDateTimeFieldInput|Ok|Bug detected, cannot select a month or a year,
see issue https://github.com/twentyhq/twenty/issues/12922
FormSingleRecordPicker|Ok|
MultiItemFieldMenuItem|Ok|
RecordDetailRelationRecordsListItem|Ok|
RecordDetailRelationSection|Ok|
RecordDetailRelationSectionDropdownToMany|Ok|
RecordDetailRelationSectionDropdownToOne|Ok|
RecordTableColumnAggregateFooterDropdownSubmenuContent|Ok|
RecordTableColumnAggregateFooterAggregateOperationMenuItems|Ok|
RecordTableColumnAggregateFooterMenuContent|Ok|
RecordTableColumnAggregateFooterValueCell|Ok|
RecordTableColumnHeadDropdownMenu|Ok|
RecordTableHeaderPlusButtonContent|Ok|
useTriggerActionMenuDropdown|Ok|
MultipleSelectDropdown|Ok|
RecordBoardColumnHeaderAggregateDropdownButton|Ok|
SettingsDataModelFieldSelectFormOptionRow|Ok|
SettingsDataModelNewFieldBreadcrumbDropDown|Ok|
SettingsObjectFieldActiveActionDropdown|Ok|
SettingsObjectFieldInactiveActionDropdown|Ok|
SettingsObjectInactiveMenuDropDown|Ok|
SettingsSecurityApprovedAccessDomainRowDropdownMenu|Couldn’t test|
SettingsSecuritySSORowDropdownMenu|Couldn’t test|
SettingsAccountsRowDropdownMenu|Ok|
SettingsRoleAssignment|Ok|
SettingsServerlessFunctionTabEnvironmentVariableTableRow|Couldn’t test|
MatchColumnToFieldSelect|Ok|
SubMatchingSelectDropdownButton|Ok|Removed conflicting duplicate open
dropdown
SubMatchingSelectRowRightDropdown|Ok|
CurrencyPickerDropdownButton|Ok|
IconPicker|Ok|
DateTimePicker|Ok|
PhoneCountryPickerDropdownButton|OK|
Select|Ok|
Dropdown|Ok|Not QAing all dropdowns in the app because the ones of this
QA are enough to show up that Dropdown is behaving correctly on a lot of
use cases
DropdownMenuInnerSelect|Ok|
TabList|Ok|Removed onClickOutside called in dropdown clickable
component, validated with Raph who recently worked on this
DateInput|Ok|
MultiWorkspaceDropdownDefaultComponents|Ok|
AdvancedFilterChip|Ok|
EditableFilterDropdownButton|Ok|
UpdateViewButtonGroup|Ok|
ViewBarDetailsAddFilterButton|Ok|
ViewBarFilterButton|Ok|
ViewBarFilterDropdown|Ok|
ViewBarFilterDropdownAdvancedFilterButton|Ok|
ViewPickerDropdown|Ok|
ViewPickerListContent|Ok|
ViewPickerOptionDropdown|Ok|
WorkflowEditTriggerDatabaseEventForm|Ok|
WorkflowVariablesDropdownWorkflowStepItems|Ok|
AttachmentDropdown|Ok|
SupportDropdown|Ok|

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2025-07-02 18:38:45 +02:00
committed by GitHub
parent a19a73a977
commit a7b9a0710e
70 changed files with 352 additions and 426 deletions

View File

@ -9,7 +9,7 @@ import { SOFT_DELETE_FILTER_FIELD_NAME } from '@/object-record/record-filter/con
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
import { getAllRecordFilterDescendantsOfRecordFilterGroup } from '@/object-record/record-filter/utils/getAllRecordFilterDescendantsOfRecordFilterGroup';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
@ -19,7 +19,7 @@ import { isDefined } from 'twenty-shared/utils';
import { IconFilter } from 'twenty-ui/display';
export const AdvancedFilterChip = () => {
const { closeDropdown } = useDropdown(ADVANCED_FILTER_DROPDOWN_ID);
const { closeDropdown } = useCloseDropdown();
const currentRecordFilterGroups = useRecoilComponentValueV2(
currentRecordFilterGroupsComponentState,
@ -49,7 +49,7 @@ export const AdvancedFilterChip = () => {
});
const handleRemoveClick = () => {
closeDropdown();
closeDropdown(ADVANCED_FILTER_DROPDOWN_ID);
const viewFilterGroupIds = currentRecordFilterGroups.map(
(recordFilterGroup) => recordFilterGroup.id,

View File

@ -2,12 +2,12 @@ import { useCallback } from 'react';
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { EditableFilterChip } from '@/views/components/EditableFilterChip';
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates';
type EditableFilterDropdownButtonProps = {
@ -17,12 +17,14 @@ type EditableFilterDropdownButtonProps = {
export const EditableFilterDropdownButton = ({
recordFilter,
}: EditableFilterDropdownButtonProps) => {
const { closeDropdown } = useDropdown(recordFilter.id);
const dropdownId = recordFilter.id;
const { closeDropdown } = useCloseDropdown();
const { removeRecordFilter } = useRemoveRecordFilter();
const handleRemove = () => {
closeDropdown();
closeDropdown(dropdownId);
removeRecordFilter({ recordFilterId: recordFilter.id });
};

View File

@ -4,7 +4,8 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/
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 { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
@ -43,12 +44,8 @@ export const UpdateViewButtonGroup = () => {
contextStoreCurrentViewIdComponentState,
);
const { closeDropdown: closeUpdateViewButtonDropdown } = useDropdown(
UPDATE_VIEW_BUTTON_DROPDOWN_ID,
);
const { openDropdown: openViewPickerDropdown } = useDropdown(
VIEW_PICKER_DROPDOWN_ID,
);
const { closeDropdown: closeUpdateViewButtonDropdown } = useCloseDropdown();
const { openDropdown: openViewPickerDropdown } = useOpenDropdown();
const { currentView } = useGetCurrentViewOnly();
const setViewPickerReferenceViewId = useSetRecoilComponentStateV2(
@ -60,11 +57,13 @@ export const UpdateViewButtonGroup = () => {
return;
}
openViewPickerDropdown();
openViewPickerDropdown({
dropdownComponentInstanceIdFromProps: VIEW_PICKER_DROPDOWN_ID,
});
setViewPickerReferenceViewId(currentViewId);
setViewPickerMode('create-from-current');
closeUpdateViewButtonDropdown();
closeUpdateViewButtonDropdown(UPDATE_VIEW_BUTTON_DROPDOWN_ID);
};
const handleCreateViewClick = () => {

View File

@ -1,13 +1,13 @@
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown';
import { t } from '@lingui/core/macro';
import { IconPlus } from 'twenty-ui/display';
import { LightButton } from 'twenty-ui/input';
export const ViewBarDetailsAddFilterButton = () => {
const { toggleDropdown } = useDropdown(VIEW_BAR_FILTER_DROPDOWN_ID);
const { toggleDropdown } = useToggleDropdown();
const { resetFilterDropdown } = useResetFilterDropdown(
VIEW_BAR_FILTER_DROPDOWN_ID,
@ -15,7 +15,9 @@ export const ViewBarDetailsAddFilterButton = () => {
const handleClick = () => {
resetFilterDropdown();
toggleDropdown();
toggleDropdown({
dropdownComponentInstanceIdFromProps: VIEW_BAR_FILTER_DROPDOWN_ID,
});
};
return (

View File

@ -1,10 +1,14 @@
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { isDropdownOpenComponentStateV2 } from '@/ui/layout/dropdown/states/isDropdownOpenComponentStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { Trans } from '@lingui/react/macro';
export const ViewBarFilterButton = () => {
const { isDropdownOpen } = useDropdown(VIEW_BAR_FILTER_DROPDOWN_ID);
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentStateV2,
VIEW_BAR_FILTER_DROPDOWN_ID,
);
return (
<StyledHeaderDropdownButton isUnfolded={isDropdownOpen}>

View File

@ -3,7 +3,6 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
import { useVectorSearchFilterActions } from '@/views/hooks/useVectorSearchFilterActions';
import { OPERAND_DROPDOWN_CLICK_OUTSIDE_ID } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandDropdown';
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
@ -53,7 +52,6 @@ export const ViewBarFilterDropdown = () => {
dropdownComponents={<ViewBarFilterDropdownContent />}
dropdownOffset={{ y: 8 }}
onClickOutside={handleDropdownClickOutside}
excludedClickOutsideIds={[OPERAND_DROPDOWN_CLICK_OUTSIDE_ID]}
/>
);
};

View File

@ -12,7 +12,8 @@ import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDrop
import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow';
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
@ -40,13 +41,9 @@ export const ViewBarFilterDropdownAdvancedFilterButton = () => {
VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS.ADVANCED_FILTER,
);
const { openDropdown: openAdvancedFilterDropdown } = useDropdown(
ADVANCED_FILTER_DROPDOWN_ID,
);
const { openDropdown: openAdvancedFilterDropdown } = useOpenDropdown();
const { closeDropdown: closeObjectFilterDropdown } = useDropdown(
VIEW_BAR_FILTER_DROPDOWN_ID,
);
const { closeDropdown: closeObjectFilterDropdown } = useCloseDropdown();
const { currentView } = useGetCurrentViewOnly();
@ -118,8 +115,10 @@ export const ViewBarFilterDropdownAdvancedFilterButton = () => {
setRecordFilterUsedInAdvancedFilterDropdownRow(newRecordFilter);
}
closeObjectFilterDropdown();
openAdvancedFilterDropdown();
closeObjectFilterDropdown(VIEW_BAR_FILTER_DROPDOWN_ID);
openAdvancedFilterDropdown({
dropdownComponentInstanceIdFromProps: ADVANCED_FILTER_DROPDOWN_ID,
});
};
return (