fix: filter and sort options to match order of table columns (#7392)
### ISSUE - Closes #5960 ### Demo https://github.com/user-attachments/assets/279b19cf-6841-4a63-82ed-423bc0eb4395 --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -1,38 +1,19 @@
|
|||||||
import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
|
|
||||||
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 { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
|
||||||
|
|
||||||
import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect';
|
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
|
||||||
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
|
import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu';
|
||||||
import { ObjectFilterDropdownTextSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput';
|
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||||
import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter';
|
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect';
|
import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect';
|
||||||
import { ObjectFilterDropdownDateInput } from './ObjectFilterDropdownDateInput';
|
|
||||||
import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect';
|
import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect';
|
||||||
import { ObjectFilterDropdownNumberInput } from './ObjectFilterDropdownNumberInput';
|
|
||||||
import { ObjectFilterDropdownOperandButton } from './ObjectFilterDropdownOperandButton';
|
|
||||||
import { ObjectFilterDropdownOperandSelect } from './ObjectFilterDropdownOperandSelect';
|
|
||||||
import { ObjectFilterDropdownOptionSelect } from './ObjectFilterDropdownOptionSelect';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
position: relative;
|
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;
|
||||||
};
|
};
|
||||||
@ -40,99 +21,38 @@ type MultipleFiltersDropdownContentProps = {
|
|||||||
export const MultipleFiltersDropdownContent = ({
|
export const MultipleFiltersDropdownContent = ({
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
}: MultipleFiltersDropdownContentProps) => {
|
}: MultipleFiltersDropdownContentProps) => {
|
||||||
const {
|
const { filterDefinitionUsedInDropdownState } = useFilterDropdown({
|
||||||
filterDefinitionUsedInDropdownState,
|
filterDropdownId,
|
||||||
selectedOperandInDropdownState,
|
});
|
||||||
isObjectFilterDropdownOperandSelectUnfoldedState,
|
|
||||||
} = useFilterDropdown({ filterDropdownId });
|
|
||||||
|
|
||||||
const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue(
|
const [objectFilterDropdownIsSelectingCompositeField] =
|
||||||
isObjectFilterDropdownOperandSelectUnfoldedState,
|
useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
||||||
|
filterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [objectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownFilterIsSelectedComponentState,
|
||||||
|
filterDropdownId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const filterDefinitionUsedInDropdown = useRecoilValue(
|
const filterDefinitionUsedInDropdown = useRecoilValue(
|
||||||
filterDefinitionUsedInDropdownState,
|
filterDefinitionUsedInDropdownState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedOperandInDropdown = useRecoilValue(
|
const shouldShowCompositeSelectionSubMenu =
|
||||||
selectedOperandInDropdownState,
|
objectFilterDropdownIsSelectingCompositeField;
|
||||||
);
|
|
||||||
|
|
||||||
const isConfigurable =
|
const shoudShowFilterInput = objectFilterDropdownFilterIsSelected;
|
||||||
selectedOperandInDropdown &&
|
|
||||||
[
|
|
||||||
ViewFilterOperand.Is,
|
|
||||||
ViewFilterOperand.IsNotNull,
|
|
||||||
ViewFilterOperand.IsNot,
|
|
||||||
ViewFilterOperand.LessThan,
|
|
||||||
ViewFilterOperand.GreaterThan,
|
|
||||||
ViewFilterOperand.IsBefore,
|
|
||||||
ViewFilterOperand.IsAfter,
|
|
||||||
ViewFilterOperand.Contains,
|
|
||||||
ViewFilterOperand.DoesNotContain,
|
|
||||||
ViewFilterOperand.IsRelative,
|
|
||||||
].includes(selectedOperandInDropdown);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
{!filterDefinitionUsedInDropdown ? (
|
{shoudShowFilterInput ? (
|
||||||
<ObjectFilterDropdownFilterSelect />
|
<ObjectFilterDropdownFilterInput filterDropdownId={filterDropdownId} />
|
||||||
|
) : shouldShowCompositeSelectionSubMenu ? (
|
||||||
|
<ObjectFilterDropdownFilterSelectCompositeFieldSubMenu />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<ObjectFilterDropdownFilterSelect />
|
||||||
<ObjectFilterDropdownOperandButton />
|
|
||||||
{isObjectFilterDropdownOperandSelectUnfolded && (
|
|
||||||
<StyledOperandSelectContainer>
|
|
||||||
<ObjectFilterDropdownOperandSelect />
|
|
||||||
</StyledOperandSelectContainer>
|
|
||||||
)}
|
|
||||||
{isConfigurable && selectedOperandInDropdown && (
|
|
||||||
<>
|
|
||||||
{[
|
|
||||||
'TEXT',
|
|
||||||
'EMAIL',
|
|
||||||
'EMAILS',
|
|
||||||
'PHONE',
|
|
||||||
'FULL_NAME',
|
|
||||||
'LINK',
|
|
||||||
'LINKS',
|
|
||||||
'ADDRESS',
|
|
||||||
'ACTOR',
|
|
||||||
'ARRAY',
|
|
||||||
'PHONES',
|
|
||||||
].includes(filterDefinitionUsedInDropdown.type) &&
|
|
||||||
!isActorSourceCompositeFilter(
|
|
||||||
filterDefinitionUsedInDropdown,
|
|
||||||
) && <ObjectFilterDropdownTextSearchInput />}
|
|
||||||
{['NUMBER', 'CURRENCY'].includes(
|
|
||||||
filterDefinitionUsedInDropdown.type,
|
|
||||||
) && <ObjectFilterDropdownNumberInput />}
|
|
||||||
{filterDefinitionUsedInDropdown.type === 'RATING' && (
|
|
||||||
<ObjectFilterDropdownRatingInput />
|
|
||||||
)}
|
|
||||||
{['DATE_TIME', 'DATE'].includes(
|
|
||||||
filterDefinitionUsedInDropdown.type,
|
|
||||||
) && <ObjectFilterDropdownDateInput />}
|
|
||||||
{filterDefinitionUsedInDropdown.type === 'RELATION' && (
|
|
||||||
<>
|
|
||||||
<ObjectFilterDropdownSearchInput />
|
|
||||||
<ObjectFilterDropdownRecordSelect />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
|
|
||||||
<>
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<ObjectFilterDropdownSourceSelect />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{filterDefinitionUsedInDropdown.type === 'SELECT' && (
|
|
||||||
<>
|
|
||||||
<ObjectFilterDropdownSearchInput />
|
|
||||||
<ObjectFilterDropdownOptionSelect />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
<MultipleFiltersDropdownFilterOnFilterChangedEffect
|
<MultipleFiltersDropdownFilterOnFilterChangedEffect
|
||||||
filterDefinitionUsedInDropdownType={
|
filterDefinitionUsedInDropdownType={
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
|
||||||
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||||
import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton';
|
import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton';
|
||||||
@ -29,12 +30,16 @@ export const ObjectFilterDropdownButton = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ObjectFilterDropdownScope filterScopeId={filterDropdownId}>
|
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||||
{hasOnlyOneEntityFilter ? (
|
value={{ instanceId: filterDropdownId }}
|
||||||
<SingleEntityObjectFilterDropdownButton hotkeyScope={hotkeyScope} />
|
>
|
||||||
) : (
|
<ObjectFilterDropdownScope filterScopeId={filterDropdownId}>
|
||||||
<MultipleFiltersDropdownButton hotkeyScope={hotkeyScope} />
|
{hasOnlyOneEntityFilter ? (
|
||||||
)}
|
<SingleEntityObjectFilterDropdownButton hotkeyScope={hotkeyScope} />
|
||||||
</ObjectFilterDropdownScope>
|
) : (
|
||||||
|
<MultipleFiltersDropdownButton hotkeyScope={hotkeyScope} />
|
||||||
|
)}
|
||||||
|
</ObjectFilterDropdownScope>
|
||||||
|
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,132 @@
|
|||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { ObjectFilterDropdownDateInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput';
|
||||||
|
import { ObjectFilterDropdownNumberInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownNumberInput';
|
||||||
|
import { ObjectFilterDropdownOperandButton } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandButton';
|
||||||
|
import { ObjectFilterDropdownOperandSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect';
|
||||||
|
import { ObjectFilterDropdownOptionSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect';
|
||||||
|
import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
|
||||||
|
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 { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||||
|
import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter';
|
||||||
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { isDefined } from 'twenty-ui';
|
||||||
|
|
||||||
|
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 ObjectFilterDropdownFilterInputProps = {
|
||||||
|
filterDropdownId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ObjectFilterDropdownFilterInput = ({
|
||||||
|
filterDropdownId,
|
||||||
|
}: ObjectFilterDropdownFilterInputProps) => {
|
||||||
|
const {
|
||||||
|
filterDefinitionUsedInDropdownState,
|
||||||
|
selectedOperandInDropdownState,
|
||||||
|
isObjectFilterDropdownOperandSelectUnfoldedState,
|
||||||
|
} = useFilterDropdown({ filterDropdownId });
|
||||||
|
|
||||||
|
const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue(
|
||||||
|
isObjectFilterDropdownOperandSelectUnfoldedState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const filterDefinitionUsedInDropdown = useRecoilValue(
|
||||||
|
filterDefinitionUsedInDropdownState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedOperandInDropdown = useRecoilValue(
|
||||||
|
selectedOperandInDropdownState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isConfigurable =
|
||||||
|
selectedOperandInDropdown &&
|
||||||
|
[
|
||||||
|
ViewFilterOperand.Is,
|
||||||
|
ViewFilterOperand.IsNotNull,
|
||||||
|
ViewFilterOperand.IsNot,
|
||||||
|
ViewFilterOperand.LessThan,
|
||||||
|
ViewFilterOperand.GreaterThan,
|
||||||
|
ViewFilterOperand.IsBefore,
|
||||||
|
ViewFilterOperand.IsAfter,
|
||||||
|
ViewFilterOperand.Contains,
|
||||||
|
ViewFilterOperand.DoesNotContain,
|
||||||
|
ViewFilterOperand.IsRelative,
|
||||||
|
].includes(selectedOperandInDropdown);
|
||||||
|
|
||||||
|
if (!isDefined(filterDefinitionUsedInDropdown)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ObjectFilterDropdownOperandButton />
|
||||||
|
{isObjectFilterDropdownOperandSelectUnfolded && (
|
||||||
|
<StyledOperandSelectContainer>
|
||||||
|
<ObjectFilterDropdownOperandSelect />
|
||||||
|
</StyledOperandSelectContainer>
|
||||||
|
)}
|
||||||
|
{isConfigurable && selectedOperandInDropdown && (
|
||||||
|
<>
|
||||||
|
{[
|
||||||
|
'TEXT',
|
||||||
|
'EMAIL',
|
||||||
|
'EMAILS',
|
||||||
|
'PHONE',
|
||||||
|
'FULL_NAME',
|
||||||
|
'LINK',
|
||||||
|
'LINKS',
|
||||||
|
'ADDRESS',
|
||||||
|
'ACTOR',
|
||||||
|
'ARRAY',
|
||||||
|
'PHONES',
|
||||||
|
].includes(filterDefinitionUsedInDropdown.type) &&
|
||||||
|
!isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
|
||||||
|
<ObjectFilterDropdownTextSearchInput />
|
||||||
|
)}
|
||||||
|
{['NUMBER', 'CURRENCY'].includes(
|
||||||
|
filterDefinitionUsedInDropdown.type,
|
||||||
|
) && <ObjectFilterDropdownNumberInput />}
|
||||||
|
{filterDefinitionUsedInDropdown.type === 'RATING' && (
|
||||||
|
<ObjectFilterDropdownRatingInput />
|
||||||
|
)}
|
||||||
|
{['DATE_TIME', 'DATE'].includes(
|
||||||
|
filterDefinitionUsedInDropdown.type,
|
||||||
|
) && <ObjectFilterDropdownDateInput />}
|
||||||
|
{filterDefinitionUsedInDropdown.type === 'RELATION' && (
|
||||||
|
<>
|
||||||
|
<ObjectFilterDropdownSearchInput />
|
||||||
|
<ObjectFilterDropdownRecordSelect />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
|
||||||
|
<>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<ObjectFilterDropdownSourceSelect />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{filterDefinitionUsedInDropdown.type === 'SELECT' && (
|
||||||
|
<>
|
||||||
|
<ObjectFilterDropdownSearchInput />
|
||||||
|
<ObjectFilterDropdownOptionSelect />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,27 +1,23 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useState } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
|
||||||
import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu';
|
import { ObjectFilterDropdownFilterSelectMenuItem } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectMenuItem';
|
||||||
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
|
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
|
||||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||||
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
|
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
|
||||||
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
|
|
||||||
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
|
||||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||||
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
|
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
||||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined, useIcons } from 'twenty-ui';
|
import { isDefined } from 'twenty-ui';
|
||||||
import { getOperandsForFilterDefinition } from '../utils/getOperandsForFilterType';
|
|
||||||
|
|
||||||
export const StyledInput = styled.input`
|
export const StyledInput = styled.input`
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -50,15 +46,7 @@ export const StyledInput = styled.input`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ObjectFilterDropdownFilterSelect = () => {
|
export const ObjectFilterDropdownFilterSelect = () => {
|
||||||
const [subMenuFieldType, setSubMenuFieldType] =
|
|
||||||
useState<CompositeFilterableFieldType | null>(null);
|
|
||||||
|
|
||||||
const [firstLevelFilterDefinition, setFirstLevelFilterDefinition] =
|
|
||||||
useState<FilterDefinition | null>(null);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setFilterDefinitionUsedInDropdown,
|
|
||||||
setSelectedOperandInDropdown,
|
|
||||||
setObjectFilterDropdownSearchInput,
|
setObjectFilterDropdownSearchInput,
|
||||||
objectFilterDropdownSearchInputState,
|
objectFilterDropdownSearchInputState,
|
||||||
} = useFilterDropdown();
|
} = useFilterDropdown();
|
||||||
@ -70,16 +58,41 @@ export const ObjectFilterDropdownFilterSelect = () => {
|
|||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const availableFilterDefinitions = useRecoilComponentValueV2(
|
||||||
availableFilterDefinitionsComponentState,
|
availableFilterDefinitionsComponentState,
|
||||||
);
|
);
|
||||||
|
const { recordIndexId } = useContext(RecordIndexRootPropsContext);
|
||||||
|
const { hiddenTableColumnsSelector, visibleTableColumnsSelector } =
|
||||||
|
useRecordTableStates(recordIndexId);
|
||||||
|
|
||||||
const sortedAvailableFilterDefinitions = [...availableFilterDefinitions]
|
const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector());
|
||||||
.sort((a, b) => a.label.localeCompare(b.label))
|
const visibleColumnsIds = visibleTableColumns.map(
|
||||||
.filter((item) =>
|
(column) => column.fieldMetadataId,
|
||||||
|
);
|
||||||
|
const hiddenTableColumns = useRecoilValue(hiddenTableColumnsSelector());
|
||||||
|
const hiddenColumnIds = hiddenTableColumns.map(
|
||||||
|
(column) => column.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredSearchInputFilterDefinitions =
|
||||||
|
availableFilterDefinitions.filter((item) =>
|
||||||
item.label
|
item.label
|
||||||
.toLocaleLowerCase()
|
.toLocaleLowerCase()
|
||||||
.includes(objectFilterDropdownSearchInput.toLocaleLowerCase()),
|
.includes(objectFilterDropdownSearchInput.toLocaleLowerCase()),
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectableListItemIds = sortedAvailableFilterDefinitions.map(
|
const visibleColumnsFilterDefinitions = filteredSearchInputFilterDefinitions
|
||||||
|
|
||||||
|
.sort((a, b) => {
|
||||||
|
return (
|
||||||
|
visibleColumnsIds.indexOf(a.fieldMetadataId) -
|
||||||
|
visibleColumnsIds.indexOf(b.fieldMetadataId)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter((item) => visibleColumnsIds.includes(item.fieldMetadataId));
|
||||||
|
|
||||||
|
const hiddenColumnsFilterDefinitions = filteredSearchInputFilterDefinitions
|
||||||
|
.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
|
.filter((item) => hiddenColumnIds.includes(item.fieldMetadataId));
|
||||||
|
|
||||||
|
const selectableListItemIds = availableFilterDefinitions.map(
|
||||||
(item) => item.fieldMetadataId,
|
(item) => item.fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -88,7 +101,7 @@ export const ObjectFilterDropdownFilterSelect = () => {
|
|||||||
const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
|
const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
|
||||||
|
|
||||||
const handleEnter = (itemId: string) => {
|
const handleEnter = (itemId: string) => {
|
||||||
const selectedFilterDefinition = sortedAvailableFilterDefinitions.find(
|
const selectedFilterDefinition = availableFilterDefinitions.find(
|
||||||
(item) => item.fieldMetadataId === itemId,
|
(item) => item.fieldMetadataId === itemId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -101,96 +114,56 @@ export const ObjectFilterDropdownFilterSelect = () => {
|
|||||||
selectFilter({ filterDefinition: selectedFilterDefinition });
|
selectFilter({ filterDefinition: selectedFilterDefinition });
|
||||||
};
|
};
|
||||||
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const shoudShowSeparator =
|
||||||
const { getIcon } = useIcons();
|
visibleColumnsFilterDefinitions.length > 0 &&
|
||||||
|
hiddenColumnsFilterDefinitions.length > 0;
|
||||||
const handleSelectFilter = (availableFilterDefinition: FilterDefinition) => {
|
|
||||||
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
|
|
||||||
|
|
||||||
if (
|
|
||||||
availableFilterDefinition.type === 'RELATION' ||
|
|
||||||
availableFilterDefinition.type === 'SELECT'
|
|
||||||
) {
|
|
||||||
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelectedOperandInDropdown(
|
|
||||||
getOperandsForFilterDefinition(availableFilterDefinition)[0],
|
|
||||||
);
|
|
||||||
|
|
||||||
setObjectFilterDropdownSearchInput('');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubMenuBack = () => {
|
|
||||||
setSubMenuFieldType(null);
|
|
||||||
setFirstLevelFilterDefinition(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const shouldShowFirstLevelMenu = !isDefined(subMenuFieldType);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{shouldShowFirstLevelMenu ? (
|
<StyledInput
|
||||||
<>
|
value={objectFilterDropdownSearchInput}
|
||||||
<StyledInput
|
autoFocus
|
||||||
value={objectFilterDropdownSearchInput}
|
placeholder="Search fields"
|
||||||
autoFocus
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
placeholder="Search fields"
|
setObjectFilterDropdownSearchInput(event.target.value)
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
}
|
||||||
setObjectFilterDropdownSearchInput(event.target.value)
|
/>
|
||||||
}
|
<SelectableList
|
||||||
/>
|
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
|
||||||
<SelectableList
|
selectableItemIdArray={selectableListItemIds}
|
||||||
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
|
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
|
||||||
selectableItemIdArray={selectableListItemIds}
|
onEnter={handleEnter}
|
||||||
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
|
>
|
||||||
onEnter={handleEnter}
|
<DropdownMenuItemsContainer>
|
||||||
>
|
{visibleColumnsFilterDefinitions.map(
|
||||||
<DropdownMenuItemsContainer>
|
(visibleFilterDefinition, index) => (
|
||||||
{[...availableFilterDefinitions]
|
<SelectableItem
|
||||||
.sort((a, b) => a.label.localeCompare(b.label))
|
itemId={visibleFilterDefinition.fieldMetadataId}
|
||||||
.filter((item) =>
|
key={`visible-select-filter-${index}`}
|
||||||
item.label
|
>
|
||||||
.toLocaleLowerCase()
|
<ObjectFilterDropdownFilterSelectMenuItem
|
||||||
.includes(
|
filterDefinition={visibleFilterDefinition}
|
||||||
objectFilterDropdownSearchInput.toLocaleLowerCase(),
|
/>
|
||||||
),
|
</SelectableItem>
|
||||||
)
|
),
|
||||||
.map((availableFilterDefinition, index) => (
|
)}
|
||||||
<SelectableItem
|
</DropdownMenuItemsContainer>
|
||||||
itemId={availableFilterDefinition.fieldMetadataId}
|
{shoudShowSeparator && <DropdownMenuSeparator />}
|
||||||
>
|
<DropdownMenuItemsContainer>
|
||||||
<MenuItem
|
{hiddenColumnsFilterDefinitions.map(
|
||||||
key={`select-filter-${index}`}
|
(hiddenFilterDefinition, index) => (
|
||||||
testId={`select-filter-${index}`}
|
<SelectableItem
|
||||||
onClick={() => {
|
itemId={hiddenFilterDefinition.fieldMetadataId}
|
||||||
if (isCompositeField(availableFilterDefinition.type)) {
|
key={`hidden-select-filter-${index}`}
|
||||||
setSubMenuFieldType(availableFilterDefinition.type);
|
>
|
||||||
setFirstLevelFilterDefinition(
|
<ObjectFilterDropdownFilterSelectMenuItem
|
||||||
availableFilterDefinition,
|
filterDefinition={hiddenFilterDefinition}
|
||||||
);
|
/>
|
||||||
} else {
|
</SelectableItem>
|
||||||
handleSelectFilter(availableFilterDefinition);
|
),
|
||||||
}
|
)}
|
||||||
}}
|
</DropdownMenuItemsContainer>
|
||||||
LeftIcon={getIcon(availableFilterDefinition.iconName)}
|
</SelectableList>
|
||||||
text={availableFilterDefinition.label}
|
|
||||||
hasSubMenu={isCompositeField(
|
|
||||||
availableFilterDefinition.type,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</SelectableItem>
|
|
||||||
))}
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
</SelectableList>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<ObjectFilterDropdownFilterSelectCompositeFieldSubMenu
|
|
||||||
fieldType={subMenuFieldType}
|
|
||||||
firstLevelFieldDefinition={firstLevelFilterDefinition}
|
|
||||||
onBack={handleSubMenuBack}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { StyledInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect';
|
import { StyledInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect';
|
||||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||||
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
|
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||||
|
import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState';
|
||||||
|
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
||||||
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
||||||
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
||||||
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
|
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
|
||||||
@ -9,24 +11,33 @@ import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/con
|
|||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||||
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { IconApps, IconChevronLeft, useIcons } from 'twenty-ui';
|
import { IconApps, IconChevronLeft, isDefined, useIcons } from 'twenty-ui';
|
||||||
|
|
||||||
type ObjectFilterDropdownFilterSelectCompositeFieldSubMenuProps = {
|
export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => {
|
||||||
fieldType: CompositeFilterableFieldType;
|
|
||||||
firstLevelFieldDefinition: FilterDefinition | null;
|
|
||||||
onBack: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
|
|
||||||
fieldType,
|
|
||||||
firstLevelFieldDefinition,
|
|
||||||
onBack,
|
|
||||||
}: ObjectFilterDropdownFilterSelectCompositeFieldSubMenuProps) => {
|
|
||||||
const [searchText, setSearchText] = useState('');
|
const [searchText, setSearchText] = useState('');
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
|
const [
|
||||||
|
objectFilterDropdownFirstLevelFilterDefinition,
|
||||||
|
setObjectFilterDropdownFirstLevelFilterDefinition,
|
||||||
|
] = useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownFirstLevelFilterDefinitionComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownFilterIsSelectedComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [
|
||||||
|
objectFilterDropdownSubMenuFieldType,
|
||||||
|
setObjectFilterDropdownSubMenuFieldType,
|
||||||
|
] = useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownSubMenuFieldTypeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setFilterDefinitionUsedInDropdown,
|
setFilterDefinitionUsedInDropdown,
|
||||||
setSelectedOperandInDropdown,
|
setSelectedOperandInDropdown,
|
||||||
@ -42,11 +53,26 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
setObjectFilterDropdownSearchInput('');
|
setObjectFilterDropdownSearchInput('');
|
||||||
|
|
||||||
|
setObjectFilterDropdownFilterIsSelected(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubMenuBack = () => {
|
||||||
|
setFilterDefinitionUsedInDropdown(null);
|
||||||
|
setObjectFilterDropdownSubMenuFieldType(null);
|
||||||
|
setObjectFilterDropdownFirstLevelFilterDefinition(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isDefined(objectFilterDropdownSubMenuFieldType) ||
|
||||||
|
!isDefined(objectFilterDropdownFirstLevelFilterDefinition)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const options = SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS[
|
const options = SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS[
|
||||||
fieldType
|
objectFilterDropdownSubMenuFieldType
|
||||||
].filterableSubFields
|
].filterableSubFields
|
||||||
.sort((a, b) => a.localeCompare(b))
|
.sort((a, b) => a.localeCompare(b))
|
||||||
.filter((item) =>
|
.filter((item) =>
|
||||||
@ -55,8 +81,11 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuHeader StartIcon={IconChevronLeft} onClick={onBack}>
|
<DropdownMenuHeader
|
||||||
{getFilterableFieldTypeLabel(fieldType)}
|
StartIcon={IconChevronLeft}
|
||||||
|
onClick={handleSubMenuBack}
|
||||||
|
>
|
||||||
|
{getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)}
|
||||||
</DropdownMenuHeader>
|
</DropdownMenuHeader>
|
||||||
<StyledInput
|
<StyledInput
|
||||||
value={searchText}
|
value={searchText}
|
||||||
@ -71,25 +100,34 @@ export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = ({
|
|||||||
key={`select-filter-${-1}`}
|
key={`select-filter-${-1}`}
|
||||||
testId={`select-filter-${-1}`}
|
testId={`select-filter-${-1}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleSelectFilter(firstLevelFieldDefinition);
|
handleSelectFilter(objectFilterDropdownFirstLevelFilterDefinition);
|
||||||
}}
|
}}
|
||||||
LeftIcon={IconApps}
|
LeftIcon={IconApps}
|
||||||
text={`Any ${getFilterableFieldTypeLabel(fieldType)} field`}
|
text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`}
|
||||||
/>
|
/>
|
||||||
{options.map((subFieldName, index) => (
|
{options.map((subFieldName, index) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={`select-filter-${index}`}
|
key={`select-filter-${index}`}
|
||||||
testId={`select-filter-${index}`}
|
testId={`select-filter-${index}`}
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
firstLevelFieldDefinition &&
|
if (isDefined(objectFilterDropdownFirstLevelFilterDefinition)) {
|
||||||
handleSelectFilter({
|
handleSelectFilter({
|
||||||
...firstLevelFieldDefinition,
|
...objectFilterDropdownFirstLevelFilterDefinition,
|
||||||
label: getCompositeSubFieldLabel(fieldType, subFieldName),
|
label: getCompositeSubFieldLabel(
|
||||||
compositeFieldName: subFieldName,
|
objectFilterDropdownSubMenuFieldType,
|
||||||
})
|
subFieldName,
|
||||||
}
|
),
|
||||||
text={getCompositeSubFieldLabel(fieldType, subFieldName)}
|
compositeFieldName: subFieldName,
|
||||||
LeftIcon={getIcon(firstLevelFieldDefinition?.iconName)}
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
text={getCompositeSubFieldLabel(
|
||||||
|
objectFilterDropdownSubMenuFieldType,
|
||||||
|
subFieldName,
|
||||||
|
)}
|
||||||
|
LeftIcon={getIcon(
|
||||||
|
objectFilterDropdownFirstLevelFilterDefinition?.iconName,
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
|
|||||||
@ -1,9 +1,20 @@
|
|||||||
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
|
import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdown/constants/ObjectFilterDropdownId';
|
||||||
|
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||||
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
|
import { useSelectFilter } from '@/object-record/object-filter-dropdown/hooks/useSelectFilter';
|
||||||
|
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||||
|
import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFirstLevelFilterDefinitionComponentState';
|
||||||
|
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||||
|
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
||||||
|
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
|
||||||
|
|
||||||
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
||||||
|
import { getOperandsForFilterDefinition } from '@/object-record/object-filter-dropdown/utils/getOperandsForFilterType';
|
||||||
|
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
|
||||||
|
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||||
import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect';
|
import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect';
|
||||||
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { useIcons } from 'twenty-ui';
|
import { useIcons } from 'twenty-ui';
|
||||||
|
|
||||||
@ -16,6 +27,24 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
}: ObjectFilterDropdownFilterSelectMenuItemProps) => {
|
}: ObjectFilterDropdownFilterSelectMenuItemProps) => {
|
||||||
const { selectFilter } = useSelectFilter();
|
const { selectFilter } = useSelectFilter();
|
||||||
|
|
||||||
|
const [, setObjectFilterDropdownFirstLevelFilterDefinition] =
|
||||||
|
useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownFirstLevelFilterDefinitionComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [, setObjectFilterDropdownSubMenuFieldType] = useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownSubMenuFieldTypeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [, setObjectFilterDropdownIsSelectingCompositeField] =
|
||||||
|
useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
||||||
|
objectFilterDropdownFilterIsSelectedComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const { isSelectedItemIdSelector, resetSelectedItem } = useSelectableList(
|
const { isSelectedItemIdSelector, resetSelectedItem } = useSelectableList(
|
||||||
OBJECT_FILTER_DROPDOWN_ID,
|
OBJECT_FILTER_DROPDOWN_ID,
|
||||||
);
|
);
|
||||||
@ -24,12 +53,52 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
isSelectedItemIdSelector(filterDefinition.fieldMetadataId),
|
isSelectedItemIdSelector(filterDefinition.fieldMetadataId),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isACompositeField = isCompositeField(filterDefinition.type);
|
||||||
|
|
||||||
|
const {
|
||||||
|
setFilterDefinitionUsedInDropdown,
|
||||||
|
setSelectedOperandInDropdown,
|
||||||
|
setObjectFilterDropdownSearchInput,
|
||||||
|
} = useFilterDropdown();
|
||||||
|
|
||||||
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|
||||||
|
const handleSelectFilter = (availableFilterDefinition: FilterDefinition) => {
|
||||||
|
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
|
||||||
|
|
||||||
|
if (
|
||||||
|
availableFilterDefinition.type === 'RELATION' ||
|
||||||
|
availableFilterDefinition.type === 'SELECT'
|
||||||
|
) {
|
||||||
|
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedOperandInDropdown(
|
||||||
|
getOperandsForFilterDefinition(availableFilterDefinition)[0],
|
||||||
|
);
|
||||||
|
|
||||||
|
setObjectFilterDropdownSearchInput('');
|
||||||
|
|
||||||
|
setObjectFilterDropdownFilterIsSelected(true);
|
||||||
|
};
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
resetSelectedItem();
|
resetSelectedItem();
|
||||||
|
|
||||||
selectFilter({ filterDefinition });
|
selectFilter({ filterDefinition });
|
||||||
|
|
||||||
|
if (isACompositeField) {
|
||||||
|
// TODO: create isCompositeFilterableFieldType type guard
|
||||||
|
setObjectFilterDropdownSubMenuFieldType(
|
||||||
|
filterDefinition.type as CompositeFilterableFieldType,
|
||||||
|
);
|
||||||
|
setObjectFilterDropdownFirstLevelFilterDefinition(filterDefinition);
|
||||||
|
setObjectFilterDropdownIsSelectingCompositeField(true);
|
||||||
|
} else {
|
||||||
|
handleSelectFilter(filterDefinition);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -39,6 +108,7 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
LeftIcon={getIcon(filterDefinition.iconName)}
|
LeftIcon={getIcon(filterDefinition.iconName)}
|
||||||
text={filterDefinition.label}
|
text={filterDefinition.label}
|
||||||
|
hasSubMenu={isACompositeField}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,10 +3,15 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
||||||
import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton';
|
import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton';
|
||||||
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
||||||
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
|
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
|
import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext';
|
||||||
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
import { within } from '@storybook/test';
|
import { within } from '@storybook/test';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { ComponentDecorator } from 'twenty-ui';
|
import { ComponentDecorator } from 'twenty-ui';
|
||||||
import { FieldMetadataType } from '~/generated/graphql';
|
import { FieldMetadataType } from '~/generated/graphql';
|
||||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||||
@ -25,6 +30,43 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
instanceId,
|
instanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { tableColumnsState } = useRecordTableStates(instanceId);
|
||||||
|
|
||||||
|
const setTableColumns = useSetRecoilState(tableColumnsState);
|
||||||
|
|
||||||
|
setTableColumns([
|
||||||
|
{
|
||||||
|
fieldMetadataId: '1',
|
||||||
|
iconName: 'IconUser',
|
||||||
|
label: 'Text',
|
||||||
|
type: FieldMetadataType.Text,
|
||||||
|
isVisible: true,
|
||||||
|
metadata: {
|
||||||
|
fieldName: 'text',
|
||||||
|
},
|
||||||
|
} as ColumnDefinition<any>,
|
||||||
|
{
|
||||||
|
fieldMetadataId: '3',
|
||||||
|
iconName: 'IconNumber',
|
||||||
|
label: 'Number',
|
||||||
|
type: FieldMetadataType.Number,
|
||||||
|
isVisible: true,
|
||||||
|
metadata: {
|
||||||
|
fieldName: 'number',
|
||||||
|
},
|
||||||
|
} as ColumnDefinition<any>,
|
||||||
|
{
|
||||||
|
fieldMetadataId: '4',
|
||||||
|
iconName: 'IconCalendar',
|
||||||
|
label: 'Date',
|
||||||
|
type: FieldMetadataType.DateTime,
|
||||||
|
isVisible: true,
|
||||||
|
metadata: {
|
||||||
|
fieldName: 'date',
|
||||||
|
},
|
||||||
|
} as ColumnDefinition<any>,
|
||||||
|
]);
|
||||||
|
|
||||||
setAvailableFilterDefinitions([
|
setAvailableFilterDefinitions([
|
||||||
{
|
{
|
||||||
fieldMetadataId: '1',
|
fieldMetadataId: '1',
|
||||||
@ -32,12 +74,6 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
label: 'Text',
|
label: 'Text',
|
||||||
type: FieldMetadataType.Text,
|
type: FieldMetadataType.Text,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
fieldMetadataId: '2',
|
|
||||||
iconName: 'Icon123',
|
|
||||||
label: 'Email',
|
|
||||||
type: FieldMetadataType.Emails,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
fieldMetadataId: '3',
|
fieldMetadataId: '3',
|
||||||
iconName: 'IconNumber',
|
iconName: 'IconNumber',
|
||||||
@ -52,11 +88,19 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
return (
|
return (
|
||||||
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||||
<ObjectFilterDropdownScope filterScopeId={instanceId}>
|
value={{ instanceId }}
|
||||||
<Story />
|
>
|
||||||
</ObjectFilterDropdownScope>
|
<RecordTableScopeInternalContext.Provider
|
||||||
</ViewComponentInstanceContext.Provider>
|
value={{ scopeId: instanceId, onColumnsChange: () => {} }}
|
||||||
|
>
|
||||||
|
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
||||||
|
<ObjectFilterDropdownScope filterScopeId={instanceId}>
|
||||||
|
<Story />
|
||||||
|
</ObjectFilterDropdownScope>
|
||||||
|
</ViewComponentInstanceContext.Provider>
|
||||||
|
</RecordTableScopeInternalContext.Provider>
|
||||||
|
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
ObjectMetadataItemsDecorator,
|
ObjectMetadataItemsDecorator,
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import { useFilterDropdownStates } from '@/object-record/object-filter-dropdown/
|
|||||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
|
|
||||||
|
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||||
|
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { ObjectFilterDropdownScopeInternalContext } from '../scopes/scope-internal-context/ObjectFilterDropdownScopeInternalContext';
|
import { ObjectFilterDropdownScopeInternalContext } from '../scopes/scope-internal-context/ObjectFilterDropdownScopeInternalContext';
|
||||||
import { Filter } from '../types/Filter';
|
import { Filter } from '../types/Filter';
|
||||||
|
|
||||||
@ -54,6 +57,18 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setObjectFilterDropdownFilterIsSelectedCallbackState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
objectFilterDropdownFilterIsSelectedComponentState,
|
||||||
|
props?.filterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setObjectFilterDropdownIsSelectingCompositeFieldCallbackState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
||||||
|
props?.filterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
const resetFilter = useRecoilCallback(
|
const resetFilter = useRecoilCallback(
|
||||||
({ set }) =>
|
({ set }) =>
|
||||||
() => {
|
() => {
|
||||||
@ -62,6 +77,11 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => {
|
|||||||
set(selectedFilterState, undefined);
|
set(selectedFilterState, undefined);
|
||||||
set(filterDefinitionUsedInDropdownState, null);
|
set(filterDefinitionUsedInDropdownState, null);
|
||||||
set(selectedOperandInDropdownState, null);
|
set(selectedOperandInDropdownState, null);
|
||||||
|
set(setObjectFilterDropdownFilterIsSelectedCallbackState, false);
|
||||||
|
set(
|
||||||
|
setObjectFilterDropdownIsSelectingCompositeFieldCallbackState,
|
||||||
|
false,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
filterDefinitionUsedInDropdownState,
|
filterDefinitionUsedInDropdownState,
|
||||||
@ -69,6 +89,8 @@ export const useFilterDropdown = (props?: UseFilterDropdownProps) => {
|
|||||||
objectFilterDropdownSelectedRecordIdsState,
|
objectFilterDropdownSelectedRecordIdsState,
|
||||||
selectedFilterState,
|
selectedFilterState,
|
||||||
selectedOperandInDropdownState,
|
selectedOperandInDropdownState,
|
||||||
|
setObjectFilterDropdownFilterIsSelectedCallbackState,
|
||||||
|
setObjectFilterDropdownIsSelectingCompositeFieldCallbackState,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
|
||||||
|
|
||||||
|
export const ObjectFilterDropdownComponentInstanceContext =
|
||||||
|
createComponentInstanceContext();
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
|
export const objectFilterDropdownFilterIsSelectedComponentState =
|
||||||
|
createComponentStateV2<boolean>({
|
||||||
|
key: 'objectFilterDropdownFilterIsSelectedComponentState',
|
||||||
|
defaultValue: false,
|
||||||
|
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
|
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
||||||
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
|
export const objectFilterDropdownFirstLevelFilterDefinitionComponentState =
|
||||||
|
createComponentStateV2<FilterDefinition | null>({
|
||||||
|
key: 'objectFilterDropdownFirstLevelFilterDefinitionComponentState',
|
||||||
|
defaultValue: null,
|
||||||
|
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
|
export const objectFilterDropdownIsSelectingCompositeFieldComponentState =
|
||||||
|
createComponentStateV2<boolean>({
|
||||||
|
key: 'objectFilterDropdownIsSelectingCompositeFieldComponentState',
|
||||||
|
defaultValue: false,
|
||||||
|
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
|
import { CompositeFilterableFieldType } from '@/object-record/object-filter-dropdown/types/CompositeFilterableFieldType';
|
||||||
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
|
export const objectFilterDropdownSubMenuFieldTypeComponentState =
|
||||||
|
createComponentStateV2<CompositeFilterableFieldType | null>({
|
||||||
|
key: 'objectFilterDropdownSubMenuFieldTypeComponentState',
|
||||||
|
defaultValue: null,
|
||||||
|
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -5,14 +5,17 @@ import { IconChevronDown, useIcons } from 'twenty-ui';
|
|||||||
import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId';
|
import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId';
|
||||||
import { useObjectSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useObjectSortDropdown';
|
import { useObjectSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useObjectSortDropdown';
|
||||||
import { ObjectSortDropdownScope } from '@/object-record/object-sort-dropdown/scopes/ObjectSortDropdownScope';
|
import { ObjectSortDropdownScope } from '@/object-record/object-sort-dropdown/scopes/ObjectSortDropdownScope';
|
||||||
|
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
||||||
|
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
import { useContext } from 'react';
|
||||||
import { SORT_DIRECTIONS } from '../types/SortDirection';
|
import { SORT_DIRECTIONS } from '../types/SortDirection';
|
||||||
|
|
||||||
export const StyledInput = styled.input`
|
export const StyledInput = styled.input`
|
||||||
@ -94,6 +97,43 @@ export const ObjectSortDropdownButton = ({
|
|||||||
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
|
const { recordIndexId } = useContext(RecordIndexRootPropsContext);
|
||||||
|
const { hiddenTableColumnsSelector, visibleTableColumnsSelector } =
|
||||||
|
useRecordTableStates(recordIndexId);
|
||||||
|
|
||||||
|
const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector());
|
||||||
|
const visibleColumnsIds = visibleTableColumns.map(
|
||||||
|
(column) => column.fieldMetadataId,
|
||||||
|
);
|
||||||
|
const hiddenTableColumns = useRecoilValue(hiddenTableColumnsSelector());
|
||||||
|
const hiddenColumnIds = hiddenTableColumns.map(
|
||||||
|
(column) => column.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredSearchInputSortDefinitions = availableSortDefinitions.filter(
|
||||||
|
(item) =>
|
||||||
|
item.label
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.includes(objectSortDropdownSearchInput.toLocaleLowerCase()),
|
||||||
|
);
|
||||||
|
|
||||||
|
const visibleColumnsSortDefinitions = filteredSearchInputSortDefinitions
|
||||||
|
.sort((a, b) => {
|
||||||
|
return (
|
||||||
|
visibleColumnsIds.indexOf(a.fieldMetadataId) -
|
||||||
|
visibleColumnsIds.indexOf(b.fieldMetadataId)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter((item) => visibleColumnsIds.includes(item.fieldMetadataId));
|
||||||
|
|
||||||
|
const hiddenColumnsSortDefinitions = filteredSearchInputSortDefinitions
|
||||||
|
.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
|
.filter((item) => hiddenColumnIds.includes(item.fieldMetadataId));
|
||||||
|
|
||||||
|
const shoudShowSeparator =
|
||||||
|
visibleColumnsSortDefinitions.length > 0 &&
|
||||||
|
hiddenColumnsSortDefinitions.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ObjectSortDropdownScope sortScopeId={sortDropdownId}>
|
<ObjectSortDropdownScope sortScopeId={sortDropdownId}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
@ -142,27 +182,37 @@ export const ObjectSortDropdownButton = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{[...availableSortDefinitions]
|
{visibleColumnsSortDefinitions.map(
|
||||||
.sort((a, b) => a.label.localeCompare(b.label))
|
(visibleSortDefinition, index) => (
|
||||||
.filter((item) =>
|
|
||||||
item.label
|
|
||||||
.toLocaleLowerCase()
|
|
||||||
.includes(
|
|
||||||
objectSortDropdownSearchInput.toLocaleLowerCase(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map((availableSortDefinition, index) => (
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
testId={`select-sort-${index}`}
|
testId={`visible-select-sort-${index}`}
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setObjectSortDropdownSearchInput('');
|
setObjectSortDropdownSearchInput('');
|
||||||
handleAddSort(availableSortDefinition);
|
handleAddSort(visibleSortDefinition);
|
||||||
}}
|
}}
|
||||||
LeftIcon={getIcon(availableSortDefinition.iconName)}
|
LeftIcon={getIcon(visibleSortDefinition.iconName)}
|
||||||
text={availableSortDefinition.label}
|
text={visibleSortDefinition.label}
|
||||||
/>
|
/>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
{shoudShowSeparator && <DropdownMenuSeparator />}
|
||||||
|
<DropdownMenuItemsContainer>
|
||||||
|
{hiddenColumnsSortDefinitions.map(
|
||||||
|
(hiddenSortDefinition, index) => (
|
||||||
|
<MenuItem
|
||||||
|
testId={`hidden-select-sort-${index}`}
|
||||||
|
key={index}
|
||||||
|
onClick={() => {
|
||||||
|
setObjectSortDropdownSearchInput('');
|
||||||
|
handleAddSort(hiddenSortDefinition);
|
||||||
|
}}
|
||||||
|
LeftIcon={getIcon(hiddenSortDefinition.iconName)}
|
||||||
|
text={hiddenSortDefinition.label}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user