3886 - Shortcut Sort/Filter (#3901)

Closes #3886

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Kanav Arora 2024-04-04 04:13:44 +05:30 committed by GitHub
parent b65d82c274
commit bcf5268f7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 473 additions and 63 deletions

View File

@ -23,6 +23,14 @@ export const useColumnDefinitionsFromFieldMetadata = (
[objectMetadataItem],
);
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({
fields: activeFieldMetadataItems,
});
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
fields: activeFieldMetadataItems,
});
const columnDefinitions: ColumnDefinition<FieldMetadata>[] = useMemo(
() =>
objectMetadataItem
@ -35,17 +43,29 @@ export const useColumnDefinitionsFromFieldMetadata = (
}),
)
.filter(filterAvailableTableColumns)
: [],
[activeFieldMetadataItems, objectMetadataItem],
.map((column) => {
const existsInFilterDefinitions = filterDefinitions.some(
(filter) => filter.fieldMetadataId === column.fieldMetadataId,
);
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({
fields: activeFieldMetadataItems,
});
const existsInSortDefinitions = sortDefinitions.some(
(sort) => sort.fieldMetadataId === column.fieldMetadataId,
);
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
fields: activeFieldMetadataItems,
});
return {
...column,
isFilterable: existsInFilterDefinitions,
isSortable: existsInSortDefinitions,
};
})
: [],
[
activeFieldMetadataItems,
objectMetadataItem,
filterDefinitions,
sortDefinitions,
],
);
return {
columnDefinitions,

View File

@ -53,10 +53,10 @@ export const formatFieldMetadataItemAsFilterDefinition = ({
field.toRelationMetadata?.fromObjectMetadata.namePlural,
relationObjectMetadataNameSingular:
field.toRelationMetadata?.fromObjectMetadata.nameSingular,
type: getFilterType(field.type),
type: getFilterTypeFromFieldType(field.type),
});
const getFilterType = (fieldType: FieldMetadataType) => {
export const getFilterTypeFromFieldType = (fieldType: FieldMetadataType) => {
switch (fieldType) {
case FieldMetadataType.DateTime:
return 'DATE_TIME';

View File

@ -1,9 +1,7 @@
import { useCallback, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { IconChevronDown } from 'twenty-ui';
import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId';
import { useSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useSortDropdown';
import { useObjectSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useObjectSortDropdown';
import { ObjectSortDropdownScope } from '@/object-record/object-sort-dropdown/scopes/ObjectSortDropdownScope';
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
import { LightButton } from '@/ui/input/button/components/LightButton';
@ -11,12 +9,10 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { SortDefinition } from '../types/SortDefinition';
import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection';
import { SORT_DIRECTIONS } from '../types/SortDirection';
export type ObjectSortDropdownButtonProps = {
sortDropdownId: string;
@ -27,45 +23,20 @@ export const ObjectSortDropdownButton = ({
sortDropdownId,
hotkeyScope,
}: ObjectSortDropdownButtonProps) => {
const [isSortDirectionMenuUnfolded, setIsSortDirectionMenuUnfolded] =
useState(false);
const [selectedSortDirection, setSelectedSortDirection] =
useState<SortDirection>('asc');
const resetState = useCallback(() => {
setIsSortDirectionMenuUnfolded(false);
setSelectedSortDirection('asc');
}, []);
const { toggleDropdown } = useDropdown(OBJECT_SORT_DROPDOWN_ID);
const {
isSortDirectionMenuUnfolded,
setIsSortDirectionMenuUnfolded,
selectedSortDirection,
setSelectedSortDirection,
toggleSortDropdown,
resetState,
isSortSelected,
availableSortDefinitions,
handleAddSort,
} = useObjectSortDropdown();
const handleButtonClick = () => {
toggleDropdown();
resetState();
};
const {
availableSortDefinitionsState,
onSortSelectState,
isSortSelectedState,
} = useSortDropdown({
sortDropdownId: sortDropdownId,
});
const isSortSelected = useRecoilValue(isSortSelectedState);
const availableSortDefinitions = useRecoilValue(
availableSortDefinitionsState,
);
const onSortSelect = useRecoilValue(onSortSelectState);
const handleAddSort = (selectedSortDefinition: SortDefinition) => {
toggleDropdown();
onSortSelect?.({
fieldMetadataId: selectedSortDefinition.fieldMetadataId,
direction: selectedSortDirection,
definition: selectedSortDefinition,
});
toggleSortDropdown();
};
const handleDropdownButtonClose = () => {

View File

@ -1 +1,5 @@
export const OBJECT_SORT_DROPDOWN_ID = 'sort-dropdown';
/* eslint-disable @nx/workspace-max-consts-per-file */
const OBJECT_SORT_DROPDOWN_ID = 'sort-dropdown';
const VIEW_SORT_DROPDOWN_ID = 'view-sort';
export { OBJECT_SORT_DROPDOWN_ID, VIEW_SORT_DROPDOWN_ID };

View File

@ -0,0 +1,77 @@
import { useCallback } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useSortDropdown';
import isSortDirectionMenuUnfoldedState from '@/object-record/object-sort-dropdown/states/isSortDirectionMenuUnfoldedState';
import selectedSortDirectionState from '@/object-record/object-sort-dropdown/states/selectedSortDirectionState';
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import {
OBJECT_SORT_DROPDOWN_ID,
VIEW_SORT_DROPDOWN_ID,
} from '../constants/ObjectSortDropdownId';
// TODO: merge this with useSortDropdown
export const useObjectSortDropdown = () => {
const [isSortDirectionMenuUnfolded, setIsSortDirectionMenuUnfolded] =
useRecoilState(isSortDirectionMenuUnfoldedState);
const [selectedSortDirection, setSelectedSortDirection] = useRecoilState(
selectedSortDirectionState,
);
const resetState = useCallback(() => {
setIsSortDirectionMenuUnfolded(false);
setSelectedSortDirection('asc');
}, [setIsSortDirectionMenuUnfolded, setSelectedSortDirection]);
const { toggleDropdown, closeDropdown } = useDropdown(
OBJECT_SORT_DROPDOWN_ID,
);
const toggleSortDropdown = () => {
toggleDropdown();
resetState();
};
const closeSortDropdown = () => {
closeDropdown();
resetState();
};
const {
availableSortDefinitionsState,
onSortSelectState,
isSortSelectedState,
} = useSortDropdown({
sortDropdownId: VIEW_SORT_DROPDOWN_ID,
});
const isSortSelected = useRecoilValue(isSortSelectedState);
const availableSortDefinitions = useRecoilValue(
availableSortDefinitionsState,
);
const onSortSelect = useRecoilValue(onSortSelectState);
const handleAddSort = (selectedSortDefinition: SortDefinition) => {
closeSortDropdown();
onSortSelect?.({
fieldMetadataId: selectedSortDefinition.fieldMetadataId,
direction: selectedSortDirection,
definition: selectedSortDefinition,
});
};
return {
isSortDirectionMenuUnfolded,
setIsSortDirectionMenuUnfolded,
selectedSortDirection,
setSelectedSortDirection,
toggleSortDropdown,
resetState,
isSortSelected,
availableSortDefinitions,
handleAddSort,
};
};

View File

@ -0,0 +1,8 @@
import { atom } from 'recoil';
const isSortDirectionMenuUnfoldedState = atom({
key: 'isSortDirectionMenuUnfoldedState',
default: false,
});
export default isSortDirectionMenuUnfoldedState;

View File

@ -0,0 +1,10 @@
import { atom } from 'recoil';
import { SortDirection } from '@/object-record/object-sort-dropdown/types/SortDirection';
const selectedSortDirectionState = atom<SortDirection>({
key: 'selectedSortDirectionState',
default: 'asc',
});
export default selectedSortDirectionState;

View File

@ -4,6 +4,8 @@ import { useRecoilValue } from 'recoil';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar';
import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter';
import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { useSetRecordCountInCurrentView } from '@/views/hooks/useSetRecordCountInCurrentView';
@ -23,6 +25,8 @@ export const RecordIndexTableContainerEffect = ({
setOnEntityCountChange,
resetTableRowSelection,
selectedRowIdsSelector,
setOnToggleColumnFilter,
setOnToggleColumnSort,
} = useRecordTable({
recordTableId,
});
@ -49,6 +53,30 @@ export const RecordIndexTableContainerEffect = ({
callback: resetTableRowSelection,
});
const handleToggleColumnFilter = useHandleToggleColumnFilter({
objectNameSingular,
viewBarId,
});
const handleToggleColumnSort = useHandleToggleColumnSort({
objectNameSingular,
viewBarId,
});
useEffect(() => {
setOnToggleColumnFilter(
() => (fieldMetadataId: string) =>
handleToggleColumnFilter(fieldMetadataId),
);
}, [setOnToggleColumnFilter, handleToggleColumnFilter]);
useEffect(() => {
setOnToggleColumnSort(
() => (fieldMetadataId: string) =>
handleToggleColumnSort(fieldMetadataId),
);
}, [setOnToggleColumnSort, handleToggleColumnSort]);
useEffect(() => {
setActionBarEntries?.();
setContextMenuEntries?.();

View File

@ -0,0 +1,71 @@
import { useCallback } from 'react';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
import { getOperandsForFilterType } from '@/object-record/object-filter-dropdown/utils/getOperandsForFilterType';
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters';
import { isDefined } from '~/utils/isDefined';
type UseHandleToggleColumnFilterProps = {
objectNameSingular: string;
viewBarId: string;
};
export const useHandleToggleColumnFilter = ({
viewBarId,
objectNameSingular,
}: UseHandleToggleColumnFilterProps) => {
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
const { upsertCombinedViewFilter } = useCombinedViewFilters(viewBarId);
const { openDropdown } = useDropdownV2();
const handleToggleColumnFilter = useCallback(
(fieldMetadataId: string) => {
const correspondingColumnDefinition = columnDefinitions.find(
(columnDefinition) =>
columnDefinition.fieldMetadataId === fieldMetadataId,
);
if (!isDefined(correspondingColumnDefinition)) return;
const filterType = getFilterTypeFromFieldType(
correspondingColumnDefinition?.type,
);
const availableOperandsForFilter = getOperandsForFilterType(filterType);
const defaultOperand = availableOperandsForFilter[0];
const newFilter: Filter = {
fieldMetadataId,
operand: defaultOperand,
displayValue: '',
definition: {
label: correspondingColumnDefinition.label,
iconName: correspondingColumnDefinition.iconName,
fieldMetadataId,
type: filterType,
},
value: '',
};
upsertCombinedViewFilter(newFilter);
openDropdown(fieldMetadataId, {
scope: fieldMetadataId,
});
},
[columnDefinitions, upsertCombinedViewFilter, openDropdown],
);
return handleToggleColumnFilter;
};

View File

@ -0,0 +1,52 @@
import { useCallback } from 'react';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
import { useCombinedViewSorts } from '@/views/hooks/useCombinedViewSorts';
import { isDefined } from '~/utils/isDefined';
type UseHandleToggleColumnSortProps = {
objectNameSingular: string;
viewBarId: string;
};
export const useHandleToggleColumnSort = ({
viewBarId,
objectNameSingular,
}: UseHandleToggleColumnSortProps) => {
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
const { upsertCombinedViewSort } = useCombinedViewSorts(viewBarId);
const handleToggleColumnSort = useCallback(
(fieldMetadataId: string) => {
const correspondingColumnDefinition = columnDefinitions.find(
(columnDefinition) =>
columnDefinition.fieldMetadataId === fieldMetadataId,
);
if (!isDefined(correspondingColumnDefinition)) return;
const newSort: Sort = {
fieldMetadataId,
definition: {
fieldMetadataId,
label: correspondingColumnDefinition.label,
iconName: correspondingColumnDefinition.iconName,
},
direction: 'asc',
};
upsertCombinedViewSort(newSort);
},
[columnDefinitions, upsertCombinedViewSort],
);
return handleToggleColumnSort;
};

View File

@ -1,9 +1,16 @@
import { useRecoilValue } from 'recoil';
import { IconArrowLeft, IconArrowRight, IconEyeOff } from 'twenty-ui';
import {
IconArrowLeft,
IconArrowRight,
IconEyeOff,
IconFilter,
IconSortDescending,
} from 'twenty-ui';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
@ -17,7 +24,11 @@ export type RecordTableColumnDropdownMenuProps = {
export const RecordTableColumnDropdownMenu = ({
column,
}: RecordTableColumnDropdownMenuProps) => {
const { visibleTableColumnsSelector } = useRecordTableStates();
const {
visibleTableColumnsSelector,
onToggleColumnFilterState,
onToggleColumnSortState,
} = useRecordTableStates();
const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector());
@ -55,8 +66,42 @@ export const RecordTableColumnDropdownMenu = ({
handleColumnVisibilityChange(column);
};
const onToggleColumnFilter = useRecoilValue(onToggleColumnFilterState);
const onToggleColumnSort = useRecoilValue(onToggleColumnSortState);
const handleSortClick = () => {
closeDropdown();
onToggleColumnSort?.(column.fieldMetadataId);
};
const handleFilterClick = () => {
closeDropdown();
onToggleColumnFilter?.(column.fieldMetadataId);
};
const isSortable = column.isSortable === true;
const isFilterable = column.isFilterable === true;
const showSeparator = isFilterable || isSortable;
return (
<DropdownMenuItemsContainer>
{isFilterable && (
<MenuItem
LeftIcon={IconFilter}
onClick={handleFilterClick}
text="Filter"
/>
)}
{isSortable && (
<MenuItem
LeftIcon={IconSortDescending}
onClick={handleSortClick}
text="Sort"
/>
)}
{showSeparator && <DropdownMenuSeparator />}
{canMoveLeft && (
<MenuItem
LeftIcon={IconArrowLeft}

View File

@ -10,6 +10,8 @@ import { isTableCellInEditModeComponentFamilyState } from '@/object-record/recor
import { numberOfTableRowsComponentState } from '@/object-record/record-table/states/numberOfTableRowsComponentState';
import { onColumnsChangeComponentState } from '@/object-record/record-table/states/onColumnsChangeComponentState';
import { onEntityCountChangeComponentState } from '@/object-record/record-table/states/onEntityCountChangeComponentState';
import { onToggleColumnFilterComponentState } from '@/object-record/record-table/states/onToggleColumnFilterComponentState';
import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState';
import { resizeFieldOffsetComponentState } from '@/object-record/record-table/states/resizeFieldOffsetComponentState';
import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector';
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
@ -49,6 +51,14 @@ export const useRecordTableStates = (recordTableId?: string) => {
tableColumnsComponentState,
scopeId,
),
onToggleColumnFilterState: extractComponentState(
onToggleColumnFilterComponentState,
scopeId,
),
onToggleColumnSortState: extractComponentState(
onToggleColumnSortComponentState,
scopeId,
),
onColumnsChangeState: extractComponentState(
onColumnsChangeComponentState,
scopeId,

View File

@ -42,6 +42,8 @@ export const useRecordTable = (props?: useRecordTableProps) => {
isRecordTableInitialLoadingState,
tableLastRowVisibleState,
selectedRowIdsSelector,
onToggleColumnFilterState,
onToggleColumnSortState,
} = useRecordTableStates(recordTableId);
const setAvailableTableColumns = useRecoilCallback(
@ -70,6 +72,9 @@ export const useRecordTable = (props?: useRecordTableProps) => {
const setOnColumnsChange = useSetRecoilState(onColumnsChangeState);
const setOnToggleColumnFilter = useSetRecoilState(onToggleColumnFilterState);
const setOnToggleColumnSort = useSetRecoilState(onToggleColumnSortState);
const setIsRecordTableInitialLoading = useSetRecoilState(
isRecordTableInitialLoadingState,
);
@ -215,5 +220,7 @@ export const useRecordTable = (props?: useRecordTableProps) => {
isSomeCellInEditModeState,
selectedRowIdsSelector,
setHasUserSelectedAllRows,
setOnToggleColumnFilter,
setOnToggleColumnSort,
};
};

View File

@ -0,0 +1,8 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const onToggleColumnFilterComponentState = createComponentState<
((fieldMetadataId: string) => void) | undefined
>({
key: 'onToggleColumnFilterComponentState',
defaultValue: undefined,
});

View File

@ -0,0 +1,8 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const onToggleColumnSortComponentState = createComponentState<
((fieldMetadataId: string) => void) | undefined
>({
key: 'onToggleColumnSortComponentState',
defaultValue: undefined,
});

View File

@ -7,4 +7,6 @@ export type ColumnDefinition<T extends FieldMetadata> = FieldDefinition<T> & {
isLabelIdentifier?: boolean;
isVisible?: boolean;
viewFieldId?: string;
isFilterable?: boolean;
isSortable?: boolean;
};

View File

@ -14,6 +14,7 @@ import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
import { isDefined } from '~/utils/isDefined';
import { useDropdown } from '../hooks/useDropdown';
@ -92,7 +93,7 @@ export const Dropdown = ({
});
useInternalHotkeyScopeManagement({
dropdownScopeId: `${dropdownId}-scope`,
dropdownScopeId: getScopeIdFromComponentId(dropdownId),
dropdownHotkeyScopeFromParent: dropdownHotkeyScope,
});
@ -106,7 +107,7 @@ export const Dropdown = ({
);
return (
<DropdownScope dropdownScopeId={`${dropdownId}-scope`}>
<DropdownScope dropdownScopeId={getScopeIdFromComponentId(dropdownId)}>
<div ref={containerRef} className={className}>
{clickableComponent && (
<div

View File

@ -0,0 +1,85 @@
import { useRecoilCallback } from 'recoil';
import { dropdownHotkeyComponentState } from '@/ui/layout/dropdown/states/dropdownHotkeyComponentState';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
import { isDefined } from '~/utils/isDefined';
export const useDropdownV2 = () => {
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
const closeDropdown = useRecoilCallback(
({ set }) =>
(specificComponentId: string) => {
const scopeId = getScopeIdFromComponentId(specificComponentId);
goBackToPreviousHotkeyScope();
set(
isDropdownOpenComponentState({
scopeId,
}),
false,
);
},
[goBackToPreviousHotkeyScope],
);
const openDropdown = useRecoilCallback(
({ set, snapshot }) =>
(specificComponentId: string, customHotkeyScope?: HotkeyScope) => {
const scopeId = getScopeIdFromComponentId(specificComponentId);
const dropdownHotkeyScope = snapshot
.getLoadable(dropdownHotkeyComponentState({ scopeId }))
.getValue();
set(
isDropdownOpenComponentState({
scopeId,
}),
true,
);
if (isDefined(customHotkeyScope)) {
setHotkeyScopeAndMemorizePreviousScope(
customHotkeyScope.scope,
customHotkeyScope.customScopes,
);
} else if (isDefined(dropdownHotkeyScope)) {
setHotkeyScopeAndMemorizePreviousScope(
dropdownHotkeyScope.scope,
dropdownHotkeyScope.customScopes,
);
}
},
[setHotkeyScopeAndMemorizePreviousScope],
);
const toggleDropdown = useRecoilCallback(
({ snapshot }) =>
(specificComponentId: string) => {
const scopeId = getScopeIdFromComponentId(specificComponentId);
const isDropdownOpen = snapshot
.getLoadable(isDropdownOpenComponentState({ scopeId }))
.getValue();
if (isDropdownOpen) {
closeDropdown(specificComponentId);
} else {
openDropdown(specificComponentId);
}
},
[closeDropdown, openDropdown],
);
return {
closeDropdown,
openDropdown,
toggleDropdown,
};
};

View File

@ -74,7 +74,7 @@ export const EditableFilterDropdownButton = ({
return (
<Dropdown
dropdownId={viewFilter.fieldMetadataId}
dropdownId={viewFilterDropdownId}
clickableComponent={
<EditableFilterChip viewFilter={viewFilter} onRemove={handleRemove} />
}

View File

@ -4,7 +4,6 @@ import { useRecoilValue } from 'recoil';
import { AddObjectFilterFromDetailsButton } from '@/object-record/object-filter-dropdown/components/AddObjectFilterFromDetailsButton';
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { EditableFilterDropdownButton } from '@/views/components/EditableFilterDropdownButton';
import { EditableSortChip } from '@/views/components/EditableSortChip';
@ -161,7 +160,7 @@ export const ViewBarDetails = ({
<EditableFilterDropdownButton
viewFilter={viewFilter}
hotkeyScope={{
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
scope: viewFilter.fieldMetadataId,
}}
viewFilterDropdownId={viewFilter.fieldMetadataId}
/>

View File

@ -47,7 +47,9 @@ export const mapViewFieldsToColumnDefinitions = ({
isLabelIdentifier,
isVisible: isLabelIdentifier || viewField.isVisible,
viewFieldId: viewField.id,
};
isSortable: correspondingColumnDefinition.isSortable,
isFilterable: correspondingColumnDefinition.isFilterable,
} as ColumnDefinition<FieldMetadata>;
})
.filter(isDefined);

View File

@ -67,6 +67,7 @@ export {
IconFileText,
IconFileUpload,
IconFileZip,
IconFilter,
IconFilterOff,
IconFocusCentered,
IconForbid,
@ -119,6 +120,7 @@ export {
IconSearch,
IconSend,
IconSettings,
IconSortDescending,
IconTable,
IconTag,
IconTarget,