5922 - UI Overlap and State Persistence in Filter Menus (#7270)

fixes #5922 


https://github.com/user-attachments/assets/07d088da-cefb-4d87-9016-e14cef18567d
This commit is contained in:
nitin
2024-09-27 17:50:21 +05:30
committed by GitHub
parent c4762c3921
commit ca906bbf6b
5 changed files with 154 additions and 117 deletions

View File

@ -2,6 +2,7 @@ import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdow
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useCallback } from 'react';
import { MultipleFiltersButton } from './MultipleFiltersButton'; import { MultipleFiltersButton } from './MultipleFiltersButton';
import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent'; import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent';
@ -13,12 +14,18 @@ type MultipleFiltersDropdownButtonProps = {
export const MultipleFiltersDropdownButton = ({ export const MultipleFiltersDropdownButton = ({
hotkeyScope, hotkeyScope,
}: MultipleFiltersDropdownButtonProps) => { }: MultipleFiltersDropdownButtonProps) => {
const { resetFilter } = useFilterDropdown(); const { resetFilter, setIsObjectFilterDropdownOperandSelectUnfolded } =
useFilterDropdown();
const handleDropdownClose = useCallback(() => {
resetFilter();
setIsObjectFilterDropdownOperandSelectUnfolded(false);
}, [resetFilter, setIsObjectFilterDropdownOperandSelectUnfolded]);
return ( return (
<Dropdown <Dropdown
dropdownId={OBJECT_FILTER_DROPDOWN_ID} dropdownId={OBJECT_FILTER_DROPDOWN_ID}
onClose={resetFilter} onClose={handleDropdownClose}
clickableComponent={<MultipleFiltersButton />} clickableComponent={<MultipleFiltersButton />}
dropdownComponents={<MultipleFiltersDropdownContent />} dropdownComponents={<MultipleFiltersDropdownContent />}
dropdownHotkeyScope={hotkeyScope} dropdownHotkeyScope={hotkeyScope}

View File

@ -1,11 +1,9 @@
import { useRecoilValue } from 'recoil'; import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput'; import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import styled from '@emotion/styled';
import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput'; import { useRecoilValue } from 'recoil';
import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect'; import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect';
import { ObjectFilterDropdownDateInput } from './ObjectFilterDropdownDateInput'; import { ObjectFilterDropdownDateInput } from './ObjectFilterDropdownDateInput';
import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect'; import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect';
@ -16,6 +14,21 @@ import { ObjectFilterDropdownOptionSelect } from './ObjectFilterDropdownOptionSe
import { ObjectFilterDropdownRecordSelect } from './ObjectFilterDropdownRecordSelect'; import { ObjectFilterDropdownRecordSelect } from './ObjectFilterDropdownRecordSelect';
import { ObjectFilterDropdownTextSearchInput } from './ObjectFilterDropdownTextSearchInput'; import { ObjectFilterDropdownTextSearchInput } from './ObjectFilterDropdownTextSearchInput';
const StyledContainer = styled.div`
position: relative;
`;
const StyledOperandSelectContainer = styled.div`
background: ${({ theme }) => theme.background.secondary};
box-shadow: ${({ theme }) => theme.boxShadow.light};
border-radius: ${({ theme }) => theme.border.radius.md};
left: 10px;
position: absolute;
top: 10px;
width: 100%;
z-index: 1000;
`;
type MultipleFiltersDropdownContentProps = { type MultipleFiltersDropdownContentProps = {
filterDropdownId?: string; filterDropdownId?: string;
}; };
@ -24,20 +37,23 @@ export const MultipleFiltersDropdownContent = ({
filterDropdownId, filterDropdownId,
}: MultipleFiltersDropdownContentProps) => { }: MultipleFiltersDropdownContentProps) => {
const { const {
isObjectFilterDropdownOperandSelectUnfoldedState,
filterDefinitionUsedInDropdownState, filterDefinitionUsedInDropdownState,
selectedOperandInDropdownState, selectedOperandInDropdownState,
isObjectFilterDropdownOperandSelectUnfoldedState,
} = useFilterDropdown({ filterDropdownId }); } = useFilterDropdown({ filterDropdownId });
const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue( const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue(
isObjectFilterDropdownOperandSelectUnfoldedState, isObjectFilterDropdownOperandSelectUnfoldedState,
); );
const filterDefinitionUsedInDropdown = useRecoilValue( const filterDefinitionUsedInDropdown = useRecoilValue(
filterDefinitionUsedInDropdownState, filterDefinitionUsedInDropdownState,
); );
const selectedOperandInDropdown = useRecoilValue( const selectedOperandInDropdown = useRecoilValue(
selectedOperandInDropdownState, selectedOperandInDropdownState,
); );
const isEmptyOperand = const isEmptyOperand =
selectedOperandInDropdown && selectedOperandInDropdown &&
[ViewFilterOperand.IsEmpty, ViewFilterOperand.IsNotEmpty].includes( [ViewFilterOperand.IsEmpty, ViewFilterOperand.IsNotEmpty].includes(
@ -45,18 +61,19 @@ export const MultipleFiltersDropdownContent = ({
); );
return ( return (
<> <StyledContainer>
{!filterDefinitionUsedInDropdown ? ( {!filterDefinitionUsedInDropdown ? (
<ObjectFilterDropdownFilterSelect /> <ObjectFilterDropdownFilterSelect />
) : isObjectFilterDropdownOperandSelectUnfolded ? (
<ObjectFilterDropdownOperandSelect />
) : isEmptyOperand ? (
<ObjectFilterDropdownOperandButton />
) : ( ) : (
selectedOperandInDropdown && (
<> <>
<ObjectFilterDropdownOperandButton /> <ObjectFilterDropdownOperandButton />
<DropdownMenuSeparator /> {isObjectFilterDropdownOperandSelectUnfolded && (
<StyledOperandSelectContainer>
<ObjectFilterDropdownOperandSelect />
</StyledOperandSelectContainer>
)}
{!isEmptyOperand && selectedOperandInDropdown && (
<>
{[ {[
'TEXT', 'TEXT',
'EMAIL', 'EMAIL',
@ -84,25 +101,24 @@ export const MultipleFiltersDropdownContent = ({
{filterDefinitionUsedInDropdown.type === 'RELATION' && ( {filterDefinitionUsedInDropdown.type === 'RELATION' && (
<> <>
<ObjectFilterDropdownSearchInput /> <ObjectFilterDropdownSearchInput />
<DropdownMenuSeparator />
<ObjectFilterDropdownRecordSelect /> <ObjectFilterDropdownRecordSelect />
</> </>
)} )}
{filterDefinitionUsedInDropdown.type === 'SELECT' && ( {filterDefinitionUsedInDropdown.type === 'SELECT' && (
<> <>
<ObjectFilterDropdownSearchInput /> <ObjectFilterDropdownSearchInput />
<DropdownMenuSeparator />
<ObjectFilterDropdownOptionSelect /> <ObjectFilterDropdownOptionSelect />
</> </>
)} )}
</> </>
) )}
</>
)} )}
<MultipleFiltersDropdownFilterOnFilterChangedEffect <MultipleFiltersDropdownFilterOnFilterChangedEffect
filterDefinitionUsedInDropdownType={ filterDefinitionUsedInDropdownType={
filterDefinitionUsedInDropdown?.type filterDefinitionUsedInDropdown?.type
} }
/> />
</> </StyledContainer>
); );
}; };

View File

@ -10,19 +10,11 @@ export const ObjectFilterDropdownOperandButton = () => {
const { const {
selectedOperandInDropdownState, selectedOperandInDropdownState,
setIsObjectFilterDropdownOperandSelectUnfolded, setIsObjectFilterDropdownOperandSelectUnfolded,
isObjectFilterDropdownOperandSelectUnfoldedState,
} = useFilterDropdown(); } = useFilterDropdown();
const selectedOperandInDropdown = useRecoilValue( const selectedOperandInDropdown = useRecoilValue(
selectedOperandInDropdownState, selectedOperandInDropdownState,
); );
const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue(
isObjectFilterDropdownOperandSelectUnfoldedState,
);
if (isObjectFilterDropdownOperandSelectUnfolded) {
return null;
}
return ( return (
<DropdownMenuHeader <DropdownMenuHeader

View File

@ -39,6 +39,21 @@ export const StyledInput = styled.input`
} }
`; `;
const StyledContainer = styled.div`
position: relative;
`;
const StyledSelectedSortDirectionContainer = styled.div`
background: ${({ theme }) => theme.background.secondary};
box-shadow: ${({ theme }) => theme.boxShadow.light};
border-radius: ${({ theme }) => theme.border.radius.md};
left: 10px;
position: absolute;
top: 10px;
width: 100%;
z-index: 1000;
`;
export type ObjectSortDropdownButtonProps = { export type ObjectSortDropdownButtonProps = {
sortDropdownId: string; sortDropdownId: string;
hotkeyScope: HotkeyScope; hotkeyScope: HotkeyScope;
@ -95,7 +110,8 @@ export const ObjectSortDropdownButton = ({
} }
dropdownComponents={ dropdownComponents={
<> <>
{isSortDirectionMenuUnfolded ? ( {isSortDirectionMenuUnfolded && (
<StyledSelectedSortDirectionContainer>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
{SORT_DIRECTIONS.map((sortOrder, index) => ( {SORT_DIRECTIONS.map((sortOrder, index) => (
<MenuItem <MenuItem
@ -108,8 +124,9 @@ export const ObjectSortDropdownButton = ({
/> />
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
) : ( </StyledSelectedSortDirectionContainer>
<> )}
<StyledContainer>
<DropdownMenuHeader <DropdownMenuHeader
EndIcon={IconChevronDown} EndIcon={IconChevronDown}
onClick={() => setIsSortDirectionMenuUnfolded(true)} onClick={() => setIsSortDirectionMenuUnfolded(true)}
@ -147,8 +164,7 @@ export const ObjectSortDropdownButton = ({
/> />
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</> </StyledContainer>
)}
</> </>
} }
onClose={handleDropdownButtonClose} onClose={handleDropdownButtonClose}

View File

@ -29,6 +29,7 @@ export const EditableFilterDropdownButton = ({
setFilterDefinitionUsedInDropdown, setFilterDefinitionUsedInDropdown,
setSelectedOperandInDropdown, setSelectedOperandInDropdown,
setSelectedFilter, setSelectedFilter,
setIsObjectFilterDropdownOperandSelectUnfolded,
} = useFilterDropdown({ } = useFilterDropdown({
filterDropdownId: viewFilterDropdownId, filterDropdownId: viewFilterDropdownId,
}); });
@ -79,6 +80,10 @@ export const EditableFilterDropdownButton = ({
} }
}, [viewFilter, deleteCombinedViewFilter]); }, [viewFilter, deleteCombinedViewFilter]);
const handleDropdownClose = useCallback(() => {
setIsObjectFilterDropdownOperandSelectUnfolded(false);
}, [setIsObjectFilterDropdownOperandSelectUnfolded]);
return ( return (
<Dropdown <Dropdown
dropdownId={viewFilterDropdownId} dropdownId={viewFilterDropdownId}
@ -94,6 +99,7 @@ export const EditableFilterDropdownButton = ({
dropdownOffset={{ y: 8, x: 0 }} dropdownOffset={{ y: 8, x: 0 }}
dropdownPlacement="bottom-start" dropdownPlacement="bottom-start"
onClickOutside={handleDropdownClickOutside} onClickOutside={handleDropdownClickOutside}
onClose={handleDropdownClose}
/> />
); );
}; };