Implemented dropdown menu section label in filter and sort (#12453)
This PR implements a new component `DropdownMenuSectionLabel`, to be used for indicating visible and hidden fields in the multiple dropdowns that use those two sections. After : <img width="247" alt="Capture d’écran 2025-06-04 à 12 49 42" src="https://github.com/user-attachments/assets/759c48ca-c54d-4921-bea6-cbfe7a2d244d" /> <img width="252" alt="Capture d’écran 2025-06-04 à 12 49 20" src="https://github.com/user-attachments/assets/72cd63d0-e5d6-4000-897d-c16efd8396c9" /> <img width="359" alt="Capture d’écran 2025-06-04 à 12 48 44" src="https://github.com/user-attachments/assets/d7c41039-dc15-46d7-be89-33a39e226fb2" /> In this PR we also fix the scrolling behavior of those two sections so that it is more natural. The height mechanism will be properly refactored by this issue : https://github.com/twentyhq/twenty/issues/11766, in the mean time this temporary modification is working : https://github.com/user-attachments/assets/c7ddb424-66b9-41e3-a6a8-a29ece09d62e Some components that weren't used are also removed : `AdvancedFilterDropdownFieldSelectMenu`, `AdvancedFilterDropdownFieldSelectMenuItem` and `AdvancedFilterDropdownSubFieldSelectMenu` Fixes https://github.com/twentyhq/core-team-issues/issues/1000
This commit is contained in:
@ -1,81 +0,0 @@
|
|||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
|
||||||
|
|
||||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
|
||||||
|
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
|
|
||||||
import { AdvancedFilterDropdownFieldSelectMenuItem } from '@/object-record/advanced-filter/components/AdvancedFilterDropdownFieldSelectMenuItem';
|
|
||||||
import { FILTER_FIELD_LIST_ID } from '@/object-record/object-filter-dropdown/constants/FilterFieldListId';
|
|
||||||
import { useFilterDropdownSelectableFieldMetadataItems } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems';
|
|
||||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
|
||||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { useLingui } from '@lingui/react/macro';
|
|
||||||
|
|
||||||
export const AdvancedFilterDropdownFieldSelectMenu = () => {
|
|
||||||
const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownSearchInputComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
|
||||||
objectFilterDropdownSearchInputComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
selectableHiddenFieldMetadataItems,
|
|
||||||
selectableVisibleFieldMetadataItems,
|
|
||||||
} = useFilterDropdownSelectableFieldMetadataItems();
|
|
||||||
|
|
||||||
const shouldShowSeparator =
|
|
||||||
selectableVisibleFieldMetadataItems.length > 0 &&
|
|
||||||
selectableHiddenFieldMetadataItems.length > 0;
|
|
||||||
|
|
||||||
const { t } = useLingui();
|
|
||||||
|
|
||||||
const selectableFieldMetadataItemIds = [
|
|
||||||
...selectableVisibleFieldMetadataItems.map(
|
|
||||||
(fieldMetadataItem) => fieldMetadataItem.id,
|
|
||||||
),
|
|
||||||
...selectableHiddenFieldMetadataItems.map(
|
|
||||||
(fieldMetadataItem) => fieldMetadataItem.id,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DropdownMenuSearchInput
|
|
||||||
value={objectFilterDropdownSearchInput}
|
|
||||||
autoFocus
|
|
||||||
placeholder={t`Search fields`}
|
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
|
||||||
setObjectFilterDropdownSearchInput(event.target.value)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SelectableList
|
|
||||||
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
|
|
||||||
selectableItemIdArray={selectableFieldMetadataItemIds}
|
|
||||||
selectableListInstanceId={FILTER_FIELD_LIST_ID}
|
|
||||||
>
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
{selectableVisibleFieldMetadataItems.map(
|
|
||||||
(visibleFieldMetadataItem) => (
|
|
||||||
<AdvancedFilterDropdownFieldSelectMenuItem
|
|
||||||
key={visibleFieldMetadataItem.id}
|
|
||||||
fieldMetadataItemToSelect={visibleFieldMetadataItem}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
{shouldShowSeparator && <DropdownMenuSeparator />}
|
|
||||||
{selectableHiddenFieldMetadataItems.map((hiddenFieldMetadataItem) => (
|
|
||||||
<AdvancedFilterDropdownFieldSelectMenuItem
|
|
||||||
key={hiddenFieldMetadataItem.id}
|
|
||||||
fieldMetadataItemToSelect={hiddenFieldMetadataItem}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
</SelectableList>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,152 +0,0 @@
|
|||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
|
||||||
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
|
||||||
|
|
||||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
|
||||||
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
|
||||||
|
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
|
||||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
|
||||||
import { FILTER_FIELD_LIST_ID } from '@/object-record/object-filter-dropdown/constants/FilterFieldListId';
|
|
||||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
|
||||||
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
|
||||||
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
|
|
||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
|
||||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
|
||||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
|
||||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
|
||||||
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
|
||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
import { useIcons } from 'twenty-ui/display';
|
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
|
||||||
|
|
||||||
export type AdvancedFilterDropdownFieldSelectMenuItemProps = {
|
|
||||||
fieldMetadataItemToSelect: FieldMetadataItem;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AdvancedFilterDropdownFieldSelectMenuItem = ({
|
|
||||||
fieldMetadataItemToSelect,
|
|
||||||
}: AdvancedFilterDropdownFieldSelectMenuItemProps) => {
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setObjectFilterDropdownSubMenuFieldType] = useRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownSubMenuFieldTypeComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setObjectFilterDropdownIsSelectingCompositeField] =
|
|
||||||
useRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownFilterIsSelectedComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { resetSelectedItem } = useSelectableList(FILTER_FIELD_LIST_ID);
|
|
||||||
|
|
||||||
const isSelectedItem = useRecoilComponentFamilyValueV2(
|
|
||||||
isSelectedItemIdComponentFamilySelector,
|
|
||||||
fieldMetadataItemToSelect.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
selectedOperandInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
|
||||||
|
|
||||||
const currentRecordFilters = useRecoilComponentValueV2(
|
|
||||||
currentRecordFiltersComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setObjectFilterDropdownCurrentRecordFilter =
|
|
||||||
useSetRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectFilter = (fieldMetadataItem: FieldMetadataItem) => {
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(fieldMetadataItem.id);
|
|
||||||
|
|
||||||
const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type);
|
|
||||||
|
|
||||||
if (filterType === 'RELATION' || filterType === 'SELECT') {
|
|
||||||
setHotkeyScope(SingleRecordPickerHotkeyScope.SingleRecordPicker);
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultOperand = getRecordFilterOperands({
|
|
||||||
filterType,
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
setObjectFilterDropdownFilterIsSelected(true);
|
|
||||||
|
|
||||||
const duplicateFilterInCurrentRecordFilters =
|
|
||||||
findDuplicateRecordFilterInNonAdvancedRecordFilters({
|
|
||||||
recordFilters: currentRecordFilters,
|
|
||||||
fieldMetadataItemId: fieldMetadataItem.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const filterIsAlreadyInCurrentRecordFilters = isDefined(
|
|
||||||
duplicateFilterInCurrentRecordFilters,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (filterIsAlreadyInCurrentRecordFilters) {
|
|
||||||
setObjectFilterDropdownCurrentRecordFilter(
|
|
||||||
duplicateFilterInCurrentRecordFilters,
|
|
||||||
);
|
|
||||||
|
|
||||||
setSelectedOperandInDropdown(
|
|
||||||
duplicateFilterInCurrentRecordFilters.operand,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setSelectedOperandInDropdown(defaultOperand);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
|
||||||
|
|
||||||
const Icon = getIcon(fieldMetadataItemToSelect.icon);
|
|
||||||
|
|
||||||
const shouldShowSubMenu = isCompositeFieldType(
|
|
||||||
fieldMetadataItemToSelect.type,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
resetSelectedItem();
|
|
||||||
|
|
||||||
const filterType = getFilterTypeFromFieldType(
|
|
||||||
fieldMetadataItemToSelect.type,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isCompositeFieldType(filterType)) {
|
|
||||||
setObjectFilterDropdownSubMenuFieldType(filterType);
|
|
||||||
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(fieldMetadataItemToSelect.id);
|
|
||||||
setObjectFilterDropdownIsSelectingCompositeField(true);
|
|
||||||
} else {
|
|
||||||
handleSelectFilter(fieldMetadataItemToSelect);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SelectableListItem
|
|
||||||
itemId={fieldMetadataItemToSelect.id}
|
|
||||||
onEnter={handleClick}
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
focused={isSelectedItem}
|
|
||||||
onClick={handleClick}
|
|
||||||
LeftIcon={Icon}
|
|
||||||
text={fieldMetadataItemToSelect.label}
|
|
||||||
hasSubMenu={shouldShowSubMenu}
|
|
||||||
/>
|
|
||||||
</SelectableListItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,257 +0,0 @@
|
|||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
|
||||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
|
||||||
import { FILTER_FIELD_LIST_ID } from '@/object-record/object-filter-dropdown/constants/FilterFieldListId';
|
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
|
||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
|
||||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
|
||||||
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
|
||||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
|
||||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
|
||||||
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
|
||||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
|
||||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
|
||||||
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
|
||||||
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
|
|
||||||
import { ICON_NAME_BY_SUB_FIELD } from '@/object-record/record-filter/constants/IconNameBySubField';
|
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
|
||||||
import { areCompositeTypeSubFieldsFilterable } from '@/object-record/record-filter/utils/areCompositeTypeSubFieldsFilterable';
|
|
||||||
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
|
|
||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
|
||||||
import { isCompositeTypeFilterableByAnySubField } from '@/object-record/record-filter/utils/isCompositeTypeFilterableByAnySubField';
|
|
||||||
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
|
||||||
import { CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
|
||||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
|
||||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { StyledInput } from '@/views/components/ViewBarFilterDropdownFieldSelectMenu';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
import { IconApps, IconChevronLeft, useIcons } from 'twenty-ui/display';
|
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
|
||||||
|
|
||||||
export const AdvancedFilterDropdownSubFieldSelectMenu = () => {
|
|
||||||
const [searchText, setSearchText] = useState('');
|
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
|
||||||
|
|
||||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
|
||||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSubFieldNameUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
subFieldNameUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownFilterIsSelectedComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setObjectFilterDropdownIsSelectingCompositeField] =
|
|
||||||
useRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [
|
|
||||||
objectFilterDropdownSubMenuFieldType,
|
|
||||||
setObjectFilterDropdownSubMenuFieldType,
|
|
||||||
] = useRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownSubMenuFieldTypeComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
selectedOperandInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownSearchInputComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentRecordFilters = useRecoilComponentValueV2(
|
|
||||||
currentRecordFiltersComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setObjectFilterDropdownCurrentRecordFilter =
|
|
||||||
useSetRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectFilter = (
|
|
||||||
fieldMetadataItem: FieldMetadataItem | null | undefined,
|
|
||||||
subFieldName?: CompositeFieldSubFieldName | null | undefined,
|
|
||||||
) => {
|
|
||||||
if (!isDefined(fieldMetadataItem)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const type = getFilterTypeFromFieldType(fieldMetadataItem.type);
|
|
||||||
|
|
||||||
const defaultOperand = getRecordFilterOperands({
|
|
||||||
filterType: type,
|
|
||||||
subFieldName: subFieldName,
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(fieldMetadataItem.id);
|
|
||||||
|
|
||||||
setSubFieldNameUsedInDropdown(subFieldName);
|
|
||||||
|
|
||||||
setObjectFilterDropdownSearchInput('');
|
|
||||||
|
|
||||||
setObjectFilterDropdownFilterIsSelected(true);
|
|
||||||
|
|
||||||
const duplicateFilterInCurrentRecordFilters =
|
|
||||||
findDuplicateRecordFilterInNonAdvancedRecordFilters({
|
|
||||||
recordFilters: currentRecordFilters,
|
|
||||||
fieldMetadataItemId: fieldMetadataItem.id,
|
|
||||||
subFieldName,
|
|
||||||
});
|
|
||||||
|
|
||||||
const filterIsAlreadyInCurrentRecordFilters = isDefined(
|
|
||||||
duplicateFilterInCurrentRecordFilters,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (filterIsAlreadyInCurrentRecordFilters) {
|
|
||||||
setObjectFilterDropdownCurrentRecordFilter(
|
|
||||||
duplicateFilterInCurrentRecordFilters,
|
|
||||||
);
|
|
||||||
|
|
||||||
setSelectedOperandInDropdown(
|
|
||||||
duplicateFilterInCurrentRecordFilters.operand,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setSelectedOperandInDropdown(defaultOperand);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubMenuBack = () => {
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(null);
|
|
||||||
setObjectFilterDropdownSubMenuFieldType(null);
|
|
||||||
setObjectFilterDropdownIsSelectingCompositeField(false);
|
|
||||||
setObjectFilterDropdownFilterIsSelected(false);
|
|
||||||
setSubFieldNameUsedInDropdown(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectedItemId = useRecoilComponentValueV2(
|
|
||||||
selectedItemIdComponentState,
|
|
||||||
FILTER_FIELD_LIST_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isDefined(objectFilterDropdownSubMenuFieldType)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS[
|
|
||||||
objectFilterDropdownSubMenuFieldType
|
|
||||||
].filterableSubFields
|
|
||||||
.sort((a, b) => a.localeCompare(b))
|
|
||||||
.filter((item) =>
|
|
||||||
item.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()),
|
|
||||||
);
|
|
||||||
|
|
||||||
const subFieldsAreFilterable =
|
|
||||||
isDefined(fieldMetadataItemUsedInDropdown) &&
|
|
||||||
areCompositeTypeSubFieldsFilterable(fieldMetadataItemUsedInDropdown.type);
|
|
||||||
|
|
||||||
const compositeFieldTypeFilterableByAnySubField =
|
|
||||||
isDefined(fieldMetadataItemUsedInDropdown) &&
|
|
||||||
isCompositeTypeFilterableByAnySubField(
|
|
||||||
fieldMetadataItemUsedInDropdown.type,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DropdownMenuHeader
|
|
||||||
StartComponent={
|
|
||||||
<DropdownMenuHeaderLeftComponent
|
|
||||||
onClick={handleSubMenuBack}
|
|
||||||
Icon={IconChevronLeft}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)}
|
|
||||||
</DropdownMenuHeader>
|
|
||||||
<StyledInput
|
|
||||||
value={searchText}
|
|
||||||
autoFocus
|
|
||||||
placeholder="Search fields"
|
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
|
||||||
setSearchText(event.target.value)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
<SelectableList
|
|
||||||
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
|
|
||||||
selectableItemIdArray={['-1', ...options]}
|
|
||||||
selectableListInstanceId={FILTER_FIELD_LIST_ID}
|
|
||||||
>
|
|
||||||
{compositeFieldTypeFilterableByAnySubField ? (
|
|
||||||
<SelectableListItem
|
|
||||||
itemId={'-1'}
|
|
||||||
key={`select-filter-${-1}`}
|
|
||||||
onEnter={() => {
|
|
||||||
handleSelectFilter(fieldMetadataItemUsedInDropdown);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
key={`select-filter-${-1}`}
|
|
||||||
testId={`select-filter-${-1}`}
|
|
||||||
onClick={() => {
|
|
||||||
handleSelectFilter(fieldMetadataItemUsedInDropdown);
|
|
||||||
}}
|
|
||||||
LeftIcon={IconApps}
|
|
||||||
text={`Any ${getFilterableFieldTypeLabel(objectFilterDropdownSubMenuFieldType)} field`}
|
|
||||||
/>
|
|
||||||
</SelectableListItem>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
{subFieldsAreFilterable &&
|
|
||||||
options.map((subFieldName, index) => (
|
|
||||||
<SelectableListItem
|
|
||||||
itemId={subFieldName}
|
|
||||||
key={`select-filter-${index}`}
|
|
||||||
onEnter={() => {
|
|
||||||
handleSelectFilter(
|
|
||||||
fieldMetadataItemUsedInDropdown,
|
|
||||||
subFieldName,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
focused={selectedItemId === subFieldName}
|
|
||||||
key={`select-filter-${index}`}
|
|
||||||
testId={`select-filter-${index}`}
|
|
||||||
onClick={() => {
|
|
||||||
if (isDefined(fieldMetadataItemUsedInDropdown)) {
|
|
||||||
handleSelectFilter(
|
|
||||||
fieldMetadataItemUsedInDropdown,
|
|
||||||
subFieldName,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
text={getCompositeSubFieldLabel(
|
|
||||||
objectFilterDropdownSubMenuFieldType,
|
|
||||||
subFieldName,
|
|
||||||
)}
|
|
||||||
LeftIcon={getIcon(
|
|
||||||
ICON_NAME_BY_SUB_FIELD[subFieldName] ??
|
|
||||||
fieldMetadataItemUsedInDropdown?.icon,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</SelectableListItem>
|
|
||||||
))}
|
|
||||||
</SelectableList>
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -22,8 +22,10 @@ import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-rec
|
|||||||
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
||||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
|
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
|
||||||
type AdvancedFilterFieldSelectMenuProps = {
|
type AdvancedFilterFieldSelectMenuProps = {
|
||||||
recordFilterId: string;
|
recordFilterId: string;
|
||||||
@ -119,6 +121,9 @@ export const AdvancedFilterFieldSelectMenu = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const shouldShowVisibleFields = visibleColumnsFieldMetadataItems.length > 0;
|
||||||
|
const shouldShowHiddenFields = hiddenColumnsFieldMetadataItems.length > 0;
|
||||||
|
|
||||||
const shouldShowSeparator =
|
const shouldShowSeparator =
|
||||||
visibleColumnsFieldMetadataItems.length > 0 &&
|
visibleColumnsFieldMetadataItems.length > 0 &&
|
||||||
hiddenColumnsFieldMetadataItems.length > 0;
|
hiddenColumnsFieldMetadataItems.length > 0;
|
||||||
@ -132,6 +137,8 @@ export const AdvancedFilterFieldSelectMenu = ({
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const { t } = useLingui();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownContent>
|
<DropdownContent>
|
||||||
<AdvancedFilterFieldSelectSearchInput />
|
<AdvancedFilterFieldSelectSearchInput />
|
||||||
@ -140,41 +147,53 @@ export const AdvancedFilterFieldSelectMenu = ({
|
|||||||
selectableItemIdArray={selectableItemIdArray}
|
selectableItemIdArray={selectableItemIdArray}
|
||||||
selectableListInstanceId={advancedFilterFieldSelectDropdownId}
|
selectableListInstanceId={advancedFilterFieldSelectDropdownId}
|
||||||
>
|
>
|
||||||
<DropdownMenuItemsContainer>
|
{shouldShowVisibleFields && (
|
||||||
{visibleColumnsFieldMetadataItems.map(
|
<>
|
||||||
(visibleFieldMetadataItem, index) => (
|
<DropdownMenuSectionLabel label={t`Visible fields`} />
|
||||||
<SelectableListItem
|
<DropdownMenuItemsContainer scrollWrapperHeightAuto>
|
||||||
itemId={visibleFieldMetadataItem.id}
|
{visibleColumnsFieldMetadataItems.map(
|
||||||
key={`visible-select-filter-${index}`}
|
(visibleFieldMetadataItem, index) => (
|
||||||
onEnter={() => {
|
<SelectableListItem
|
||||||
handleFieldMetadataItemSelect(visibleFieldMetadataItem);
|
itemId={visibleFieldMetadataItem.id}
|
||||||
}}
|
key={`visible-select-filter-${index}`}
|
||||||
>
|
onEnter={() => {
|
||||||
<ObjectFilterDropdownFilterSelectMenuItemV2
|
handleFieldMetadataItemSelect(visibleFieldMetadataItem);
|
||||||
fieldMetadataItemToSelect={visibleFieldMetadataItem}
|
}}
|
||||||
onClick={handleFieldMetadataItemSelect}
|
>
|
||||||
/>
|
<ObjectFilterDropdownFilterSelectMenuItemV2
|
||||||
</SelectableListItem>
|
fieldMetadataItemToSelect={visibleFieldMetadataItem}
|
||||||
),
|
onClick={handleFieldMetadataItemSelect}
|
||||||
)}
|
/>
|
||||||
{shouldShowSeparator && <DropdownMenuSeparator />}
|
</SelectableListItem>
|
||||||
{hiddenColumnsFieldMetadataItems.map(
|
),
|
||||||
(hiddenFieldMetadataItem, index) => (
|
)}
|
||||||
<SelectableListItem
|
</DropdownMenuItemsContainer>
|
||||||
itemId={hiddenFieldMetadataItem.id}
|
</>
|
||||||
key={`hidden-select-filter-${index}`}
|
)}
|
||||||
onEnter={() => {
|
{shouldShowSeparator && <DropdownMenuSeparator />}
|
||||||
handleFieldMetadataItemSelect(hiddenFieldMetadataItem);
|
{shouldShowHiddenFields && (
|
||||||
}}
|
<>
|
||||||
>
|
<DropdownMenuSectionLabel label={t`Hidden fields`} />
|
||||||
<ObjectFilterDropdownFilterSelectMenuItemV2
|
<DropdownMenuItemsContainer scrollWrapperHeightAuto>
|
||||||
fieldMetadataItemToSelect={hiddenFieldMetadataItem}
|
{hiddenColumnsFieldMetadataItems.map(
|
||||||
onClick={handleFieldMetadataItemSelect}
|
(hiddenFieldMetadataItem, index) => (
|
||||||
/>
|
<SelectableListItem
|
||||||
</SelectableListItem>
|
itemId={hiddenFieldMetadataItem.id}
|
||||||
),
|
key={`hidden-select-filter-${index}`}
|
||||||
)}
|
onEnter={() => {
|
||||||
</DropdownMenuItemsContainer>
|
handleFieldMetadataItemSelect(hiddenFieldMetadataItem);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ObjectFilterDropdownFilterSelectMenuItemV2
|
||||||
|
fieldMetadataItemToSelect={hiddenFieldMetadataItem}
|
||||||
|
onClick={handleFieldMetadataItemSelect}
|
||||||
|
/>
|
||||||
|
</SelectableListItem>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
</DropdownContent>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
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';
|
||||||
@ -216,6 +217,9 @@ export const ObjectSortDropdownButton = ({
|
|||||||
OBJECT_SORT_DROPDOWN_ID,
|
OBJECT_SORT_DROPDOWN_ID,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const shouldShowHiddenFields = hiddenFieldMetadataItems.length > 0;
|
||||||
|
const shouldShowVisibleFields = visibleFieldMetadataItems.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
dropdownId={OBJECT_SORT_DROPDOWN_ID}
|
dropdownId={OBJECT_SORT_DROPDOWN_ID}
|
||||||
@ -279,43 +283,61 @@ export const ObjectSortDropdownButton = ({
|
|||||||
setObjectSortDropdownSearchInput(event.target.value)
|
setObjectSortDropdownSearchInput(event.target.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<DropdownMenuItemsContainer scrollable={false}>
|
{shouldShowVisibleFields && (
|
||||||
{visibleFieldMetadataItems.map(
|
<>
|
||||||
(visibleFieldMetadataItem, index) => (
|
<DropdownMenuSectionLabel label={t`Visible fields`} />
|
||||||
<SelectableListItem
|
<DropdownMenuItemsContainer scrollWrapperHeightAuto>
|
||||||
key={visibleFieldMetadataItem.id}
|
{visibleFieldMetadataItems.map(
|
||||||
itemId={visibleFieldMetadataItem.id}
|
(visibleFieldMetadataItem, index) => (
|
||||||
onEnter={() => handleAddSort(visibleFieldMetadataItem)}
|
<SelectableListItem
|
||||||
>
|
key={visibleFieldMetadataItem.id}
|
||||||
<MenuItem
|
itemId={visibleFieldMetadataItem.id}
|
||||||
focused={selectedItemId === visibleFieldMetadataItem.id}
|
onEnter={() => handleAddSort(visibleFieldMetadataItem)}
|
||||||
testId={`visible-select-sort-${index}`}
|
>
|
||||||
onClick={() => handleAddSort(visibleFieldMetadataItem)}
|
<MenuItem
|
||||||
LeftIcon={getIcon(visibleFieldMetadataItem.icon)}
|
focused={
|
||||||
text={visibleFieldMetadataItem.label}
|
selectedItemId === visibleFieldMetadataItem.id
|
||||||
/>
|
}
|
||||||
</SelectableListItem>
|
testId={`visible-select-sort-${index}`}
|
||||||
),
|
onClick={() =>
|
||||||
)}
|
handleAddSort(visibleFieldMetadataItem)
|
||||||
{shouldShowSeparator && <DropdownMenuSeparator />}
|
}
|
||||||
{hiddenFieldMetadataItems.map(
|
LeftIcon={getIcon(visibleFieldMetadataItem.icon)}
|
||||||
(hiddenFieldMetadataItem, index) => (
|
text={visibleFieldMetadataItem.label}
|
||||||
<SelectableListItem
|
/>
|
||||||
key={hiddenFieldMetadataItem.id}
|
</SelectableListItem>
|
||||||
itemId={hiddenFieldMetadataItem.id}
|
),
|
||||||
onEnter={() => handleAddSort(hiddenFieldMetadataItem)}
|
)}
|
||||||
>
|
</DropdownMenuItemsContainer>
|
||||||
<MenuItem
|
</>
|
||||||
focused={selectedItemId === hiddenFieldMetadataItem.id}
|
)}
|
||||||
testId={`hidden-select-sort-${index}`}
|
{shouldShowSeparator && <DropdownMenuSeparator />}
|
||||||
onClick={() => handleAddSort(hiddenFieldMetadataItem)}
|
{shouldShowHiddenFields && (
|
||||||
LeftIcon={getIcon(hiddenFieldMetadataItem.icon)}
|
<>
|
||||||
text={hiddenFieldMetadataItem.label}
|
<DropdownMenuSectionLabel label={t`Hidden fields`} />
|
||||||
/>
|
<DropdownMenuItemsContainer scrollWrapperHeightAuto>
|
||||||
</SelectableListItem>
|
{hiddenFieldMetadataItems.map(
|
||||||
),
|
(hiddenFieldMetadataItem, index) => (
|
||||||
)}
|
<SelectableListItem
|
||||||
</DropdownMenuItemsContainer>
|
key={hiddenFieldMetadataItem.id}
|
||||||
|
itemId={hiddenFieldMetadataItem.id}
|
||||||
|
onEnter={() => handleAddSort(hiddenFieldMetadataItem)}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
focused={
|
||||||
|
selectedItemId === hiddenFieldMetadataItem.id
|
||||||
|
}
|
||||||
|
testId={`hidden-select-sort-${index}`}
|
||||||
|
onClick={() => handleAddSort(hiddenFieldMetadataItem)}
|
||||||
|
LeftIcon={getIcon(hiddenFieldMetadataItem.icon)}
|
||||||
|
text={hiddenFieldMetadataItem.label}
|
||||||
|
/>
|
||||||
|
</SelectableListItem>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</SelectableList>
|
</SelectableList>
|
||||||
</DropdownContent>
|
</DropdownContent>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,12 +49,14 @@ export const DropdownMenuItemsContainer = ({
|
|||||||
className,
|
className,
|
||||||
scrollable = true,
|
scrollable = true,
|
||||||
width = 'auto',
|
width = 'auto',
|
||||||
|
scrollWrapperHeightAuto,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
hasMaxHeight?: boolean;
|
hasMaxHeight?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
scrollable?: boolean;
|
scrollable?: boolean;
|
||||||
width?: number | 'auto' | '100%';
|
width?: number | 'auto' | '100%';
|
||||||
|
scrollWrapperHeightAuto?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const id = useId();
|
const id = useId();
|
||||||
|
|
||||||
@ -68,6 +70,7 @@ export const DropdownMenuItemsContainer = ({
|
|||||||
{hasMaxHeight ? (
|
{hasMaxHeight ? (
|
||||||
<StyledScrollWrapper
|
<StyledScrollWrapper
|
||||||
componentInstanceId={`scroll-wrapper-dropdown-menu-${id}`}
|
componentInstanceId={`scroll-wrapper-dropdown-menu-${id}`}
|
||||||
|
heightAuto={scrollWrapperHeightAuto}
|
||||||
>
|
>
|
||||||
<StyledDropdownMenuItemsInternalContainer>
|
<StyledDropdownMenuItemsInternalContainer>
|
||||||
{children}
|
{children}
|
||||||
@ -80,7 +83,10 @@ export const DropdownMenuItemsContainer = ({
|
|||||||
)}
|
)}
|
||||||
</StyledDropdownMenuItemsExternalContainer>
|
</StyledDropdownMenuItemsExternalContainer>
|
||||||
) : (
|
) : (
|
||||||
<ScrollWrapper componentInstanceId={`scroll-wrapper-dropdown-menu-${id}`}>
|
<ScrollWrapper
|
||||||
|
componentInstanceId={`scroll-wrapper-dropdown-menu-${id}`}
|
||||||
|
heightAuto={scrollWrapperHeightAuto}
|
||||||
|
>
|
||||||
<StyledDropdownMenuItemsExternalContainer
|
<StyledDropdownMenuItemsExternalContainer
|
||||||
hasMaxHeight={hasMaxHeight}
|
hasMaxHeight={hasMaxHeight}
|
||||||
className={className}
|
className={className}
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledDropdownMenuSectionLabel = styled.div`
|
||||||
|
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
||||||
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
|
min-height: 20px;
|
||||||
|
width: auto;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xxs};
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(1)};
|
||||||
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type DropdownMenuSectionLabelProps = {
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DropdownMenuSectionLabel = ({
|
||||||
|
label,
|
||||||
|
}: DropdownMenuSectionLabelProps) => {
|
||||||
|
return (
|
||||||
|
<StyledDropdownMenuSectionLabel>{label}</StyledDropdownMenuSectionLabel>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -7,7 +7,7 @@ import { scrollWrapperScrollLeftComponentState } from '@/ui/utilities/scroll/sta
|
|||||||
import { scrollWrapperScrollTopComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState';
|
import { scrollWrapperScrollTopComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
|
||||||
const StyledScrollWrapper = styled.div`
|
const StyledScrollWrapper = styled.div<{ height: string }>`
|
||||||
&.scroll-wrapper-x-enabled {
|
&.scroll-wrapper-x-enabled {
|
||||||
overflow-x: overlay;
|
overflow-x: overlay;
|
||||||
}
|
}
|
||||||
@ -17,7 +17,7 @@ const StyledScrollWrapper = styled.div`
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: ${({ height }) => height};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export type ScrollWrapperProps = {
|
export type ScrollWrapperProps = {
|
||||||
@ -26,6 +26,7 @@ export type ScrollWrapperProps = {
|
|||||||
defaultEnableXScroll?: boolean;
|
defaultEnableXScroll?: boolean;
|
||||||
defaultEnableYScroll?: boolean;
|
defaultEnableYScroll?: boolean;
|
||||||
componentInstanceId: string;
|
componentInstanceId: string;
|
||||||
|
heightAuto?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ScrollWrapper = ({
|
export const ScrollWrapper = ({
|
||||||
@ -34,6 +35,7 @@ export const ScrollWrapper = ({
|
|||||||
className,
|
className,
|
||||||
defaultEnableXScroll = true,
|
defaultEnableXScroll = true,
|
||||||
defaultEnableYScroll = true,
|
defaultEnableYScroll = true,
|
||||||
|
heightAuto = false,
|
||||||
}: ScrollWrapperProps) => {
|
}: ScrollWrapperProps) => {
|
||||||
const setScrollTop = useSetRecoilComponentStateV2(
|
const setScrollTop = useSetRecoilComponentStateV2(
|
||||||
scrollWrapperScrollTopComponentState,
|
scrollWrapperScrollTopComponentState,
|
||||||
@ -71,6 +73,7 @@ export const ScrollWrapper = ({
|
|||||||
id={`scroll-wrapper-${componentInstanceId}`}
|
id={`scroll-wrapper-${componentInstanceId}`}
|
||||||
className={className}
|
className={className}
|
||||||
onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
|
height={heightAuto ? 'auto' : '100%'}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</StyledScrollWrapper>
|
</StyledScrollWrapper>
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { FILTER_FIELD_LIST_ID } from '@/object-record/object-filter-dropdown/con
|
|||||||
import { useFilterDropdownSelectableFieldMetadataItems } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems';
|
import { useFilterDropdownSelectableFieldMetadataItems } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdownSelectableFieldMetadataItems';
|
||||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
|
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { ViewBarFilterDropdownBottomMenu } from '@/views/components/ViewBarFilterDropdownBottomMenu';
|
import { ViewBarFilterDropdownBottomMenu } from '@/views/components/ViewBarFilterDropdownBottomMenu';
|
||||||
import { ViewBarFilterDropdownFieldSelectMenuItem } from '@/views/components/ViewBarFilterDropdownFieldSelectMenuItem';
|
import { ViewBarFilterDropdownFieldSelectMenuItem } from '@/views/components/ViewBarFilterDropdownFieldSelectMenuItem';
|
||||||
@ -73,6 +74,10 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => {
|
|||||||
selectableVisibleFieldMetadataItems.length > 0 ||
|
selectableVisibleFieldMetadataItems.length > 0 ||
|
||||||
selectableHiddenFieldMetadataItems.length > 0;
|
selectableHiddenFieldMetadataItems.length > 0;
|
||||||
|
|
||||||
|
const shouldShowVisibleFields =
|
||||||
|
selectableVisibleFieldMetadataItems.length > 0;
|
||||||
|
const shouldShowHiddenFields = selectableHiddenFieldMetadataItems.length > 0;
|
||||||
|
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -90,26 +95,37 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => {
|
|||||||
selectableItemIdArray={selectableFieldMetadataItemIds}
|
selectableItemIdArray={selectableFieldMetadataItemIds}
|
||||||
selectableListInstanceId={FILTER_FIELD_LIST_ID}
|
selectableListInstanceId={FILTER_FIELD_LIST_ID}
|
||||||
>
|
>
|
||||||
{hasSelectableItems && (
|
{shouldShowVisibleFields && (
|
||||||
<DropdownMenuItemsContainer>
|
<>
|
||||||
{selectableVisibleFieldMetadataItems.map(
|
<DropdownMenuSectionLabel label={t`Visible fields`} />
|
||||||
(visibleFieldMetadataItem) => (
|
|
||||||
<ViewBarFilterDropdownFieldSelectMenuItem
|
<DropdownMenuItemsContainer scrollWrapperHeightAuto>
|
||||||
key={visibleFieldMetadataItem.id}
|
{selectableVisibleFieldMetadataItems.map(
|
||||||
fieldMetadataItemToSelect={visibleFieldMetadataItem}
|
(visibleFieldMetadataItem) => (
|
||||||
/>
|
<ViewBarFilterDropdownFieldSelectMenuItem
|
||||||
),
|
key={visibleFieldMetadataItem.id}
|
||||||
)}
|
fieldMetadataItemToSelect={visibleFieldMetadataItem}
|
||||||
{shouldShowSeparator && <DropdownMenuSeparator />}
|
/>
|
||||||
{selectableHiddenFieldMetadataItems.map(
|
),
|
||||||
(hiddenFieldMetadataItem) => (
|
)}
|
||||||
<ViewBarFilterDropdownFieldSelectMenuItem
|
</DropdownMenuItemsContainer>
|
||||||
key={hiddenFieldMetadataItem.id}
|
</>
|
||||||
fieldMetadataItemToSelect={hiddenFieldMetadataItem}
|
)}
|
||||||
/>
|
{shouldShowSeparator && <DropdownMenuSeparator />}
|
||||||
),
|
{shouldShowHiddenFields && (
|
||||||
)}
|
<>
|
||||||
</DropdownMenuItemsContainer>
|
<DropdownMenuSectionLabel label={t`Hidden fields`} />
|
||||||
|
<DropdownMenuItemsContainer scrollWrapperHeightAuto>
|
||||||
|
{selectableHiddenFieldMetadataItems.map(
|
||||||
|
(hiddenFieldMetadataItem) => (
|
||||||
|
<ViewBarFilterDropdownFieldSelectMenuItem
|
||||||
|
key={hiddenFieldMetadataItem.id}
|
||||||
|
fieldMetadataItemToSelect={hiddenFieldMetadataItem}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{hasSelectableItems && <DropdownMenuSeparator />}
|
{hasSelectableItems && <DropdownMenuSeparator />}
|
||||||
<ViewBarFilterDropdownBottomMenu />
|
<ViewBarFilterDropdownBottomMenu />
|
||||||
|
|||||||
Reference in New Issue
Block a user