Fixed minor bugs on advanced filters (#10847)
This PR fixes minor bugs on advanced filters : - We couldn't close the advanced filter dropdown after removing a rule, because the rule options dropdown wasn't closed, so focus dropdown id was in a corrupted state. - The text filter input in filter dropdown and the search input were the same component, which was causing conflicts with state management but this conflict didn't happen with the simple filter dropdown implementation, the advanced filter dropdown brought this bug to light. - The chevron down icon disappeared from the filter update button group, this PR fixes it. Fixes https://github.com/twentyhq/core-team-issues/issues/557 Fixes https://github.com/twentyhq/core-team-issues/issues/558
This commit is contained in:
@ -4,6 +4,7 @@ import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRe
|
||||
|
||||
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 { IconButton, IconDotsVertical, MenuItem } from 'twenty-ui';
|
||||
|
||||
type AdvancedFilterRecordFilterGroupOptionsDropdownProps = {
|
||||
@ -15,6 +16,8 @@ export const AdvancedFilterRecordFilterGroupOptionsDropdown = ({
|
||||
}: AdvancedFilterRecordFilterGroupOptionsDropdownProps) => {
|
||||
const dropdownId = `advanced-filter-record-filter-group-options-${recordFilterGroupId}`;
|
||||
|
||||
const { closeDropdown } = useDropdown(dropdownId);
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
const { removeRecordFilterGroup } = useRemoveRecordFilterGroup();
|
||||
|
||||
@ -28,6 +31,8 @@ export const AdvancedFilterRecordFilterGroupOptionsDropdown = ({
|
||||
}
|
||||
|
||||
removeRecordFilterGroup(recordFilterGroupId);
|
||||
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -6,6 +6,7 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
|
||||
|
||||
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { IconButton, IconDotsVertical, MenuItem } from 'twenty-ui';
|
||||
@ -19,6 +20,8 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({
|
||||
}: AdvancedFilterRecordFilterOptionsDropdownProps) => {
|
||||
const dropdownId = `advanced-filter-record-filter-options-${recordFilterId}`;
|
||||
|
||||
const { closeDropdown } = useDropdown(dropdownId);
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
const { removeRecordFilterGroup } = useRemoveRecordFilterGroup();
|
||||
|
||||
@ -36,7 +39,7 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({
|
||||
});
|
||||
|
||||
const handleRemove = async () => {
|
||||
removeRecordFilter({ recordFilterId: recordFilterId });
|
||||
closeDropdown();
|
||||
|
||||
if (isDefined(currentRecordFilter?.recordFilterGroupId)) {
|
||||
const isOnlyViewFilterInGroup =
|
||||
@ -46,6 +49,8 @@ export const AdvancedFilterRecordFilterOptionsDropdown = ({
|
||||
removeRecordFilterGroup(currentRecordFilter.recordFilterGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
removeRecordFilter({ recordFilterId: recordFilterId });
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -5,13 +5,13 @@ import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-d
|
||||
import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect';
|
||||
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
|
||||
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
|
||||
import { ObjectFilterDropdownTextSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
||||
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
||||
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||
import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes';
|
||||
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
||||
@ -75,9 +75,7 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
{isConfigurable && selectedOperandInDropdown && (
|
||||
<>
|
||||
{TEXT_FILTER_TYPES.includes(filterType) &&
|
||||
!isActorSourceCompositeFilter && (
|
||||
<ObjectFilterDropdownTextSearchInput />
|
||||
)}
|
||||
!isActorSourceCompositeFilter && <ObjectFilterDropdownTextInput />}
|
||||
{NUMBER_FILTER_TYPES.includes(filterType) && (
|
||||
<ObjectFilterDropdownNumberInput />
|
||||
)}
|
||||
|
||||
@ -27,6 +27,7 @@ import { advancedFilterViewFilterIdComponentState } from '@/object-record/object
|
||||
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';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
@ -65,17 +66,12 @@ export const ObjectFilterDropdownFilterSelect = ({
|
||||
}: ObjectFilterDropdownFilterSelectProps) => {
|
||||
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||
|
||||
const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
|
||||
const advancedFilterViewFilterId = useRecoilComponentValueV2(
|
||||
advancedFilterViewFilterIdComponentState,
|
||||
);
|
||||
|
||||
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
const [objectFilterDropdownSearchInput, setObjectFilterDropdownSearchInput] =
|
||||
useRecoilComponentStateV2(objectFilterDropdownSearchInputComponentState);
|
||||
|
||||
const { closeAdvancedFilterDropdown } = useAdvancedFilterDropdown(
|
||||
advancedFilterViewFilterId,
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
import { ChangeEvent, useCallback, useState } from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const ObjectFilterDropdownTextInput = () => {
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
|
||||
const [hasFocused, setHasFocused] = useState(false);
|
||||
|
||||
const [inputValue, setInputValue] = useState(
|
||||
() => selectedFilter?.value || '',
|
||||
);
|
||||
|
||||
const handleInputRef = useCallback(
|
||||
(node: HTMLInputElement | null) => {
|
||||
if (Boolean(node) && !hasFocused) {
|
||||
node?.focus();
|
||||
node?.select();
|
||||
setHasFocused(true);
|
||||
}
|
||||
},
|
||||
[hasFocused],
|
||||
);
|
||||
|
||||
return (
|
||||
fieldMetadataItemUsedInDropdown &&
|
||||
selectedOperandInDropdown && (
|
||||
<DropdownMenuInput
|
||||
ref={handleInputRef}
|
||||
value={inputValue}
|
||||
autoFocus
|
||||
type="text"
|
||||
placeholder={fieldMetadataItemUsedInDropdown.label}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
|
||||
setInputValue(newValue);
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '',
|
||||
value: newValue,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: newValue,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
@ -2,6 +2,7 @@ import styled from '@emotion/styled';
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
IconButton,
|
||||
IconChevronDown,
|
||||
IconPlus,
|
||||
MenuItem,
|
||||
@ -32,9 +33,7 @@ const StyledContainer = styled.div`
|
||||
margin-right: ${({ theme }) => theme.spacing(2)};
|
||||
position: relative;
|
||||
`;
|
||||
const StyledButton = styled(Button)`
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
export type UpdateViewButtonGroupProps = {
|
||||
hotkeyScope: HotkeyScope;
|
||||
};
|
||||
@ -116,7 +115,7 @@ export const UpdateViewButtonGroup = ({
|
||||
dropdownId={UPDATE_VIEW_BUTTON_DROPDOWN_ID}
|
||||
dropdownHotkeyScope={hotkeyScope}
|
||||
clickableComponent={
|
||||
<StyledButton
|
||||
<IconButton
|
||||
size="small"
|
||||
accent="blue"
|
||||
Icon={IconChevronDown}
|
||||
|
||||
Reference in New Issue
Block a user