Removed availableFilterDefinitions as a state but kept its usage as a derived state of objectMetadataItems (#9972)
The global record filter refactor will derive everything at runtime from objectMetadataItemsState, thus removing the need for a filter definition concept. Here we don't yet remove available filter definition usage but we replace the available filter definitions states, we now derive the same value from objectMetadataItemsState. This will allow us to progressively remove the usage of the concept of filter definition, at the end it will then be easy to just remove from the codebase because nothing will use it anymore.
This commit is contained in:
@ -0,0 +1,41 @@
|
|||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { getFilterFilterableFieldMetadataItems } from '@/object-metadata/utils/getFilterFilterableFieldMetadataItems';
|
||||||
|
import { checkIfFeatureFlagIsEnabledOnWorkspace } from '@/workspace/utils/checkIfFeatureFlagIsEnabledOnWorkspace';
|
||||||
|
import { selectorFamily } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
|
export const availableFieldMetadataItemsForFilterFamilySelector =
|
||||||
|
selectorFamily({
|
||||||
|
key: 'availableFieldMetadataItemsForFilterFamilySelector',
|
||||||
|
get:
|
||||||
|
({ objectMetadataItemId }: { objectMetadataItemId: string }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const currentWorkspace = get(currentWorkspaceState);
|
||||||
|
const objectMetadataItems = get(objectMetadataItemsState);
|
||||||
|
|
||||||
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
|
(item) => item.id === objectMetadataItemId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(objectMetadataItem)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const isJsonFeatureFlagEnabled = checkIfFeatureFlagIsEnabledOnWorkspace(
|
||||||
|
FeatureFlagKey.IsJsonFilterEnabled,
|
||||||
|
currentWorkspace,
|
||||||
|
);
|
||||||
|
|
||||||
|
const filterFilterableFieldMetadataItems =
|
||||||
|
getFilterFilterableFieldMetadataItems({
|
||||||
|
isJsonFilterEnabled: isJsonFeatureFlagEnabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
const availableFieldMetadataItemsForFilter =
|
||||||
|
objectMetadataItem.fields.filter(filterFilterableFieldMetadataItems);
|
||||||
|
|
||||||
|
return availableFieldMetadataItemsForFilter;
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
|
import {
|
||||||
|
FieldMetadataType,
|
||||||
|
RelationDefinitionType,
|
||||||
|
} from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
|
export const getFilterFilterableFieldMetadataItems = ({
|
||||||
|
isJsonFilterEnabled,
|
||||||
|
}: {
|
||||||
|
isJsonFilterEnabled: boolean;
|
||||||
|
}) => {
|
||||||
|
return (field: FieldMetadataItem) => {
|
||||||
|
const isSystemField = field.isSystem;
|
||||||
|
const isFieldActive = field.isActive;
|
||||||
|
|
||||||
|
const isRelationFieldHandled = !(
|
||||||
|
field.type === FieldMetadataType.RELATION &&
|
||||||
|
field.relationDefinition?.direction !==
|
||||||
|
RelationDefinitionType.MANY_TO_ONE &&
|
||||||
|
field.relationDefinition?.direction !== RelationDefinitionType.ONE_TO_ONE
|
||||||
|
);
|
||||||
|
|
||||||
|
const isFieldTypeFilterable = [
|
||||||
|
FieldMetadataType.BOOLEAN,
|
||||||
|
FieldMetadataType.DATE_TIME,
|
||||||
|
FieldMetadataType.DATE,
|
||||||
|
FieldMetadataType.TEXT,
|
||||||
|
FieldMetadataType.EMAILS,
|
||||||
|
FieldMetadataType.NUMBER,
|
||||||
|
FieldMetadataType.LINKS,
|
||||||
|
FieldMetadataType.FULL_NAME,
|
||||||
|
FieldMetadataType.ADDRESS,
|
||||||
|
FieldMetadataType.RELATION,
|
||||||
|
FieldMetadataType.SELECT,
|
||||||
|
FieldMetadataType.MULTI_SELECT,
|
||||||
|
FieldMetadataType.CURRENCY,
|
||||||
|
FieldMetadataType.RATING,
|
||||||
|
FieldMetadataType.ACTOR,
|
||||||
|
FieldMetadataType.PHONES,
|
||||||
|
FieldMetadataType.ARRAY,
|
||||||
|
...(isJsonFilterEnabled ? [FieldMetadataType.RAW_JSON] : []),
|
||||||
|
].includes(field.type);
|
||||||
|
|
||||||
|
const isFieldFilterable =
|
||||||
|
!isSystemField &&
|
||||||
|
isFieldActive &&
|
||||||
|
isRelationFieldHandled &&
|
||||||
|
isFieldTypeFilterable;
|
||||||
|
|
||||||
|
return isFieldFilterable;
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,17 +1,18 @@
|
|||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
|
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
|
||||||
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||||
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { IconLibraryPlus, IconPlus, LightButton, MenuItem } from 'twenty-ui';
|
import { IconLibraryPlus, IconPlus, LightButton, MenuItem } from 'twenty-ui';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
@ -41,7 +42,7 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
const objectMetadataId =
|
const objectMetadataId =
|
||||||
currentViewWithCombinedFiltersAndSorts?.objectMetadataId;
|
currentViewWithCombinedFiltersAndSorts?.objectMetadataId;
|
||||||
|
|
||||||
if (!objectMetadataId) {
|
if (!isDefined(objectMetadataId)) {
|
||||||
throw new Error('Object metadata id is missing from current view');
|
throw new Error('Object metadata id is missing from current view');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,33 +50,45 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
objectId: objectMetadataId,
|
objectId: objectMetadataId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const availableFieldMetadataItemsForFilter = useRecoilValue(
|
||||||
availableFilterDefinitionsComponentState,
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataId,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const getDefaultFilterDefinition = useCallback(() => {
|
const getDefaultFieldMetadataItem = useCallback(() => {
|
||||||
const defaultFilterDefinition =
|
const defaultFieldMetadataItem =
|
||||||
availableFilterDefinitions.find(
|
availableFieldMetadataItemsForFilter.find(
|
||||||
(filterDefinition) =>
|
(fieldMetadataItem) =>
|
||||||
filterDefinition.fieldMetadataId ===
|
fieldMetadataItem.id ===
|
||||||
objectMetadataItem?.labelIdentifierFieldMetadataId,
|
objectMetadataItem?.labelIdentifierFieldMetadataId,
|
||||||
) ?? availableFilterDefinitions?.[0];
|
) ?? availableFieldMetadataItemsForFilter[0];
|
||||||
|
|
||||||
if (!defaultFilterDefinition) {
|
if (!isDefined(defaultFieldMetadataItem)) {
|
||||||
throw new Error('Missing default filter definition');
|
throw new Error(
|
||||||
|
`Could not find default field metadata item for object ${objectMetadataId}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultFilterDefinition;
|
return defaultFieldMetadataItem;
|
||||||
}, [availableFilterDefinitions, objectMetadataItem]);
|
}, [
|
||||||
|
availableFieldMetadataItemsForFilter,
|
||||||
|
objectMetadataItem,
|
||||||
|
objectMetadataId,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleAddFilter = () => {
|
const handleAddFilter = () => {
|
||||||
closeDropdown();
|
closeDropdown();
|
||||||
|
|
||||||
const defaultFilterDefinition = getDefaultFilterDefinition();
|
const defaultFieldMetadataItem = getDefaultFieldMetadataItem();
|
||||||
|
|
||||||
|
const defaultFilterDefinition = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: defaultFieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
upsertCombinedViewFilter({
|
upsertCombinedViewFilter({
|
||||||
id: v4(),
|
id: v4(),
|
||||||
fieldMetadataId: defaultFilterDefinition.fieldMetadataId,
|
fieldMetadataId: defaultFieldMetadataItem.id,
|
||||||
operand: getRecordFilterOperandsForRecordFilterDefinition(
|
operand: getRecordFilterOperandsForRecordFilterDefinition(
|
||||||
defaultFilterDefinition,
|
defaultFilterDefinition,
|
||||||
)[0],
|
)[0],
|
||||||
@ -104,11 +117,15 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
|
|
||||||
upsertCombinedViewFilterGroup(newViewFilterGroup);
|
upsertCombinedViewFilterGroup(newViewFilterGroup);
|
||||||
|
|
||||||
const defaultFilterDefinition = getDefaultFilterDefinition();
|
const defaultFieldMetadataItem = getDefaultFieldMetadataItem();
|
||||||
|
|
||||||
|
const defaultFilterDefinition = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: defaultFieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
upsertCombinedViewFilter({
|
upsertCombinedViewFilter({
|
||||||
id: v4(),
|
id: v4(),
|
||||||
fieldMetadataId: defaultFilterDefinition.fieldMetadataId,
|
fieldMetadataId: defaultFieldMetadataItem.id,
|
||||||
operand: getRecordFilterOperandsForRecordFilterDefinition(
|
operand: getRecordFilterOperandsForRecordFilterDefinition(
|
||||||
defaultFilterDefinition,
|
defaultFilterDefinition,
|
||||||
)[0],
|
)[0],
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useFilterDefinitionsFromFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterDefinitionsFromFilterableFieldMetadataItems';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
|
|
||||||
export const useCurrentViewFilter = ({
|
export const useCurrentViewFilter = ({
|
||||||
@ -8,9 +7,8 @@ export const useCurrentViewFilter = ({
|
|||||||
}: {
|
}: {
|
||||||
viewFilterId?: string;
|
viewFilterId?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const { filterDefinitions } =
|
||||||
availableFilterDefinitionsComponentState,
|
useFilterDefinitionsFromFilterableFieldMetadataItems();
|
||||||
);
|
|
||||||
|
|
||||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||||
|
|
||||||
@ -22,10 +20,7 @@ export const useCurrentViewFilter = ({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [filter] = mapViewFiltersToFilters(
|
const [filter] = mapViewFiltersToFilters([viewFilter], filterDefinitions);
|
||||||
[viewFilter],
|
|
||||||
availableFilterDefinitions,
|
|
||||||
);
|
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
|
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup';
|
||||||
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 { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
import {
|
import {
|
||||||
IconFilter,
|
IconFilter,
|
||||||
MenuItemLeftContent,
|
MenuItemLeftContent,
|
||||||
@ -66,8 +68,10 @@ export const AdvancedFilterButton = () => {
|
|||||||
objectId: objectMetadataId ?? null,
|
objectId: objectMetadataId ?? null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const availableFieldMetadataItemsForFilter = useRecoilValue(
|
||||||
availableFilterDefinitionsComponentState,
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@ -88,24 +92,27 @@ export const AdvancedFilterButton = () => {
|
|||||||
|
|
||||||
upsertCombinedViewFilterGroup(newViewFilterGroup);
|
upsertCombinedViewFilterGroup(newViewFilterGroup);
|
||||||
|
|
||||||
const defaultFilterDefinition =
|
const defaultFieldMetadataItem =
|
||||||
availableFilterDefinitions.find(
|
availableFieldMetadataItemsForFilter.find(
|
||||||
(filterDefinition) =>
|
(fieldMetadataItem) =>
|
||||||
filterDefinition.fieldMetadataId ===
|
fieldMetadataItem.id ===
|
||||||
objectMetadataItem?.labelIdentifierFieldMetadataId,
|
objectMetadataItem?.labelIdentifierFieldMetadataId,
|
||||||
) ?? availableFilterDefinitions?.[0];
|
) ?? availableFieldMetadataItemsForFilter[0];
|
||||||
|
|
||||||
if (!defaultFilterDefinition) {
|
if (!isDefined(defaultFieldMetadataItem)) {
|
||||||
throw new Error('Missing default filter definition');
|
throw new Error('Missing default filter definition');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: defaultFieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
upsertCombinedViewFilter({
|
upsertCombinedViewFilter({
|
||||||
id: v4(),
|
id: v4(),
|
||||||
fieldMetadataId: defaultFilterDefinition.fieldMetadataId,
|
fieldMetadataId: defaultFieldMetadataItem.id,
|
||||||
operand: getRecordFilterOperandsForRecordFilterDefinition(
|
operand:
|
||||||
defaultFilterDefinition,
|
getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0],
|
||||||
)[0],
|
definition: filterDefinition,
|
||||||
definition: defaultFilterDefinition,
|
|
||||||
value: '',
|
value: '',
|
||||||
displayValue: '',
|
displayValue: '',
|
||||||
viewFilterGroupId: newViewFilterGroup.id,
|
viewFilterGroupId: newViewFilterGroup.id,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
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 { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton';
|
import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton';
|
||||||
import { SingleEntityObjectFilterDropdownButton } from './SingleEntityObjectFilterDropdownButton';
|
import { SingleEntityObjectFilterDropdownButton } from './SingleEntityObjectFilterDropdownButton';
|
||||||
|
|
||||||
@ -15,16 +14,13 @@ export const ObjectFilterDropdownButton = ({
|
|||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
}: ObjectFilterDropdownButtonProps) => {
|
}: ObjectFilterDropdownButtonProps) => {
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems();
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
filterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const hasOnlyOneEntityFilter =
|
const hasOnlyOneEntityFilter =
|
||||||
availableFilterDefinitions.length === 1 &&
|
filterableFieldMetadataItems.length === 1 &&
|
||||||
availableFilterDefinitions[0].type === 'RELATION';
|
filterableFieldMetadataItems[0].type === 'RELATION';
|
||||||
|
|
||||||
if (!availableFilterDefinitions.length) {
|
if (!filterableFieldMetadataItems.length) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,14 +19,15 @@ import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectab
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState';
|
import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||||
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
|
||||||
export const StyledInput = styled.input`
|
export const StyledInput = styled.input`
|
||||||
@ -80,9 +81,7 @@ export const ObjectFilterDropdownFilterSelect = ({
|
|||||||
advancedFilterViewFilterId,
|
advancedFilterViewFilterId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems();
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const visibleTableColumns = useRecoilComponentValueV2(
|
const visibleTableColumns = useRecoilComponentValueV2(
|
||||||
visibleTableColumnsComponentSelector,
|
visibleTableColumnsComponentSelector,
|
||||||
@ -99,29 +98,29 @@ export const ObjectFilterDropdownFilterSelect = ({
|
|||||||
(column) => column.fieldMetadataId,
|
(column) => column.fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const filteredSearchInputFilterDefinitions =
|
const filteredSearchInputFieldMetadataItems =
|
||||||
availableFilterDefinitions.filter((item) =>
|
filterableFieldMetadataItems.filter((fieldMetadataItem) =>
|
||||||
item.label
|
fieldMetadataItem.label
|
||||||
.toLocaleLowerCase()
|
.toLocaleLowerCase()
|
||||||
.includes(objectFilterDropdownSearchInput.toLocaleLowerCase()),
|
.includes(objectFilterDropdownSearchInput.toLocaleLowerCase()),
|
||||||
);
|
);
|
||||||
|
|
||||||
const visibleColumnsFilterDefinitions = filteredSearchInputFilterDefinitions
|
const visibleColumnsFieldMetadataItems = filteredSearchInputFieldMetadataItems
|
||||||
|
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return (
|
return visibleColumnsIds.indexOf(a.id) - visibleColumnsIds.indexOf(b.id);
|
||||||
visibleColumnsIds.indexOf(a.fieldMetadataId) -
|
|
||||||
visibleColumnsIds.indexOf(b.fieldMetadataId)
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.filter((item) => visibleColumnsIds.includes(item.fieldMetadataId));
|
.filter((fieldMetadataItem) =>
|
||||||
|
visibleColumnsIds.includes(fieldMetadataItem.id),
|
||||||
|
);
|
||||||
|
|
||||||
const hiddenColumnsFilterDefinitions = filteredSearchInputFilterDefinitions
|
const hiddenColumnsFieldMetadataItems = filteredSearchInputFieldMetadataItems
|
||||||
.sort((a, b) => a.label.localeCompare(b.label))
|
.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
.filter((item) => hiddenColumnIds.includes(item.fieldMetadataId));
|
.filter((fieldMetadataItem) =>
|
||||||
|
hiddenColumnIds.includes(fieldMetadataItem.id),
|
||||||
|
);
|
||||||
|
|
||||||
const selectableListItemIds = availableFilterDefinitions.map(
|
const selectableFieldMetadataItemIds = filterableFieldMetadataItems.map(
|
||||||
(item) => item.fieldMetadataId,
|
(fieldMetadataItem) => fieldMetadataItem.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { selectFilterDefinitionUsedInDropdown } =
|
const { selectFilterDefinitionUsedInDropdown } =
|
||||||
@ -134,16 +133,20 @@ export const ObjectFilterDropdownFilterSelect = ({
|
|||||||
const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
|
const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
|
||||||
|
|
||||||
const handleEnter = (fieldMetadataItemId: string) => {
|
const handleEnter = (fieldMetadataItemId: string) => {
|
||||||
const selectedFilterDefinition = availableFilterDefinitions.find(
|
const selectedFieldMetadataItem = filterableFieldMetadataItems.find(
|
||||||
(item) => item.fieldMetadataId === fieldMetadataItemId,
|
(fieldMetadataItem) => fieldMetadataItem.id === fieldMetadataItemId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isDefined(selectedFilterDefinition)) {
|
if (!isDefined(selectedFieldMetadataItem)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSelectedItem();
|
resetSelectedItem();
|
||||||
|
|
||||||
|
const selectedFilterDefinition = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: selectedFieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
selectFilterDefinitionUsedInDropdown({
|
selectFilterDefinitionUsedInDropdown({
|
||||||
filterDefinition: selectedFilterDefinition,
|
filterDefinition: selectedFilterDefinition,
|
||||||
});
|
});
|
||||||
@ -156,8 +159,8 @@ export const ObjectFilterDropdownFilterSelect = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const shoudShowSeparator =
|
const shoudShowSeparator =
|
||||||
visibleColumnsFilterDefinitions.length > 0 &&
|
visibleColumnsFieldMetadataItems.length > 0 &&
|
||||||
hiddenColumnsFilterDefinitions.length > 0;
|
hiddenColumnsFieldMetadataItems.length > 0;
|
||||||
|
|
||||||
const { currentViewId, currentViewWithCombinedFiltersAndSorts } =
|
const { currentViewId, currentViewWithCombinedFiltersAndSorts } =
|
||||||
useGetCurrentView();
|
useGetCurrentView();
|
||||||
@ -186,32 +189,32 @@ export const ObjectFilterDropdownFilterSelect = ({
|
|||||||
/>
|
/>
|
||||||
<SelectableList
|
<SelectableList
|
||||||
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
|
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
|
||||||
selectableItemIdArray={selectableListItemIds}
|
selectableItemIdArray={selectableFieldMetadataItemIds}
|
||||||
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
|
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
|
||||||
onEnter={handleEnter}
|
onEnter={handleEnter}
|
||||||
>
|
>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{visibleColumnsFilterDefinitions.map(
|
{visibleColumnsFieldMetadataItems.map(
|
||||||
(visibleFilterDefinition, index) => (
|
(visibleFieldMetadataItem, index) => (
|
||||||
<SelectableItem
|
<SelectableItem
|
||||||
itemId={visibleFilterDefinition.fieldMetadataId}
|
itemId={visibleFieldMetadataItem.id}
|
||||||
key={`visible-select-filter-${index}`}
|
key={`visible-select-filter-${index}`}
|
||||||
>
|
>
|
||||||
<ObjectFilterDropdownFilterSelectMenuItem
|
<ObjectFilterDropdownFilterSelectMenuItem
|
||||||
filterDefinition={visibleFilterDefinition}
|
fieldMetadataItemToSelect={visibleFieldMetadataItem}
|
||||||
/>
|
/>
|
||||||
</SelectableItem>
|
</SelectableItem>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
{shoudShowSeparator && <DropdownMenuSeparator />}
|
{shoudShowSeparator && <DropdownMenuSeparator />}
|
||||||
{hiddenColumnsFilterDefinitions.map(
|
{hiddenColumnsFieldMetadataItems.map(
|
||||||
(hiddenFilterDefinition, index) => (
|
(hiddenFieldMetadataItem, index) => (
|
||||||
<SelectableItem
|
<SelectableItem
|
||||||
itemId={hiddenFilterDefinition.fieldMetadataId}
|
itemId={hiddenFieldMetadataItem.id}
|
||||||
key={`hidden-select-filter-${index}`}
|
key={`hidden-select-filter-${index}`}
|
||||||
>
|
>
|
||||||
<ObjectFilterDropdownFilterSelectMenuItem
|
<ObjectFilterDropdownFilterSelectMenuItem
|
||||||
filterDefinition={hiddenFilterDefinition}
|
fieldMetadataItemToSelect={hiddenFieldMetadataItem}
|
||||||
/>
|
/>
|
||||||
</SelectableItem>
|
</SelectableItem>
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown';
|
import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown';
|
||||||
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 { useSelectFilterDefinitionUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown';
|
|
||||||
import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState';
|
import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||||
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||||
@ -9,8 +7,12 @@ import { objectFilterDropdownFirstLevelFilterDefinitionComponentState } from '@/
|
|||||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||||
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
|
|
||||||
import { CompositeFilterableFieldType } from '@/object-record/record-filter/types/CompositeFilterableFieldType';
|
import { CompositeFilterableFieldType } from '@/object-record/record-filter/types/CompositeFilterableFieldType';
|
||||||
|
|
||||||
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
|
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
||||||
|
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
|
||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
||||||
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
||||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
@ -23,15 +25,12 @@ import { useRecoilValue } from 'recoil';
|
|||||||
import { MenuItemSelect, useIcons } from 'twenty-ui';
|
import { MenuItemSelect, useIcons } from 'twenty-ui';
|
||||||
|
|
||||||
export type ObjectFilterDropdownFilterSelectMenuItemProps = {
|
export type ObjectFilterDropdownFilterSelectMenuItemProps = {
|
||||||
filterDefinition: RecordFilterDefinition;
|
fieldMetadataItemToSelect: FieldMetadataItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
||||||
filterDefinition,
|
fieldMetadataItemToSelect,
|
||||||
}: ObjectFilterDropdownFilterSelectMenuItemProps) => {
|
}: ObjectFilterDropdownFilterSelectMenuItemProps) => {
|
||||||
const { selectFilterDefinitionUsedInDropdown } =
|
|
||||||
useSelectFilterDefinitionUsedInDropdown();
|
|
||||||
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
fieldMetadataItemIdUsedInDropdownComponentState,
|
||||||
);
|
);
|
||||||
@ -58,16 +57,24 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
OBJECT_FILTER_DROPDOWN_ID,
|
OBJECT_FILTER_DROPDOWN_ID,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const filterDefinitionToSelect = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: fieldMetadataItemToSelect,
|
||||||
|
});
|
||||||
|
|
||||||
const isSelectedItem = useRecoilValue(
|
const isSelectedItem = useRecoilValue(
|
||||||
isSelectedItemIdSelector(filterDefinition.fieldMetadataId),
|
isSelectedItemIdSelector(fieldMetadataItemToSelect.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
const isACompositeField = isCompositeField(filterDefinition.type);
|
const isACompositeField = isCompositeField(fieldMetadataItemToSelect.type);
|
||||||
|
|
||||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
||||||
selectedOperandInDropdownComponentState,
|
selectedOperandInDropdownComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setFilterDefinitionUsedInDropdown = useSetRecoilComponentStateV2(
|
||||||
|
filterDefinitionUsedInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const advancedFilterViewFilterId = useRecoilComponentValueV2(
|
const advancedFilterViewFilterId = useRecoilComponentValueV2(
|
||||||
advancedFilterViewFilterIdComponentState,
|
advancedFilterViewFilterIdComponentState,
|
||||||
);
|
);
|
||||||
@ -83,13 +90,10 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
) => {
|
) => {
|
||||||
closeAdvancedFilterDropdown();
|
closeAdvancedFilterDropdown();
|
||||||
|
|
||||||
selectFilterDefinitionUsedInDropdown({
|
|
||||||
filterDefinition: availableFilterDefinition,
|
|
||||||
});
|
|
||||||
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(
|
setFieldMetadataItemIdUsedInDropdown(
|
||||||
availableFilterDefinition.fieldMetadataId,
|
availableFilterDefinition.fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
availableFilterDefinition.type === 'RELATION' ||
|
availableFilterDefinition.type === 'RELATION' ||
|
||||||
@ -115,12 +119,14 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
if (isACompositeField) {
|
if (isACompositeField) {
|
||||||
// TODO: create isCompositeFilterableFieldType type guard
|
// TODO: create isCompositeFilterableFieldType type guard
|
||||||
setObjectFilterDropdownSubMenuFieldType(
|
setObjectFilterDropdownSubMenuFieldType(
|
||||||
filterDefinition.type as CompositeFilterableFieldType,
|
filterDefinitionToSelect.type as CompositeFilterableFieldType,
|
||||||
|
);
|
||||||
|
setObjectFilterDropdownFirstLevelFilterDefinition(
|
||||||
|
filterDefinitionToSelect,
|
||||||
);
|
);
|
||||||
setObjectFilterDropdownFirstLevelFilterDefinition(filterDefinition);
|
|
||||||
setObjectFilterDropdownIsSelectingCompositeField(true);
|
setObjectFilterDropdownIsSelectingCompositeField(true);
|
||||||
} else {
|
} else {
|
||||||
handleSelectFilterDefinition(filterDefinition);
|
handleSelectFilterDefinition(filterDefinitionToSelect);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,8 +135,8 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
selected={false}
|
selected={false}
|
||||||
hovered={isSelectedItem}
|
hovered={isSelectedItem}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
LeftIcon={getIcon(filterDefinition.iconName)}
|
LeftIcon={getIcon(filterDefinitionToSelect.iconName)}
|
||||||
text={filterDefinition.label}
|
text={filterDefinitionToSelect.label}
|
||||||
hasSubMenu={isACompositeField}
|
hasSubMenu={isACompositeField}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import React from 'react';
|
|
||||||
import { IconChevronDown } from 'twenty-ui';
|
import { IconChevronDown } from 'twenty-ui';
|
||||||
|
|
||||||
import { ObjectFilterDropdownRecordRemoveFilterMenuItem } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordRemoveFilterMenuItem';
|
import { ObjectFilterDropdownRecordRemoveFilterMenuItem } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordRemoveFilterMenuItem';
|
||||||
@ -8,15 +7,10 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
|||||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
import { SingleEntityObjectFilterDropdownButtonEffect } from '@/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButtonEffect';
|
||||||
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
|
||||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { getRecordFilterOperandsForRecordFilterDefinition } from '../../record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
|
||||||
import { GenericEntityFilterChip } from './GenericEntityFilterChip';
|
import { GenericEntityFilterChip } from './GenericEntityFilterChip';
|
||||||
import { ObjectFilterDropdownRecordSelect } from './ObjectFilterDropdownRecordSelect';
|
import { ObjectFilterDropdownRecordSelect } from './ObjectFilterDropdownRecordSelect';
|
||||||
import { ObjectFilterDropdownSearchInput } from './ObjectFilterDropdownSearchInput';
|
import { ObjectFilterDropdownSearchInput } from './ObjectFilterDropdownSearchInput';
|
||||||
@ -32,68 +26,37 @@ export const SingleEntityObjectFilterDropdownButton = ({
|
|||||||
selectedFilterComponentState,
|
selectedFilterComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setFilterDefinitionUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
filterDefinitionUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
selectedOperandInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const availableFilterDefinition = availableFilterDefinitions[0];
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(
|
|
||||||
availableFilterDefinition.fieldMetadataId,
|
|
||||||
);
|
|
||||||
setFilterDefinitionUsedInDropdown(availableFilterDefinition);
|
|
||||||
const defaultOperand = getRecordFilterOperandsForRecordFilterDefinition(
|
|
||||||
availableFilterDefinition,
|
|
||||||
)[0];
|
|
||||||
setSelectedOperandInDropdown(defaultOperand);
|
|
||||||
}, [
|
|
||||||
availableFilterDefinition,
|
|
||||||
setFilterDefinitionUsedInDropdown,
|
|
||||||
setSelectedOperandInDropdown,
|
|
||||||
setFieldMetadataItemIdUsedInDropdown,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<>
|
||||||
dropdownId={SINGLE_ENTITY_FILTER_DROPDOWN_ID}
|
<SingleEntityObjectFilterDropdownButtonEffect />
|
||||||
dropdownHotkeyScope={hotkeyScope}
|
<Dropdown
|
||||||
dropdownOffset={{ x: 0, y: -28 }}
|
dropdownId={SINGLE_ENTITY_FILTER_DROPDOWN_ID}
|
||||||
clickableComponent={
|
dropdownHotkeyScope={hotkeyScope}
|
||||||
<StyledHeaderDropdownButton>
|
dropdownOffset={{ x: 0, y: -28 }}
|
||||||
{selectedFilter ? (
|
clickableComponent={
|
||||||
<GenericEntityFilterChip filter={selectedFilter} />
|
<StyledHeaderDropdownButton>
|
||||||
) : (
|
{selectedFilter ? (
|
||||||
t`Filter`
|
<GenericEntityFilterChip filter={selectedFilter} />
|
||||||
)}
|
) : (
|
||||||
<IconChevronDown size={theme.icon.size.md} />
|
t`Filter`
|
||||||
</StyledHeaderDropdownButton>
|
)}
|
||||||
}
|
<IconChevronDown size={theme.icon.size.md} />
|
||||||
dropdownComponents={
|
</StyledHeaderDropdownButton>
|
||||||
<>
|
}
|
||||||
<ObjectFilterDropdownSearchInput />
|
dropdownComponents={
|
||||||
<DropdownMenuSeparator />
|
<>
|
||||||
<ObjectFilterDropdownRecordRemoveFilterMenuItem />
|
<ObjectFilterDropdownSearchInput />
|
||||||
<ObjectFilterDropdownRecordSelect
|
<DropdownMenuSeparator />
|
||||||
viewComponentId={SINGLE_ENTITY_FILTER_DROPDOWN_ID}
|
<ObjectFilterDropdownRecordRemoveFilterMenuItem />
|
||||||
/>
|
<ObjectFilterDropdownRecordSelect
|
||||||
</>
|
viewComponentId={SINGLE_ENTITY_FILTER_DROPDOWN_ID}
|
||||||
}
|
/>
|
||||||
/>
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
|
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||||
|
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
||||||
|
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
|
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export const SingleEntityObjectFilterDropdownButtonEffect = () => {
|
||||||
|
const setFilterDefinitionUsedInDropdown = useSetRecoilComponentStateV2(
|
||||||
|
filterDefinitionUsedInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
||||||
|
fieldMetadataItemIdUsedInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
||||||
|
selectedOperandInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems();
|
||||||
|
|
||||||
|
const firstFieldMetadataItem = filterableFieldMetadataItems[0];
|
||||||
|
|
||||||
|
const firstFieldDefinition = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: firstFieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFieldMetadataItemIdUsedInDropdown(firstFieldDefinition.fieldMetadataId);
|
||||||
|
setFilterDefinitionUsedInDropdown(firstFieldDefinition);
|
||||||
|
|
||||||
|
const defaultOperand =
|
||||||
|
getRecordFilterOperandsForRecordFilterDefinition(firstFieldDefinition)[0];
|
||||||
|
|
||||||
|
setSelectedOperandInDropdown(defaultOperand);
|
||||||
|
}, [
|
||||||
|
firstFieldDefinition,
|
||||||
|
setFilterDefinitionUsedInDropdown,
|
||||||
|
setSelectedOperandInDropdown,
|
||||||
|
setFieldMetadataItemIdUsedInDropdown,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@ -4,7 +4,6 @@ import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
|||||||
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
|
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||||
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
|
||||||
import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton';
|
import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton';
|
||||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||||
@ -12,7 +11,6 @@ import { RecordIndexContextProvider } from '@/object-record/record-index/context
|
|||||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||||
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 { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
import { within } from '@storybook/test';
|
import { within } from '@storybook/test';
|
||||||
import {
|
import {
|
||||||
@ -35,10 +33,6 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
(item) => item.nameSingular === CoreObjectNameSingular.Company,
|
(item) => item.nameSingular === CoreObjectNameSingular.Company,
|
||||||
)!;
|
)!;
|
||||||
const instanceId = 'entity-tasks-filter-scope';
|
const instanceId = 'entity-tasks-filter-scope';
|
||||||
const setAvailableFilterDefinitions = useSetRecoilComponentStateV2(
|
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
instanceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setTableColumns = useSetRecoilComponentStateV2(
|
const setTableColumns = useSetRecoilComponentStateV2(
|
||||||
tableColumnsComponentState,
|
tableColumnsComponentState,
|
||||||
@ -54,17 +48,8 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const filterDefinitions = companyObjectMetadataItem.fields.map(
|
|
||||||
(fieldMetadataItem) =>
|
|
||||||
formatFieldMetadataItemAsFilterDefinition({
|
|
||||||
field: fieldMetadataItem,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
setTableColumns(columns);
|
setTableColumns(columns);
|
||||||
|
|
||||||
setAvailableFilterDefinitions(filterDefinitions);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordIndexContextProvider
|
<RecordIndexContextProvider
|
||||||
value={{
|
value={{
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { advancedFilterViewFilterGroupIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterGroupIdComponentState';
|
import { advancedFilterViewFilterGroupIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterGroupIdComponentState';
|
||||||
import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState';
|
import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
|
||||||
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
||||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
@ -27,11 +26,6 @@ export const useSelectFilterDefinitionUsedInDropdown = (
|
|||||||
componentInstanceId,
|
componentInstanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
|
||||||
componentInstanceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
||||||
selectedOperandInDropdownComponentState,
|
selectedOperandInDropdownComponentState,
|
||||||
componentInstanceId,
|
componentInstanceId,
|
||||||
@ -60,7 +54,6 @@ export const useSelectFilterDefinitionUsedInDropdown = (
|
|||||||
filterDefinition,
|
filterDefinition,
|
||||||
}: SelectFilterParams) => {
|
}: SelectFilterParams) => {
|
||||||
setFilterDefinitionUsedInDropdown(filterDefinition);
|
setFilterDefinitionUsedInDropdown(filterDefinition);
|
||||||
setFieldMetadataItemIdUsedInDropdown(filterDefinition.fieldMetadataId);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
filterDefinition.type === 'RELATION' ||
|
filterDefinition.type === 'RELATION' ||
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
|
||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
|
||||||
|
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
|
||||||
|
|
||||||
export const availableFilterDefinitionsComponentState = createComponentStateV2<
|
|
||||||
RecordFilterDefinition[]
|
|
||||||
>({
|
|
||||||
key: 'availableFilterDefinitionsComponentState',
|
|
||||||
defaultValue: [],
|
|
||||||
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
|
||||||
});
|
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
export const useFilterDefinitionsFromFilterableFieldMetadataItems = () => {
|
||||||
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const availableFieldMetadataItemsForFilter = useRecoilValue(
|
||||||
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const filterDefinitions = availableFieldMetadataItemsForFilter.map(
|
||||||
|
(fieldMetadataItem) =>
|
||||||
|
formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: fieldMetadataItem,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return { filterDefinitions };
|
||||||
|
};
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
export const useFilterableFieldMetadataItems = () => {
|
||||||
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const filterableFieldMetadataItems = useRecoilValue(
|
||||||
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return { filterableFieldMetadataItems };
|
||||||
|
};
|
||||||
@ -26,6 +26,7 @@ import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActio
|
|||||||
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||||
|
import { useFilterDefinitionsFromFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterDefinitionsFromFilterableFieldMetadataItems';
|
||||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||||
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
||||||
@ -76,7 +77,7 @@ export const RecordIndexContainer = () => {
|
|||||||
|
|
||||||
const setRecordGroup = useSetRecordGroup(recordIndexId);
|
const setRecordGroup = useSetRecordGroup(recordIndexId);
|
||||||
|
|
||||||
const { columnDefinitions, filterDefinitions, sortDefinitions } =
|
const { columnDefinitions, sortDefinitions } =
|
||||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||||
|
|
||||||
const setRecordIndexViewFilterGroups = useSetRecoilState(
|
const setRecordIndexViewFilterGroups = useSetRecoilState(
|
||||||
@ -179,6 +180,9 @@ export const RecordIndexContainer = () => {
|
|||||||
contextStoreTargetedRecordsRuleComponentState,
|
contextStoreTargetedRecordsRuleComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { filterDefinitions } =
|
||||||
|
useFilterDefinitionsFromFilterableFieldMetadataItems();
|
||||||
|
|
||||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -23,13 +23,12 @@ export const RecordIndexViewBarEffect = ({
|
|||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { columnDefinitions, filterDefinitions, sortDefinitions } =
|
const { columnDefinitions, sortDefinitions } =
|
||||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setViewObjectMetadataId,
|
setViewObjectMetadataId,
|
||||||
setAvailableSortDefinitions,
|
setAvailableSortDefinitions,
|
||||||
setAvailableFilterDefinitions,
|
|
||||||
setAvailableFieldDefinitions,
|
setAvailableFieldDefinitions,
|
||||||
} = useInitViewBar(viewBarId);
|
} = useInitViewBar(viewBarId);
|
||||||
|
|
||||||
@ -39,15 +38,12 @@ export const RecordIndexViewBarEffect = ({
|
|||||||
}
|
}
|
||||||
setViewObjectMetadataId?.(objectMetadataItem.id);
|
setViewObjectMetadataId?.(objectMetadataItem.id);
|
||||||
setAvailableSortDefinitions?.(sortDefinitions);
|
setAvailableSortDefinitions?.(sortDefinitions);
|
||||||
setAvailableFilterDefinitions?.(filterDefinitions);
|
|
||||||
setAvailableFieldDefinitions?.(columnDefinitions);
|
setAvailableFieldDefinitions?.(columnDefinitions);
|
||||||
}, [
|
}, [
|
||||||
setViewObjectMetadataId,
|
setViewObjectMetadataId,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
setAvailableSortDefinitions,
|
setAvailableSortDefinitions,
|
||||||
sortDefinitions,
|
sortDefinitions,
|
||||||
setAvailableFilterDefinitions,
|
|
||||||
filterDefinitions,
|
|
||||||
setAvailableFieldDefinitions,
|
setAvailableFieldDefinitions,
|
||||||
columnDefinitions,
|
columnDefinitions,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -4,19 +4,19 @@ import { v4 } from 'uuid';
|
|||||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
|
||||||
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { useSelectFilterDefinitionUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown';
|
import { useSelectFilterDefinitionUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterDefinitionUsedInDropdown';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
||||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
import { useRecoilCallback } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
type UseHandleToggleColumnFilterProps = {
|
type UseHandleToggleColumnFilterProps = {
|
||||||
@ -49,8 +49,10 @@ export const useHandleToggleColumnFilter = ({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const availableFieldMetadataItemsForFilter = useRecoilValue(
|
||||||
availableFilterDefinitionsComponentState,
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||||
@ -80,10 +82,19 @@ export const useHandleToggleColumnFilter = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!existingViewFilter) {
|
if (!existingViewFilter) {
|
||||||
const filterDefinition = availableFilterDefinitions.find(
|
const fieldMetadataItem = availableFieldMetadataItemsForFilter.find(
|
||||||
(fd) => fd.fieldMetadataId === fieldMetadataId,
|
(fieldMetadataItemToFind) =>
|
||||||
|
fieldMetadataItemToFind.id === fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!isDefined(fieldMetadataItem)) {
|
||||||
|
throw new Error('Field metadata item not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: fieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
if (!isDefined(filterDefinition)) {
|
if (!isDefined(filterDefinition)) {
|
||||||
throw new Error('Filter definition not found');
|
throw new Error('Filter definition not found');
|
||||||
}
|
}
|
||||||
@ -118,7 +129,7 @@ export const useHandleToggleColumnFilter = ({
|
|||||||
upsertCombinedViewFilter,
|
upsertCombinedViewFilter,
|
||||||
selectFilterDefinitionUsedInDropdown,
|
selectFilterDefinitionUsedInDropdown,
|
||||||
currentViewWithCombinedFiltersAndSorts,
|
currentViewWithCombinedFiltersAndSorts,
|
||||||
availableFilterDefinitions,
|
availableFieldMetadataItemsForFilter,
|
||||||
upsertRecordFilter,
|
upsertRecordFilter,
|
||||||
setFieldMetadataItemIdUsedInDropdown,
|
setFieldMetadataItemIdUsedInDropdown,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObje
|
|||||||
import { useSetRecordIndexEntityCount } from '@/object-record/record-index/hooks/useSetRecordIndexEntityCount';
|
import { useSetRecordIndexEntityCount } from '@/object-record/record-index/hooks/useSetRecordIndexEntityCount';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions';
|
import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions';
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockFilterDefinitions';
|
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockSortDefinitions';
|
import { SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockSortDefinitions';
|
||||||
import { SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS } from '@/sign-in-background-mock/constants/SignInBackgroundMockViewFields';
|
import { SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS } from '@/sign-in-background-mock/constants/SignInBackgroundMockViewFields';
|
||||||
import { useInitViewBar } from '@/views/hooks/useInitViewBar';
|
import { useInitViewBar } from '@/views/hooks/useInitViewBar';
|
||||||
@ -37,7 +36,6 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
setAvailableSortDefinitions,
|
setAvailableSortDefinitions,
|
||||||
setAvailableFilterDefinitions,
|
|
||||||
setAvailableFieldDefinitions,
|
setAvailableFieldDefinitions,
|
||||||
setViewObjectMetadataId,
|
setViewObjectMetadataId,
|
||||||
} = useInitViewBar(viewId);
|
} = useInitViewBar(viewId);
|
||||||
@ -48,7 +46,6 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
setViewObjectMetadataId?.(objectMetadataItem.id);
|
setViewObjectMetadataId?.(objectMetadataItem.id);
|
||||||
|
|
||||||
setAvailableSortDefinitions?.(SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS);
|
setAvailableSortDefinitions?.(SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS);
|
||||||
setAvailableFilterDefinitions?.(SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS);
|
|
||||||
setAvailableFieldDefinitions?.(SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS);
|
setAvailableFieldDefinitions?.(SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS);
|
||||||
|
|
||||||
setAvailableTableColumns(SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS);
|
setAvailableTableColumns(SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS);
|
||||||
@ -62,7 +59,6 @@ export const SignInBackgroundMockContainerEffect = ({
|
|||||||
}, [
|
}, [
|
||||||
setViewObjectMetadataId,
|
setViewObjectMetadataId,
|
||||||
setAvailableSortDefinitions,
|
setAvailableSortDefinitions,
|
||||||
setAvailableFilterDefinitions,
|
|
||||||
setAvailableFieldDefinitions,
|
setAvailableFieldDefinitions,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
|
|||||||
@ -1,23 +1,16 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { EditableFilterChip } from '@/views/components/EditableFilterChip';
|
import { EditableFilterChip } from '@/views/components/EditableFilterChip';
|
||||||
|
|
||||||
import { ObjectFilterOperandSelectAndInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterOperandSelectAndInput';
|
import { ObjectFilterOperandSelectAndInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterOperandSelectAndInput';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
|
||||||
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
|
||||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
|
||||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { EditableFilterDropdownButtonEffect } from '@/views/components/EditableFilterDropdownButtonEffect';
|
||||||
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
type EditableFilterDropdownButtonProps = {
|
type EditableFilterDropdownButtonProps = {
|
||||||
viewFilterDropdownId: string;
|
viewFilterDropdownId: string;
|
||||||
@ -30,57 +23,10 @@ export const EditableFilterDropdownButton = ({
|
|||||||
viewFilter,
|
viewFilter,
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
}: EditableFilterDropdownButtonProps) => {
|
}: EditableFilterDropdownButtonProps) => {
|
||||||
const setFilterDefinitionUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
filterDefinitionUsedInDropdownComponentState,
|
|
||||||
viewFilterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
selectedOperandInDropdownComponentState,
|
|
||||||
viewFilterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedFilter = useSetRecoilComponentStateV2(
|
|
||||||
selectedFilterComponentState,
|
|
||||||
viewFilterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: verify this instance id works
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
viewFilterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown(viewFilterDropdownId);
|
const { closeDropdown } = useDropdown(viewFilterDropdownId);
|
||||||
|
|
||||||
const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters();
|
const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const filterDefinition = availableFilterDefinitions.find(
|
|
||||||
(filterDefinition) =>
|
|
||||||
filterDefinition.fieldMetadataId === viewFilter.fieldMetadataId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isDefined(filterDefinition)) {
|
|
||||||
setFilterDefinitionUsedInDropdown(filterDefinition);
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(filterDefinition.fieldMetadataId);
|
|
||||||
setSelectedOperandInDropdown(viewFilter.operand);
|
|
||||||
setSelectedFilter(viewFilter);
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
availableFilterDefinitions,
|
|
||||||
setFilterDefinitionUsedInDropdown,
|
|
||||||
setFieldMetadataItemIdUsedInDropdown,
|
|
||||||
viewFilter,
|
|
||||||
setSelectedOperandInDropdown,
|
|
||||||
setSelectedFilter,
|
|
||||||
viewFilterDropdownId,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||||
|
|
||||||
const handleRemove = () => {
|
const handleRemove = () => {
|
||||||
@ -108,20 +54,26 @@ export const EditableFilterDropdownButton = ({
|
|||||||
}, [viewFilter, deleteCombinedViewFilter, removeRecordFilter]);
|
}, [viewFilter, deleteCombinedViewFilter, removeRecordFilter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<>
|
||||||
dropdownId={viewFilterDropdownId}
|
<EditableFilterDropdownButtonEffect
|
||||||
clickableComponent={
|
viewFilterDropdownId={viewFilterDropdownId}
|
||||||
<EditableFilterChip viewFilter={viewFilter} onRemove={handleRemove} />
|
viewFilter={viewFilter}
|
||||||
}
|
/>
|
||||||
dropdownComponents={
|
<Dropdown
|
||||||
<ObjectFilterOperandSelectAndInput
|
dropdownId={viewFilterDropdownId}
|
||||||
filterDropdownId={viewFilterDropdownId}
|
clickableComponent={
|
||||||
/>
|
<EditableFilterChip viewFilter={viewFilter} onRemove={handleRemove} />
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={hotkeyScope}
|
dropdownComponents={
|
||||||
dropdownOffset={{ y: 8, x: 0 }}
|
<ObjectFilterOperandSelectAndInput
|
||||||
dropdownPlacement="bottom-start"
|
filterDropdownId={viewFilterDropdownId}
|
||||||
onClickOutside={handleDropdownClickOutside}
|
/>
|
||||||
/>
|
}
|
||||||
|
dropdownHotkeyScope={hotkeyScope}
|
||||||
|
dropdownOffset={{ y: 8, x: 0 }}
|
||||||
|
dropdownPlacement="bottom-start"
|
||||||
|
onClickOutside={handleDropdownClickOutside}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,74 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
|
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||||
|
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
||||||
|
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||||
|
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
type EditableFilterDropdownButtonEffectProps = {
|
||||||
|
viewFilterDropdownId: string;
|
||||||
|
viewFilter: RecordFilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EditableFilterDropdownButtonEffect = ({
|
||||||
|
viewFilterDropdownId,
|
||||||
|
viewFilter,
|
||||||
|
}: EditableFilterDropdownButtonEffectProps) => {
|
||||||
|
const setFilterDefinitionUsedInDropdown = useSetRecoilComponentStateV2(
|
||||||
|
filterDefinitionUsedInDropdownComponentState,
|
||||||
|
viewFilterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
||||||
|
fieldMetadataItemIdUsedInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
||||||
|
selectedOperandInDropdownComponentState,
|
||||||
|
viewFilterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setSelectedFilter = useSetRecoilComponentStateV2(
|
||||||
|
selectedFilterComponentState,
|
||||||
|
viewFilterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fieldMetadataItem = filterableFieldMetadataItems.find(
|
||||||
|
(fieldMetadataItem) =>
|
||||||
|
fieldMetadataItem.id === viewFilter.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(fieldMetadataItem)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterDefinition = formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: fieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDefined(filterDefinition)) {
|
||||||
|
setFilterDefinitionUsedInDropdown(filterDefinition);
|
||||||
|
setFieldMetadataItemIdUsedInDropdown(filterDefinition.fieldMetadataId);
|
||||||
|
setSelectedOperandInDropdown(viewFilter.operand);
|
||||||
|
setSelectedFilter(viewFilter);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
filterableFieldMetadataItems,
|
||||||
|
setFilterDefinitionUsedInDropdown,
|
||||||
|
setFieldMetadataItemIdUsedInDropdown,
|
||||||
|
viewFilter,
|
||||||
|
setSelectedOperandInDropdown,
|
||||||
|
setSelectedFilter,
|
||||||
|
viewFilterDropdownId,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@ -4,7 +4,6 @@ import { useContext, useEffect, useState } from 'react';
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { ViewEventContext } from '@/views/events/contexts/ViewEventContext';
|
import { ViewEventContext } from '@/views/events/contexts/ViewEventContext';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
@ -23,11 +22,6 @@ export const ViewBarEffect = ({ viewBarId }: ViewBarEffectProps) => {
|
|||||||
View | undefined
|
View | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
viewBarId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isPersistingViewFields = useRecoilComponentValueV2(
|
const isPersistingViewFields = useRecoilComponentValueV2(
|
||||||
isPersistingViewFieldsComponentState,
|
isPersistingViewFieldsComponentState,
|
||||||
viewBarId,
|
viewBarId,
|
||||||
@ -52,7 +46,6 @@ export const ViewBarEffect = ({ viewBarId }: ViewBarEffectProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
availableFilterDefinitions,
|
|
||||||
currentViewSnapshot,
|
currentViewSnapshot,
|
||||||
currentViewWithCombinedFiltersAndSorts,
|
currentViewWithCombinedFiltersAndSorts,
|
||||||
isPersistingViewFields,
|
isPersistingViewFields,
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/ob
|
|||||||
import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState';
|
import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState';
|
||||||
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema';
|
import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema';
|
||||||
import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/simpleRelationFilterValueSchema';
|
import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/simpleRelationFilterValueSchema';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
@ -22,10 +21,6 @@ export const ViewBarFilterEffect = ({
|
|||||||
}: ViewBarFilterEffectProps) => {
|
}: ViewBarFilterEffectProps) => {
|
||||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2(
|
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2(
|
||||||
filterDefinitionUsedInDropdownComponentState,
|
filterDefinitionUsedInDropdownComponentState,
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
@ -42,18 +37,6 @@ export const ViewBarFilterEffect = ({
|
|||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: verify this instance id works
|
|
||||||
const setAvailableFilterDefinitions = useSetRecoilComponentStateV2(
|
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
filterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isDefined(availableFilterDefinitions)) {
|
|
||||||
setAvailableFilterDefinitions(availableFilterDefinitions);
|
|
||||||
}
|
|
||||||
}, [availableFilterDefinitions, setAvailableFilterDefinitions]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (filterDefinitionUsedInDropdown?.type === 'RELATION') {
|
if (filterDefinitionUsedInDropdown?.type === 'RELATION') {
|
||||||
const viewFilterUsedInDropdown =
|
const viewFilterUsedInDropdown =
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
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 { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
@ -21,29 +22,31 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems();
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDataPrefetched) {
|
if (isDataPrefetched) {
|
||||||
const currentView = views.find((view) => view.id === currentViewId);
|
const currentView = views.find((view) => view.id === currentViewId);
|
||||||
|
|
||||||
|
const filterDefinitions = filterableFieldMetadataItems.map(
|
||||||
|
(fieldMetadataItem) =>
|
||||||
|
formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: fieldMetadataItem,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
if (isDefined(currentView)) {
|
if (isDefined(currentView)) {
|
||||||
setCurrentRecordFilters(
|
setCurrentRecordFilters(
|
||||||
mapViewFiltersToFilters(
|
mapViewFiltersToFilters(currentView.viewFilters, filterDefinitions),
|
||||||
currentView.viewFilters,
|
|
||||||
availableFilterDefinitions,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isDataPrefetched,
|
isDataPrefetched,
|
||||||
views,
|
views,
|
||||||
availableFilterDefinitions,
|
|
||||||
currentViewId,
|
currentViewId,
|
||||||
setCurrentRecordFilters,
|
setCurrentRecordFilters,
|
||||||
|
filterableFieldMetadataItems,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1,30 +1,42 @@
|
|||||||
import { act, renderHook } from '@testing-library/react';
|
import { act, renderHook } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
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 { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters';
|
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters';
|
||||||
|
|
||||||
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
||||||
|
|
||||||
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||||
const mockFilterDefinition: RecordFilterDefinition = {
|
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
fieldMetadataId: 'field-1',
|
(item) => item.nameSingular === 'company',
|
||||||
label: 'Test Field',
|
);
|
||||||
type: 'TEXT',
|
|
||||||
iconName: 'IconText',
|
if (!isDefined(mockObjectMetadataItem)) {
|
||||||
};
|
throw new Error(
|
||||||
|
'Missing mock object metadata item with name singular "company"',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockFieldMetadataItem = mockObjectMetadataItem.fields[0];
|
||||||
|
|
||||||
|
const mockFilterDefinition: RecordFilterDefinition =
|
||||||
|
formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: mockFieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
const mockViewFilter: ViewFilter = {
|
const mockViewFilter: ViewFilter = {
|
||||||
__typename: 'ViewFilter',
|
__typename: 'ViewFilter',
|
||||||
id: 'filter-1',
|
id: 'filter-1',
|
||||||
fieldMetadataId: 'field-1',
|
fieldMetadataId: mockFieldMetadataItem.id,
|
||||||
operand: ViewFilterOperand.Contains,
|
operand: ViewFilterOperand.Contains,
|
||||||
value: 'test',
|
value: 'test',
|
||||||
displayValue: 'test',
|
displayValue: 'test',
|
||||||
@ -36,17 +48,15 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
const mockView = {
|
const mockView = {
|
||||||
id: 'view-1',
|
id: 'view-1',
|
||||||
name: 'Test View',
|
name: 'Test View',
|
||||||
objectMetadataId: 'object-1',
|
objectMetadataId: mockObjectMetadataItem.id,
|
||||||
viewFilters: [mockViewFilter],
|
viewFilters: [mockViewFilter],
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
it('should apply filters from current view', () => {
|
||||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
(usePrefetchedData as jest.Mock).mockReturnValue({
|
||||||
records: [mockView],
|
records: [mockView],
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should apply filters from current view', () => {
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||||
@ -70,12 +80,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
}),
|
}),
|
||||||
mockView.id,
|
mockView.id,
|
||||||
);
|
);
|
||||||
snapshot.set(
|
|
||||||
availableFilterDefinitionsComponentState.atomFamily({
|
|
||||||
instanceId: 'instanceId',
|
|
||||||
}),
|
|
||||||
[mockFilterDefinition],
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -127,12 +131,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
}),
|
}),
|
||||||
mockView.id,
|
mockView.id,
|
||||||
);
|
);
|
||||||
snapshot.set(
|
|
||||||
availableFilterDefinitionsComponentState.atomFamily({
|
|
||||||
instanceId: 'instanceId',
|
|
||||||
}),
|
|
||||||
[mockFilterDefinition],
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -178,12 +176,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
}),
|
}),
|
||||||
mockView.id,
|
mockView.id,
|
||||||
);
|
);
|
||||||
snapshot.set(
|
|
||||||
availableFilterDefinitionsComponentState.atomFamily({
|
|
||||||
instanceId: 'instanceId',
|
|
||||||
}),
|
|
||||||
[mockFilterDefinition],
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,26 +1,38 @@
|
|||||||
import { act, renderHook } from '@testing-library/react';
|
import { act, renderHook } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
||||||
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 { ViewFilter } from '@/views/types/ViewFilter';
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { useApplyViewFiltersToCurrentRecordFilters } from '../useApplyViewFiltersToCurrentRecordFilters';
|
import { useApplyViewFiltersToCurrentRecordFilters } from '../useApplyViewFiltersToCurrentRecordFilters';
|
||||||
|
|
||||||
describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
||||||
const mockAvailableFilterDefinition: RecordFilterDefinition = {
|
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
fieldMetadataId: 'field-1',
|
(item) => item.nameSingular === 'company',
|
||||||
label: 'Test Field',
|
);
|
||||||
type: 'TEXT',
|
|
||||||
iconName: 'IconText',
|
if (!isDefined(mockObjectMetadataItem)) {
|
||||||
};
|
throw new Error(
|
||||||
|
'Missing mock object metadata item with name singular "company"',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockFieldMetadataItem = mockObjectMetadataItem.fields[0];
|
||||||
|
|
||||||
|
const mockAvailableFilterDefinition: RecordFilterDefinition =
|
||||||
|
formatFieldMetadataItemAsFilterDefinition({
|
||||||
|
field: mockFieldMetadataItem,
|
||||||
|
});
|
||||||
|
|
||||||
const mockViewFilter: ViewFilter = {
|
const mockViewFilter: ViewFilter = {
|
||||||
__typename: 'ViewFilter',
|
__typename: 'ViewFilter',
|
||||||
id: 'filter-1',
|
id: 'filter-1',
|
||||||
fieldMetadataId: 'field-1',
|
fieldMetadataId: mockFieldMetadataItem.id,
|
||||||
operand: ViewFilterOperand.Contains,
|
operand: ViewFilterOperand.Contains,
|
||||||
value: 'test',
|
value: 'test',
|
||||||
displayValue: 'test',
|
displayValue: 'test',
|
||||||
@ -42,16 +54,7 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
|||||||
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({}),
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
|
||||||
snapshot.set(
|
|
||||||
availableFilterDefinitionsComponentState.atomFamily({
|
|
||||||
instanceId: 'instanceId',
|
|
||||||
}),
|
|
||||||
[mockAvailableFilterDefinition],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -86,16 +89,7 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
|||||||
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksWrapper({}),
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
|
||||||
snapshot.set(
|
|
||||||
availableFilterDefinitionsComponentState.atomFamily({
|
|
||||||
instanceId: 'instanceId',
|
|
||||||
}),
|
|
||||||
[mockAvailableFilterDefinition],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
import { useFilterDefinitionsFromFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterDefinitionsFromFilterableFieldMetadataItems';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
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 { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
@ -19,19 +19,15 @@ export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => {
|
|||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const { filterDefinitions } =
|
||||||
availableFilterDefinitionsComponentState,
|
useFilterDefinitionsFromFilterableFieldMetadataItems();
|
||||||
);
|
|
||||||
|
|
||||||
const applyCurrentViewFiltersToCurrentRecordFilters = () => {
|
const applyCurrentViewFiltersToCurrentRecordFilters = () => {
|
||||||
const currentView = views.find((view) => view.id === currentViewId);
|
const currentView = views.find((view) => view.id === currentViewId);
|
||||||
|
|
||||||
if (isDefined(currentView)) {
|
if (isDefined(currentView)) {
|
||||||
setCurrentRecordFilters(
|
setCurrentRecordFilters(
|
||||||
mapViewFiltersToFilters(
|
mapViewFiltersToFilters(currentView.viewFilters, filterDefinitions),
|
||||||
currentView.viewFilters,
|
|
||||||
availableFilterDefinitions,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
|
import { useFilterDefinitionsFromFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterDefinitionsFromFilterableFieldMetadataItems';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
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 { ViewFilter } from '@/views/types/ViewFilter';
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
|
|
||||||
@ -10,16 +9,15 @@ export const useApplyViewFiltersToCurrentRecordFilters = () => {
|
|||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
const { filterDefinitions } =
|
||||||
availableFilterDefinitionsComponentState,
|
useFilterDefinitionsFromFilterableFieldMetadataItems();
|
||||||
);
|
|
||||||
|
|
||||||
const applyViewFiltersToCurrentRecordFilters = (
|
const applyViewFiltersToCurrentRecordFilters = (
|
||||||
viewFilters: ViewFilter[],
|
viewFilters: ViewFilter[],
|
||||||
) => {
|
) => {
|
||||||
const recordFiltersToApply = mapViewFiltersToFilters(
|
const recordFiltersToApply = mapViewFiltersToFilters(
|
||||||
viewFilters,
|
viewFilters,
|
||||||
availableFilterDefinitions,
|
filterDefinitions,
|
||||||
);
|
);
|
||||||
|
|
||||||
setCurrentRecordFilters(recordFiltersToApply);
|
setCurrentRecordFilters(recordFiltersToApply);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { availableFieldDefinitionsComponentState } from '@/views/states/availableFieldDefinitionsComponentState';
|
import { availableFieldDefinitionsComponentState } from '@/views/states/availableFieldDefinitionsComponentState';
|
||||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
|
||||||
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
||||||
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
||||||
|
|
||||||
@ -15,11 +14,6 @@ export const useInitViewBar = (viewBarInstanceId?: string) => {
|
|||||||
viewBarInstanceId,
|
viewBarInstanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setAvailableFilterDefinitions = useSetRecoilComponentStateV2(
|
|
||||||
availableFilterDefinitionsComponentState,
|
|
||||||
viewBarInstanceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setViewObjectMetadataId = useSetRecoilComponentStateV2(
|
const setViewObjectMetadataId = useSetRecoilComponentStateV2(
|
||||||
viewObjectMetadataIdComponentState,
|
viewObjectMetadataIdComponentState,
|
||||||
viewBarInstanceId,
|
viewBarInstanceId,
|
||||||
@ -28,7 +22,6 @@ export const useInitViewBar = (viewBarInstanceId?: string) => {
|
|||||||
return {
|
return {
|
||||||
setAvailableFieldDefinitions,
|
setAvailableFieldDefinitions,
|
||||||
setAvailableSortDefinitions,
|
setAvailableSortDefinitions,
|
||||||
setAvailableFilterDefinitions,
|
|
||||||
setViewObjectMetadataId,
|
setViewObjectMetadataId,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
|
||||||
|
|
||||||
export const availableFilterDefinitionsComponentState = createComponentStateV2<
|
|
||||||
RecordFilterDefinition[]
|
|
||||||
>({
|
|
||||||
key: 'availableFilterDefinitionsComponentState',
|
|
||||||
defaultValue: [],
|
|
||||||
componentInstanceContext: ViewComponentInstanceContext,
|
|
||||||
});
|
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
|
export const checkIfFeatureFlagIsEnabledOnWorkspace = (
|
||||||
|
featureKey: FeatureFlagKey | null | undefined,
|
||||||
|
workspace: CurrentWorkspace | null | undefined,
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
!isDefined(featureKey) ||
|
||||||
|
!isDefined(workspace) ||
|
||||||
|
!isDefined(workspace.featureFlags)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const featureFlag = workspace.featureFlags.find(
|
||||||
|
(flag) => flag.key === featureKey,
|
||||||
|
);
|
||||||
|
|
||||||
|
return featureFlag?.value === true;
|
||||||
|
};
|
||||||
@ -3,9 +3,11 @@ import { ReactNode } from 'react';
|
|||||||
import { MutableSnapshot, RecoilRoot } from 'recoil';
|
import { MutableSnapshot, RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||||
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||||
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
export const getJestMetadataAndApolloMocksWrapper = ({
|
export const getJestMetadataAndApolloMocksWrapper = ({
|
||||||
apolloMocks,
|
apolloMocks,
|
||||||
@ -20,17 +22,31 @@ export const getJestMetadataAndApolloMocksWrapper = ({
|
|||||||
<RecoilRoot initializeState={onInitializeRecoilSnapshot}>
|
<RecoilRoot initializeState={onInitializeRecoilSnapshot}>
|
||||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||||
<MockedProvider mocks={apolloMocks} addTypename={false}>
|
<MockedProvider mocks={apolloMocks} addTypename={false}>
|
||||||
<RecordFiltersComponentInstanceContext.Provider
|
<RecordIndexContextProvider
|
||||||
value={{ instanceId: 'instanceId' }}
|
value={{
|
||||||
|
indexIdentifierUrl: () => 'indexIdentifierUrl',
|
||||||
|
onIndexRecordsLoaded: () => {},
|
||||||
|
objectNamePlural: 'objectNamePlural',
|
||||||
|
objectNameSingular: 'objectNameSingular',
|
||||||
|
objectMetadataItem:
|
||||||
|
generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === 'company',
|
||||||
|
) ?? generatedMockObjectMetadataItems[0],
|
||||||
|
recordIndexId: 'recordIndexId',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
value={{ instanceId: 'instanceId' }}
|
value={{ instanceId: 'instanceId' }}
|
||||||
>
|
>
|
||||||
<JestObjectMetadataItemSetter>
|
<ViewComponentInstanceContext.Provider
|
||||||
{children}
|
value={{ instanceId: 'instanceId' }}
|
||||||
</JestObjectMetadataItemSetter>
|
>
|
||||||
</ViewComponentInstanceContext.Provider>
|
<JestObjectMetadataItemSetter>
|
||||||
</RecordFiltersComponentInstanceContext.Provider>
|
{children}
|
||||||
|
</JestObjectMetadataItemSetter>
|
||||||
|
</ViewComponentInstanceContext.Provider>
|
||||||
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
|
</RecordIndexContextProvider>
|
||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
</SnackBarProviderScope>
|
</SnackBarProviderScope>
|
||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
|
|||||||
Reference in New Issue
Block a user