Remove filterDefinition.type usage (#10164)
This PR essentially removes the usage of filterDefinition.type, by replacing it with fieldMetadataItem.type derivation. Thus allowing to completely remove filterDefinition later on. In computeFilterRecordGqlOperationFilter, emptyOperationFilter is now returned before going into the big switch case. This avoids repeating the same exact call to getEmptyRecordGqlOperationFilter for each type. Fixed some tests that need getJestMetadataAndApolloMocksAndActionMenuWrapper to have record filters properly working with the new implementation. We'll probably want to refactor the record context store, record index context, etc. Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
@ -73,9 +73,22 @@ describe('computeContextStoreFilters', () => {
|
|||||||
expect(filters).toEqual({
|
expect(filters).toEqual({
|
||||||
and: [
|
and: [
|
||||||
{
|
{
|
||||||
name: {
|
or: [
|
||||||
ilike: '%John%',
|
{
|
||||||
},
|
name: {
|
||||||
|
firstName: {
|
||||||
|
ilike: '%John%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
lastName: {
|
||||||
|
ilike: '%John%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
not: {
|
not: {
|
||||||
|
|||||||
@ -9,11 +9,13 @@ import {
|
|||||||
SubscriptionStatus,
|
SubscriptionStatus,
|
||||||
WorkspaceActivationStatus,
|
WorkspaceActivationStatus,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
const Wrapper = getJestMetadataAndApolloMocksWrapper({
|
const Wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||||
apolloMocks: [],
|
apolloMocks: [],
|
||||||
|
componentInstanceId: 'instanceId',
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular: 'company',
|
||||||
onInitializeRecoilSnapshot: ({ set }) => {
|
onInitializeRecoilSnapshot: ({ set }) => {
|
||||||
set(currentWorkspaceState, {
|
set(currentWorkspaceState, {
|
||||||
id: '1',
|
id: '1',
|
||||||
|
|||||||
@ -6,10 +6,8 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
|
|||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||||
|
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
|
||||||
import { formatFieldMetadataItemAsColumnDefinition } from '../utils/formatFieldMetadataItemAsColumnDefinition';
|
import { formatFieldMetadataItemAsColumnDefinition } from '../utils/formatFieldMetadataItemAsColumnDefinition';
|
||||||
import { formatFieldMetadataItemsAsFilterDefinitions } from '../utils/formatFieldMetadataItemsAsFilterDefinitions';
|
|
||||||
import { formatFieldMetadataItemsAsSortDefinitions } from '../utils/formatFieldMetadataItemsAsSortDefinitions';
|
import { formatFieldMetadataItemsAsSortDefinitions } from '../utils/formatFieldMetadataItemsAsSortDefinitions';
|
||||||
|
|
||||||
export const useColumnDefinitionsFromFieldMetadata = (
|
export const useColumnDefinitionsFromFieldMetadata = (
|
||||||
@ -25,14 +23,8 @@ export const useColumnDefinitionsFromFieldMetadata = (
|
|||||||
[objectMetadataItem],
|
[objectMetadataItem],
|
||||||
);
|
);
|
||||||
|
|
||||||
const isJsonFilterEnabled = useIsFeatureEnabled(
|
const { filterableFieldMetadataItems } =
|
||||||
FeatureFlagKey.IsJsonFilterEnabled,
|
useFilterableFieldMetadataItemsInRecordIndexContext();
|
||||||
);
|
|
||||||
|
|
||||||
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({
|
|
||||||
fields: activeFieldMetadataItems,
|
|
||||||
isJsonFilterEnabled,
|
|
||||||
});
|
|
||||||
|
|
||||||
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
||||||
fields: activeFieldMetadataItems,
|
fields: activeFieldMetadataItems,
|
||||||
@ -51,9 +43,11 @@ export const useColumnDefinitionsFromFieldMetadata = (
|
|||||||
)
|
)
|
||||||
.filter(filterAvailableTableColumns)
|
.filter(filterAvailableTableColumns)
|
||||||
.map((column) => {
|
.map((column) => {
|
||||||
const existsInFilterDefinitions = filterDefinitions.some(
|
const existsInFilterDefinitions =
|
||||||
(filter) => filter.fieldMetadataId === column.fieldMetadataId,
|
filterableFieldMetadataItems.some(
|
||||||
);
|
(fieldMetadataItem) =>
|
||||||
|
fieldMetadataItem.id === column.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
const existsInSortDefinitions = sortDefinitions.some(
|
const existsInSortDefinitions = sortDefinitions.some(
|
||||||
(sort) => sort.fieldMetadataId === column.fieldMetadataId,
|
(sort) => sort.fieldMetadataId === column.fieldMetadataId,
|
||||||
@ -67,16 +61,15 @@ export const useColumnDefinitionsFromFieldMetadata = (
|
|||||||
})
|
})
|
||||||
: [],
|
: [],
|
||||||
[
|
[
|
||||||
|
filterableFieldMetadataItems,
|
||||||
activeFieldMetadataItems,
|
activeFieldMetadataItems,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
filterDefinitions,
|
|
||||||
sortDefinitions,
|
sortDefinitions,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
columnDefinitions,
|
columnDefinitions,
|
||||||
filterDefinitions,
|
|
||||||
sortDefinitions,
|
sortDefinitions,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
|
import { useGetFieldMetadataItemById } from '@/object-metadata/hooks/useGetFieldMetadataItemById';
|
||||||
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { useCurrentViewFilter } from '@/object-record/advanced-filter/hooks/useCurrentViewFilter';
|
import { useCurrentViewFilter } from '@/object-record/advanced-filter/hooks/useCurrentViewFilter';
|
||||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||||
import { getOperandLabel } from '@/object-record/object-filter-dropdown/utils/getOperandLabel';
|
import { getOperandLabel } from '@/object-record/object-filter-dropdown/utils/getOperandLabel';
|
||||||
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||||
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';
|
||||||
@ -28,6 +30,8 @@ export const AdvancedFilterViewFilterOperandSelect = ({
|
|||||||
|
|
||||||
const filter = useCurrentViewFilter({ viewFilterId });
|
const filter = useCurrentViewFilter({ viewFilterId });
|
||||||
|
|
||||||
|
const { getFieldMetadataItemById } = useGetFieldMetadataItemById();
|
||||||
|
|
||||||
const isDisabled = !filter?.fieldMetadataId;
|
const isDisabled = !filter?.fieldMetadataId;
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown(dropdownId);
|
const { closeDropdown } = useDropdown(dropdownId);
|
||||||
@ -41,8 +45,16 @@ export const AdvancedFilterViewFilterOperandSelect = ({
|
|||||||
throw new Error('Filter is not defined');
|
throw new Error('Filter is not defined');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fieldMetadataItem = getFieldMetadataItemById(filter.fieldMetadataId);
|
||||||
|
|
||||||
|
if (!isDefined(fieldMetadataItem)) {
|
||||||
|
throw new Error('Field metadata item is not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type);
|
||||||
|
|
||||||
const { value, displayValue } = getInitialFilterValue(
|
const { value, displayValue } = getInitialFilterValue(
|
||||||
filter.definition.type,
|
filterType,
|
||||||
operand,
|
operand,
|
||||||
filter.value,
|
filter.value,
|
||||||
filter.displayValue,
|
filter.displayValue,
|
||||||
@ -56,8 +68,12 @@ export const AdvancedFilterViewFilterOperandSelect = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const operandsForFilterType = isDefined(filter?.definition)
|
const filterType = filter?.type;
|
||||||
? getRecordFilterOperandsForRecordFilterDefinition(filter.definition)
|
|
||||||
|
const operandsForFilterType = isDefined(filterType)
|
||||||
|
? getRecordFilterOperands({
|
||||||
|
filterType,
|
||||||
|
})
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
if (isDisabled === true) {
|
if (isDisabled === true) {
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import {
|
||||||
|
formatFieldMetadataItemAsFilterDefinition,
|
||||||
|
getFilterTypeFromFieldType,
|
||||||
|
} 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 { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
|
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
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';
|
||||||
@ -110,11 +114,18 @@ export const AdvancedFilterButton = () => {
|
|||||||
field: defaultFieldMetadataItem,
|
field: defaultFieldMetadataItem,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const filterType = getFilterTypeFromFieldType(
|
||||||
|
defaultFieldMetadataItem.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
const firstOperand = getRecordFilterOperands({
|
||||||
|
filterType,
|
||||||
|
})[0];
|
||||||
|
|
||||||
upsertCombinedViewFilter({
|
upsertCombinedViewFilter({
|
||||||
id: v4(),
|
id: v4(),
|
||||||
fieldMetadataId: defaultFieldMetadataItem.id,
|
fieldMetadataId: defaultFieldMetadataItem.id,
|
||||||
operand:
|
operand: firstOperand,
|
||||||
getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0],
|
|
||||||
definition: filterDefinition,
|
definition: filterDefinition,
|
||||||
value: '',
|
value: '',
|
||||||
displayValue: '',
|
displayValue: '',
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu';
|
import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu';
|
||||||
import { ObjectFilterOperandSelectAndInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterOperandSelectAndInput';
|
import { ObjectFilterOperandSelectAndInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterOperandSelectAndInput';
|
||||||
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
|
||||||
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect';
|
import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect';
|
||||||
import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect';
|
import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect';
|
||||||
|
|
||||||
@ -15,11 +13,6 @@ type MultipleFiltersDropdownContentProps = {
|
|||||||
export const MultipleFiltersDropdownContent = ({
|
export const MultipleFiltersDropdownContent = ({
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
}: MultipleFiltersDropdownContentProps) => {
|
}: MultipleFiltersDropdownContentProps) => {
|
||||||
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2(
|
|
||||||
filterDefinitionUsedInDropdownComponentState,
|
|
||||||
filterDropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [objectFilterDropdownIsSelectingCompositeField] =
|
const [objectFilterDropdownIsSelectingCompositeField] =
|
||||||
useRecoilComponentStateV2(
|
useRecoilComponentStateV2(
|
||||||
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
||||||
@ -47,11 +40,7 @@ export const MultipleFiltersDropdownContent = ({
|
|||||||
) : (
|
) : (
|
||||||
<ObjectFilterDropdownFilterSelect isAdvancedFilterButtonVisible />
|
<ObjectFilterDropdownFilterSelect isAdvancedFilterButtonVisible />
|
||||||
)}
|
)}
|
||||||
<MultipleFiltersDropdownFilterOnFilterChangedEffect
|
<MultipleFiltersDropdownFilterOnFilterChangedEffect />
|
||||||
filterDefinitionUsedInDropdownType={
|
|
||||||
filterDefinitionUsedInDropdown?.type
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,28 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
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 { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const MultipleFiltersDropdownFilterOnFilterChangedEffect = ({
|
export const MultipleFiltersDropdownFilterOnFilterChangedEffect = () => {
|
||||||
filterDefinitionUsedInDropdownType,
|
|
||||||
}: {
|
|
||||||
filterDefinitionUsedInDropdownType: string | undefined;
|
|
||||||
}) => {
|
|
||||||
const { setDropdownWidth } = useDropdown();
|
const { setDropdownWidth } = useDropdown();
|
||||||
|
|
||||||
|
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||||
|
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (filterDefinitionUsedInDropdownType) {
|
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterType = getFilterTypeFromFieldType(
|
||||||
|
fieldMetadataItemUsedInDropdown.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (filterType) {
|
||||||
case 'DATE':
|
case 'DATE':
|
||||||
case 'DATE_TIME':
|
case 'DATE_TIME':
|
||||||
setDropdownWidth(280);
|
setDropdownWidth(280);
|
||||||
@ -18,7 +30,7 @@ export const MultipleFiltersDropdownFilterOnFilterChangedEffect = ({
|
|||||||
default:
|
default:
|
||||||
setDropdownWidth(200);
|
setDropdownWidth(200);
|
||||||
}
|
}
|
||||||
}, [filterDefinitionUsedInDropdownType, setDropdownWidth]);
|
}, [fieldMetadataItemUsedInDropdown, setDropdownWidth]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,17 +6,19 @@ import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-
|
|||||||
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
|
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
|
||||||
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
|
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
|
||||||
import { ObjectFilterDropdownTextSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput';
|
import { ObjectFilterDropdownTextSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput';
|
||||||
import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter';
|
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
||||||
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||||
import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes';
|
import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes';
|
||||||
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
||||||
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
|
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||||
|
import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
type ObjectFilterDropdownFilterInputProps = {
|
type ObjectFilterDropdownFilterInputProps = {
|
||||||
@ -26,10 +28,16 @@ type ObjectFilterDropdownFilterInputProps = {
|
|||||||
export const ObjectFilterDropdownFilterInput = ({
|
export const ObjectFilterDropdownFilterInput = ({
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
}: ObjectFilterDropdownFilterInputProps) => {
|
}: ObjectFilterDropdownFilterInputProps) => {
|
||||||
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2(
|
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||||
filterDefinitionUsedInDropdownComponentState,
|
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const subFieldNameUsedInDropdown = useRecoilComponentValueV2(
|
||||||
|
subFieldNameUsedInDropdownComponentState,
|
||||||
|
filterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||||
selectedOperandInDropdownComponentState,
|
selectedOperandInDropdownComponentState,
|
||||||
filterDropdownId,
|
filterDropdownId,
|
||||||
@ -50,52 +58,54 @@ export const ObjectFilterDropdownFilterInput = ({
|
|||||||
ViewFilterOperand.IsRelative,
|
ViewFilterOperand.IsRelative,
|
||||||
].includes(selectedOperandInDropdown);
|
].includes(selectedOperandInDropdown);
|
||||||
|
|
||||||
if (!isDefined(filterDefinitionUsedInDropdown)) {
|
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterType = getFilterTypeFromFieldType(
|
||||||
|
fieldMetadataItemUsedInDropdown.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isActorSourceCompositeFilter = isFilterOnActorSourceSubField(
|
||||||
|
subFieldNameUsedInDropdown,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isConfigurable && selectedOperandInDropdown && (
|
{isConfigurable && selectedOperandInDropdown && (
|
||||||
<>
|
<>
|
||||||
{TEXT_FILTER_TYPES.includes(filterDefinitionUsedInDropdown.type) &&
|
{TEXT_FILTER_TYPES.includes(filterType) &&
|
||||||
!isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
|
!isActorSourceCompositeFilter && (
|
||||||
<ObjectFilterDropdownTextSearchInput />
|
<ObjectFilterDropdownTextSearchInput />
|
||||||
)}
|
)}
|
||||||
{NUMBER_FILTER_TYPES.includes(
|
{NUMBER_FILTER_TYPES.includes(filterType) && (
|
||||||
filterDefinitionUsedInDropdown.type,
|
<ObjectFilterDropdownNumberInput />
|
||||||
) && <ObjectFilterDropdownNumberInput />}
|
|
||||||
{filterDefinitionUsedInDropdown.type === 'RATING' && (
|
|
||||||
<ObjectFilterDropdownRatingInput />
|
|
||||||
)}
|
)}
|
||||||
{DATE_FILTER_TYPES.includes(filterDefinitionUsedInDropdown.type) && (
|
{filterType === 'RATING' && <ObjectFilterDropdownRatingInput />}
|
||||||
|
{DATE_FILTER_TYPES.includes(filterType) && (
|
||||||
<ObjectFilterDropdownDateInput />
|
<ObjectFilterDropdownDateInput />
|
||||||
)}
|
)}
|
||||||
{filterDefinitionUsedInDropdown.type === 'RELATION' && (
|
{filterType === 'RELATION' && (
|
||||||
<>
|
<>
|
||||||
<ObjectFilterDropdownSearchInput />
|
<ObjectFilterDropdownSearchInput />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ObjectFilterDropdownRecordSelect />
|
<ObjectFilterDropdownRecordSelect />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isActorSourceCompositeFilter(filterDefinitionUsedInDropdown) && (
|
{isActorSourceCompositeFilter && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ObjectFilterDropdownSourceSelect />
|
<ObjectFilterDropdownSourceSelect />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{['SELECT', 'MULTI_SELECT'].includes(
|
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
||||||
filterDefinitionUsedInDropdown.type,
|
|
||||||
) && (
|
|
||||||
<>
|
<>
|
||||||
<ObjectFilterDropdownSearchInput />
|
<ObjectFilterDropdownSearchInput />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ObjectFilterDropdownOptionSelect />
|
<ObjectFilterDropdownOptionSelect />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{filterDefinitionUsedInDropdown.type === 'BOOLEAN' && (
|
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
||||||
<ObjectFilterDropdownBooleanSelect />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -91,16 +91,15 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
|||||||
|
|
||||||
setFilterDefinitionUsedInDropdown(filterDefinition);
|
setFilterDefinitionUsedInDropdown(filterDefinition);
|
||||||
|
|
||||||
if (
|
const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type);
|
||||||
filterDefinition.type === 'RELATION' ||
|
|
||||||
filterDefinition.type === 'SELECT'
|
if (filterType === 'RELATION' || filterType === 'SELECT') {
|
||||||
) {
|
|
||||||
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedOperandInDropdown(
|
setSelectedOperandInDropdown(
|
||||||
getRecordFilterOperands({
|
getRecordFilterOperands({
|
||||||
filterType: filterDefinition.type,
|
filterType,
|
||||||
})[0],
|
})[0],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import {
|
||||||
|
formatFieldMetadataItemAsFilterDefinition,
|
||||||
|
getFilterTypeFromFieldType,
|
||||||
|
} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
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 { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||||
import { getRecordFilterOperandsForRecordFilterDefinition } from '@/object-record/record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
@ -30,14 +33,16 @@ export const SingleEntityObjectFilterDropdownButtonEffect = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFieldMetadataItemIdUsedInDropdown(firstFieldDefinition.fieldMetadataId);
|
setFieldMetadataItemIdUsedInDropdown(firstFieldMetadataItem.id);
|
||||||
setFilterDefinitionUsedInDropdown(firstFieldDefinition);
|
setFilterDefinitionUsedInDropdown(firstFieldDefinition);
|
||||||
|
|
||||||
const defaultOperand =
|
const filterType = getFilterTypeFromFieldType(firstFieldMetadataItem.type);
|
||||||
getRecordFilterOperandsForRecordFilterDefinition(firstFieldDefinition)[0];
|
|
||||||
|
const defaultOperand = getRecordFilterOperands({ filterType })[0];
|
||||||
|
|
||||||
setSelectedOperandInDropdown(defaultOperand);
|
setSelectedOperandInDropdown(defaultOperand);
|
||||||
}, [
|
}, [
|
||||||
|
firstFieldMetadataItem,
|
||||||
firstFieldDefinition,
|
firstFieldDefinition,
|
||||||
setFilterDefinitionUsedInDropdown,
|
setFilterDefinitionUsedInDropdown,
|
||||||
setSelectedOperandInDropdown,
|
setSelectedOperandInDropdown,
|
||||||
|
|||||||
@ -6,7 +6,8 @@ import { selectedOperandInDropdownComponentState } from '@/object-record/object-
|
|||||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||||
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 { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
|
|
||||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -62,13 +63,15 @@ export const useSelectFilterDefinitionUsedInDropdown = (
|
|||||||
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
setHotkeyScope(RelationPickerHotkeyScope.RelationPicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedOperandInDropdown(
|
const firstOperand = getRecordFilterOperands({
|
||||||
getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0],
|
filterType: filterDefinition.type,
|
||||||
);
|
})[0];
|
||||||
|
|
||||||
|
setSelectedOperandInDropdown(firstOperand);
|
||||||
|
|
||||||
const { value, displayValue } = getInitialFilterValue(
|
const { value, displayValue } = getInitialFilterValue(
|
||||||
filterDefinition.type,
|
filterDefinition.type,
|
||||||
getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0],
|
firstOperand,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isAdvancedFilter = isDefined(advancedFilterViewFilterId);
|
const isAdvancedFilter = isDefined(advancedFilterViewFilterId);
|
||||||
@ -78,8 +81,7 @@ export const useSelectFilterDefinitionUsedInDropdown = (
|
|||||||
id: advancedFilterViewFilterId ?? v4(),
|
id: advancedFilterViewFilterId ?? v4(),
|
||||||
fieldMetadataId: filterDefinition.fieldMetadataId,
|
fieldMetadataId: filterDefinition.fieldMetadataId,
|
||||||
displayValue,
|
displayValue,
|
||||||
operand:
|
operand: firstOperand,
|
||||||
getRecordFilterOperandsForRecordFilterDefinition(filterDefinition)[0],
|
|
||||||
value,
|
value,
|
||||||
definition: filterDefinition,
|
definition: filterDefinition,
|
||||||
viewFilterGroupId: advancedFilterViewFilterGroupId,
|
viewFilterGroupId: advancedFilterViewFilterGroupId,
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
|
||||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
import { getRecordFilterOperandsForRecordFilterDefinition } from '../../../record-filter/utils/getRecordFilterOperandsForRecordFilterDefinition';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
|
|
||||||
describe('getOperandsForFilterType', () => {
|
describe('getOperandsForFilterType', () => {
|
||||||
const emptyOperands = [
|
const emptyOperands = [
|
||||||
@ -49,9 +48,9 @@ describe('getOperandsForFilterType', () => {
|
|||||||
|
|
||||||
testCases.forEach(([filterType, expectedOperands]) => {
|
testCases.forEach(([filterType, expectedOperands]) => {
|
||||||
it(`should return correct operands for FilterType.${filterType}`, () => {
|
it(`should return correct operands for FilterType.${filterType}`, () => {
|
||||||
const result = getRecordFilterOperandsForRecordFilterDefinition({
|
const result = getRecordFilterOperands({
|
||||||
type: filterType as FilterableFieldType,
|
filterType: filterType as FilterableFieldType,
|
||||||
} as RecordFilterDefinition);
|
});
|
||||||
expect(result).toEqual(expectedOperands);
|
expect(result).toEqual(expectedOperands);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,7 +3,8 @@ import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/s
|
|||||||
import { DropResult, ResponderProvided } from '@hello-pangea/dnd';
|
import { DropResult, ResponderProvided } from '@hello-pangea/dnd';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
jest.mock('@/views/hooks/useSaveCurrentViewFields', () => ({
|
jest.mock('@/views/hooks/useSaveCurrentViewFields', () => ({
|
||||||
useSaveCurrentViewFields: jest.fn(() => ({
|
useSaveCurrentViewFields: jest.fn(() => ({
|
||||||
@ -17,53 +18,67 @@ jest.mock('@/views/hooks/useUpdateCurrentView', () => ({
|
|||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('@/object-metadata/hooks/useObjectMetadataItem', () => ({
|
const objectNameSingular = 'company';
|
||||||
useObjectMetadataItem: jest.fn(() => ({
|
|
||||||
objectMetadataItem: {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
id: 'field1',
|
|
||||||
name: 'field1',
|
|
||||||
label: 'Field 1',
|
|
||||||
isVisible: true,
|
|
||||||
position: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'field2',
|
|
||||||
name: 'field2',
|
|
||||||
label: 'Field 2',
|
|
||||||
isVisible: true,
|
|
||||||
position: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('useObjectOptionsForBoard', () => {
|
describe('useObjectOptionsForBoard', () => {
|
||||||
|
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
(objectMetadataItem) =>
|
||||||
|
objectMetadataItem.nameSingular === objectNameSingular,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!mockObjectMetadataItem) {
|
||||||
|
throw new Error('Mock object metadata item not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockFieldMetadataItem1 = mockObjectMetadataItem.fields.find(
|
||||||
|
(field) => field.name === 'name',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!mockFieldMetadataItem1) {
|
||||||
|
throw new Error('Mock field metadata item not found for "name"');
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockFieldMetadataItem2 = mockObjectMetadataItem.fields.find(
|
||||||
|
(field) => field.name === 'createdAt',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!mockFieldMetadataItem2) {
|
||||||
|
throw new Error('Mock field metadata item not found for "createdAt"');
|
||||||
|
}
|
||||||
|
|
||||||
const initialRecoilState = [
|
const initialRecoilState = [
|
||||||
{ fieldMetadataId: 'field1', isVisible: true, position: 0 },
|
{
|
||||||
{ fieldMetadataId: 'field2', isVisible: true, position: 1 },
|
fieldMetadataId: mockFieldMetadataItem1.id,
|
||||||
|
isVisible: true,
|
||||||
|
position: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldMetadataId: mockFieldMetadataItem2.id,
|
||||||
|
isVisible: true,
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const renderWithRecoil = () =>
|
const renderWithRecoil = () =>
|
||||||
renderHook(
|
renderHook(
|
||||||
() =>
|
() =>
|
||||||
useObjectOptionsForBoard({
|
useObjectOptionsForBoard({
|
||||||
objectNameSingular: 'object',
|
objectNameSingular,
|
||||||
recordBoardId: 'boardId',
|
recordBoardId: 'boardId',
|
||||||
viewBarId: 'viewBarId',
|
viewBarId: 'viewBarId',
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
wrapper: ({ children }) => (
|
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||||
<RecoilRoot
|
apolloMocks: [],
|
||||||
initializeState={({ set }) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
set(recordIndexFieldDefinitionsState, initialRecoilState as any);
|
snapshot.set(
|
||||||
}}
|
recordIndexFieldDefinitionsState,
|
||||||
>
|
initialRecoilState as any,
|
||||||
{children}
|
);
|
||||||
</RecoilRoot>
|
},
|
||||||
),
|
componentInstanceId: 'test',
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular: objectNameSingular,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -73,7 +88,7 @@ describe('useObjectOptionsForBoard', () => {
|
|||||||
const dropResult: DropResult = {
|
const dropResult: DropResult = {
|
||||||
source: { droppableId: 'droppable', index: 1 },
|
source: { droppableId: 'droppable', index: 1 },
|
||||||
destination: { droppableId: 'droppable', index: 2 },
|
destination: { droppableId: 'droppable', index: 2 },
|
||||||
draggableId: 'field1',
|
draggableId: mockFieldMetadataItem1.id,
|
||||||
type: 'TYPE',
|
type: 'TYPE',
|
||||||
mode: 'FLUID',
|
mode: 'FLUID',
|
||||||
reason: 'DROP',
|
reason: 'DROP',
|
||||||
@ -90,12 +105,12 @@ describe('useObjectOptionsForBoard', () => {
|
|||||||
|
|
||||||
expect(result.current.visibleBoardFields).toEqual([
|
expect(result.current.visibleBoardFields).toEqual([
|
||||||
{
|
{
|
||||||
fieldMetadataId: 'field2',
|
fieldMetadataId: mockFieldMetadataItem2.id,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
position: 0,
|
position: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldMetadataId: 'field1',
|
fieldMetadataId: mockFieldMetadataItem1.id,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
position: 1,
|
position: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
import { RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
import { RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
@ -33,7 +34,9 @@ describe('computeViewRecordGqlOperationFilter', () => {
|
|||||||
value: companiesMock[0].name,
|
value: companiesMock[0].name,
|
||||||
fieldMetadataId: companyMockNameFieldMetadataId?.id,
|
fieldMetadataId: companyMockNameFieldMetadataId?.id,
|
||||||
displayValue: companiesMock[0].name,
|
displayValue: companiesMock[0].name,
|
||||||
operand: ViewFilterOperand.Contains,
|
operand: RecordFilterOperand.Contains,
|
||||||
|
type: 'TEXT',
|
||||||
|
label: 'Name',
|
||||||
definition: {
|
definition: {
|
||||||
type: 'TEXT',
|
type: 'TEXT',
|
||||||
fieldMetadataId: companyMockNameFieldMetadataId?.id,
|
fieldMetadataId: companyMockNameFieldMetadataId?.id,
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { isDefined } from 'twenty-shared';
|
|||||||
import { Field } from '~/generated/graphql';
|
import { Field } from '~/generated/graphql';
|
||||||
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
|
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
|
||||||
|
|
||||||
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import {
|
import {
|
||||||
convertGreaterThanRatingToArrayOfRatingValues,
|
convertGreaterThanRatingToArrayOfRatingValues,
|
||||||
convertLessThanRatingToArrayOfRatingValues,
|
convertLessThanRatingToArrayOfRatingValues,
|
||||||
@ -40,22 +41,35 @@ import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/valid
|
|||||||
import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns';
|
import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
const computeFilterRecordGqlOperationFilter = (
|
import { FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||||
filterValueDependencies: RecordFilterValueDependencies,
|
|
||||||
filter: RecordFilter,
|
type ComputeFilterRecordGqlOperationFilterParams = {
|
||||||
fields: Pick<Field, 'id' | 'name'>[],
|
filterValueDependencies: RecordFilterValueDependencies;
|
||||||
): RecordGqlOperationFilter | undefined => {
|
filter: RecordFilter;
|
||||||
|
fieldMetadataItems: Pick<Field, 'id' | 'name' | 'type'>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const computeFilterRecordGqlOperationFilter = ({
|
||||||
|
filterValueDependencies,
|
||||||
|
filter,
|
||||||
|
fieldMetadataItems: fields,
|
||||||
|
}: ComputeFilterRecordGqlOperationFilterParams):
|
||||||
|
| RecordGqlOperationFilter
|
||||||
|
| undefined => {
|
||||||
const correspondingField = fields.find(
|
const correspondingField = fields.find(
|
||||||
(field) => field.id === filter.fieldMetadataId,
|
(field) => field.id === filter.fieldMetadataId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const compositeFieldName = filter.definition.compositeFieldName;
|
const compositeFieldName = filter.subFieldName;
|
||||||
|
|
||||||
const isCompositeFieldFiter = isNonEmptyString(compositeFieldName);
|
const isCompositeFieldFiter = isNonEmptyString(compositeFieldName);
|
||||||
|
|
||||||
const isEmptyOperand = [
|
const isEmptinessOperand = [
|
||||||
RecordFilterOperand.IsEmpty,
|
RecordFilterOperand.IsEmpty,
|
||||||
RecordFilterOperand.IsNotEmpty,
|
RecordFilterOperand.IsNotEmpty,
|
||||||
|
].includes(filter.operand);
|
||||||
|
|
||||||
|
const isDateOperandWithoutValue = [
|
||||||
RecordFilterOperand.IsInPast,
|
RecordFilterOperand.IsInPast,
|
||||||
RecordFilterOperand.IsInFuture,
|
RecordFilterOperand.IsInFuture,
|
||||||
RecordFilterOperand.IsToday,
|
RecordFilterOperand.IsToday,
|
||||||
@ -65,13 +79,35 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEmptyOperand) {
|
const filterType = getFilterTypeFromFieldType(correspondingField.type);
|
||||||
if (!isDefined(filter.value) || filter.value === '') {
|
|
||||||
return;
|
const isFilterValueEmpty = !isDefined(filter.value) || filter.value === '';
|
||||||
}
|
|
||||||
|
const shouldSkipFiltering =
|
||||||
|
!isEmptinessOperand && !isDateOperandWithoutValue && isFilterValueEmpty;
|
||||||
|
|
||||||
|
if (shouldSkipFiltering) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (filter.definition.type) {
|
const filterTypesThatHaveNoEmptinessOperand: FilterableFieldType[] = [
|
||||||
|
'BOOLEAN',
|
||||||
|
];
|
||||||
|
|
||||||
|
const filterHasEmptinessOperands =
|
||||||
|
!filterTypesThatHaveNoEmptinessOperand.includes(filterType);
|
||||||
|
|
||||||
|
if (filterHasEmptinessOperands && isEmptinessOperand) {
|
||||||
|
const emptyOperationFilter = getEmptyRecordGqlOperationFilter({
|
||||||
|
operand: filter.operand,
|
||||||
|
correspondingField,
|
||||||
|
recordFilter: filter,
|
||||||
|
});
|
||||||
|
|
||||||
|
return emptyOperationFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (filterType) {
|
||||||
case 'TEXT':
|
case 'TEXT':
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case RecordFilterOperand.Contains:
|
case RecordFilterOperand.Contains:
|
||||||
@ -88,16 +124,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
} as StringFilter,
|
} as StringFilter,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'RAW_JSON':
|
case 'RAW_JSON':
|
||||||
@ -116,16 +145,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
} as RawJsonFilter,
|
} as RawJsonFilter,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'DATE':
|
case 'DATE':
|
||||||
@ -150,14 +172,6 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
} as DateFilter,
|
} as DateFilter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty: {
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case RecordFilterOperand.IsRelative: {
|
case RecordFilterOperand.IsRelative: {
|
||||||
const dateRange = z
|
const dateRange = z
|
||||||
.object({ start: z.date(), end: z.date() })
|
.object({ start: z.date(), end: z.date() })
|
||||||
@ -238,7 +252,7 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`, //
|
`Unknown operand ${filter.operand} for ${filterType} filter`, //
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,16 +280,10 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
),
|
),
|
||||||
} as RatingFilter,
|
} as RatingFilter,
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'NUMBER':
|
case 'NUMBER':
|
||||||
@ -292,83 +300,61 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
lte: parseFloat(filter.value),
|
lte: parseFloat(filter.value),
|
||||||
} as FloatFilter,
|
} as FloatFilter,
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'RELATION': {
|
case 'RELATION': {
|
||||||
if (!isEmptyOperand) {
|
const { isCurrentWorkspaceMemberSelected, selectedRecordIds } =
|
||||||
const { isCurrentWorkspaceMemberSelected, selectedRecordIds } =
|
jsonRelationFilterValueSchema
|
||||||
jsonRelationFilterValueSchema
|
.catch({
|
||||||
.catch({
|
isCurrentWorkspaceMemberSelected: false,
|
||||||
isCurrentWorkspaceMemberSelected: false,
|
selectedRecordIds: simpleRelationFilterValueSchema.parse(
|
||||||
selectedRecordIds: simpleRelationFilterValueSchema.parse(
|
filter.value,
|
||||||
filter.value,
|
),
|
||||||
),
|
})
|
||||||
})
|
.parse(filter.value);
|
||||||
.parse(filter.value);
|
|
||||||
|
|
||||||
const recordIds = isCurrentWorkspaceMemberSelected
|
const recordIds = isCurrentWorkspaceMemberSelected
|
||||||
? [
|
? [
|
||||||
...selectedRecordIds,
|
...selectedRecordIds,
|
||||||
filterValueDependencies.currentWorkspaceMemberId,
|
filterValueDependencies.currentWorkspaceMemberId,
|
||||||
]
|
]
|
||||||
: selectedRecordIds;
|
: selectedRecordIds;
|
||||||
|
|
||||||
if (recordIds.length === 0) return;
|
if (recordIds.length === 0) return;
|
||||||
switch (filter.operand) {
|
|
||||||
case RecordFilterOperand.Is:
|
switch (filter.operand) {
|
||||||
return {
|
case RecordFilterOperand.Is:
|
||||||
[correspondingField.name + 'Id']: {
|
return {
|
||||||
in: recordIds,
|
[correspondingField.name + 'Id']: {
|
||||||
} as RelationFilter,
|
in: recordIds,
|
||||||
};
|
} as RelationFilter,
|
||||||
case RecordFilterOperand.IsNot: {
|
};
|
||||||
if (recordIds.length === 0) return;
|
case RecordFilterOperand.IsNot: {
|
||||||
return {
|
if (recordIds.length === 0) return;
|
||||||
or: [
|
return {
|
||||||
{
|
or: [
|
||||||
not: {
|
{
|
||||||
[correspondingField.name + 'Id']: {
|
not: {
|
||||||
in: recordIds,
|
|
||||||
} as RelationFilter,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[correspondingField.name + 'Id']: {
|
[correspondingField.name + 'Id']: {
|
||||||
is: 'NULL',
|
in: recordIds,
|
||||||
} as RelationFilter,
|
} as RelationFilter,
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
};
|
{
|
||||||
}
|
[correspondingField.name + 'Id']: {
|
||||||
default:
|
is: 'NULL',
|
||||||
throw new Error(
|
} as RelationFilter,
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
},
|
||||||
);
|
],
|
||||||
}
|
};
|
||||||
} else {
|
|
||||||
switch (filter.operand) {
|
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown empty operand ${filter.operand} for ${filter.definition.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'CURRENCY':
|
case 'CURRENCY':
|
||||||
@ -385,16 +371,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
amountMicros: { lte: parseFloat(filter.value) * 1000000 },
|
amountMicros: { lte: parseFloat(filter.value) * 1000000 },
|
||||||
} as CurrencyFilter,
|
} as CurrencyFilter,
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'LINKS': {
|
case 'LINKS': {
|
||||||
@ -439,16 +418,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -493,16 +465,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -609,27 +574,12 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'MULTI_SELECT': {
|
case 'MULTI_SELECT': {
|
||||||
if (isEmptyOperand) {
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = resolveSelectViewFilterValue(filter);
|
const options = resolveSelectViewFilterValue(filter);
|
||||||
|
|
||||||
if (options.length === 0) return;
|
if (options.length === 0) return;
|
||||||
@ -665,18 +615,11 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'SELECT': {
|
case 'SELECT': {
|
||||||
if (isEmptyOperand) {
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const options = resolveSelectViewFilterValue(filter);
|
const options = resolveSelectViewFilterValue(filter);
|
||||||
|
|
||||||
if (options.length === 0) return;
|
if (options.length === 0) return;
|
||||||
@ -698,7 +641,7 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -718,16 +661,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
} as ArrayFilter,
|
} as ArrayFilter,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -786,13 +722,6 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.label} filter`,
|
`Unknown operand ${filter.operand} for ${filter.label} filter`,
|
||||||
@ -827,16 +756,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'PHONES': {
|
case 'PHONES': {
|
||||||
@ -869,16 +791,9 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
case RecordFilterOperand.IsEmpty:
|
|
||||||
case RecordFilterOperand.IsNotEmpty:
|
|
||||||
return getEmptyRecordGqlOperationFilter(
|
|
||||||
filter.operand,
|
|
||||||
correspondingField,
|
|
||||||
filter.definition,
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
`Unknown operand ${filter.operand} for ${filterType} filter`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -897,7 +812,7 @@ const computeFilterRecordGqlOperationFilter = (
|
|||||||
const computeViewFilterGroupRecordGqlOperationFilter = (
|
const computeViewFilterGroupRecordGqlOperationFilter = (
|
||||||
filterValueDependencies: RecordFilterValueDependencies,
|
filterValueDependencies: RecordFilterValueDependencies,
|
||||||
filters: RecordFilter[],
|
filters: RecordFilter[],
|
||||||
fields: Pick<Field, 'id' | 'name'>[],
|
fields: Pick<Field, 'id' | 'name' | 'type'>[],
|
||||||
viewFilterGroups: ViewFilterGroup[],
|
viewFilterGroups: ViewFilterGroup[],
|
||||||
currentViewFilterGroupId?: string,
|
currentViewFilterGroupId?: string,
|
||||||
): RecordGqlOperationFilter | undefined => {
|
): RecordGqlOperationFilter | undefined => {
|
||||||
@ -915,11 +830,11 @@ const computeViewFilterGroupRecordGqlOperationFilter = (
|
|||||||
|
|
||||||
const groupRecordGqlOperationFilters = groupFilters
|
const groupRecordGqlOperationFilters = groupFilters
|
||||||
.map((filter) =>
|
.map((filter) =>
|
||||||
computeFilterRecordGqlOperationFilter(
|
computeFilterRecordGqlOperationFilter({
|
||||||
filterValueDependencies,
|
filterValueDependencies,
|
||||||
filter,
|
filter,
|
||||||
fields,
|
fieldMetadataItems: fields,
|
||||||
),
|
}),
|
||||||
)
|
)
|
||||||
.filter(isDefined);
|
.filter(isDefined);
|
||||||
|
|
||||||
@ -968,17 +883,17 @@ const computeViewFilterGroupRecordGqlOperationFilter = (
|
|||||||
export const computeViewRecordGqlOperationFilter = (
|
export const computeViewRecordGqlOperationFilter = (
|
||||||
filterValueDependencies: RecordFilterValueDependencies,
|
filterValueDependencies: RecordFilterValueDependencies,
|
||||||
filters: RecordFilter[],
|
filters: RecordFilter[],
|
||||||
fields: Pick<Field, 'id' | 'name'>[],
|
fields: Pick<Field, 'id' | 'name' | 'type'>[],
|
||||||
viewFilterGroups: ViewFilterGroup[],
|
viewFilterGroups: ViewFilterGroup[],
|
||||||
): RecordGqlOperationFilter => {
|
): RecordGqlOperationFilter => {
|
||||||
const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] = filters
|
const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] = filters
|
||||||
.filter((filter) => !filter.viewFilterGroupId)
|
.filter((filter) => !filter.viewFilterGroupId)
|
||||||
.map((regularFilter) =>
|
.map((regularFilter) =>
|
||||||
computeFilterRecordGqlOperationFilter(
|
computeFilterRecordGqlOperationFilter({
|
||||||
filterValueDependencies,
|
filterValueDependencies,
|
||||||
regularFilter,
|
filter: regularFilter,
|
||||||
fields,
|
fieldMetadataItems: fields,
|
||||||
),
|
}),
|
||||||
)
|
)
|
||||||
.filter(isDefined);
|
.filter(isDefined);
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import {
|
import {
|
||||||
ActorFilter,
|
ActorFilter,
|
||||||
AddressFilter,
|
AddressFilter,
|
||||||
@ -15,24 +16,32 @@ import {
|
|||||||
StringFilter,
|
StringFilter,
|
||||||
URLFilter,
|
URLFilter,
|
||||||
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
import { Field } from '~/generated/graphql';
|
import { Field } from '~/generated/graphql';
|
||||||
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
|
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
|
||||||
|
|
||||||
export const getEmptyRecordGqlOperationFilter = (
|
type GetEmptyRecordGqlOperationFilterParams = {
|
||||||
operand: ViewFilterOperand,
|
operand: ViewFilterOperand;
|
||||||
correspondingField: Pick<Field, 'id' | 'name'>,
|
correspondingField: Pick<Field, 'id' | 'name' | 'type'>;
|
||||||
definition: RecordFilterDefinition,
|
recordFilter: RecordFilter;
|
||||||
) => {
|
};
|
||||||
|
|
||||||
|
export const getEmptyRecordGqlOperationFilter = ({
|
||||||
|
operand,
|
||||||
|
correspondingField,
|
||||||
|
recordFilter,
|
||||||
|
}: GetEmptyRecordGqlOperationFilterParams) => {
|
||||||
let emptyRecordFilter: RecordGqlOperationFilter = {};
|
let emptyRecordFilter: RecordGqlOperationFilter = {};
|
||||||
|
|
||||||
const compositeFieldName = definition.compositeFieldName;
|
const compositeFieldName = recordFilter.subFieldName;
|
||||||
|
|
||||||
const isCompositeField = isNonEmptyString(compositeFieldName);
|
const isCompositeField = isNonEmptyString(compositeFieldName);
|
||||||
|
|
||||||
switch (definition.type) {
|
const filterType = getFilterTypeFromFieldType(correspondingField.type);
|
||||||
|
|
||||||
|
switch (filterType) {
|
||||||
case 'TEXT':
|
case 'TEXT':
|
||||||
emptyRecordFilter = {
|
emptyRecordFilter = {
|
||||||
or: [
|
or: [
|
||||||
@ -344,7 +353,7 @@ export const getEmptyRecordGqlOperationFilter = (
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported empty filter type ${definition.type}`);
|
throw new Error(`Unsupported empty filter type ${filterType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (operand) {
|
switch (operand) {
|
||||||
@ -355,8 +364,6 @@ export const getEmptyRecordGqlOperationFilter = (
|
|||||||
not: emptyRecordFilter,
|
not: emptyRecordFilter,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(`Unknown operand ${operand} for ${filterType} filter`);
|
||||||
`Unknown operand ${operand} for ${definition.type} filter`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,99 +0,0 @@
|
|||||||
import { isActorSourceCompositeFilter } from '@/object-record/object-filter-dropdown/utils/isActorSourceCompositeFilter';
|
|
||||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
|
||||||
import { ViewFilterOperand as RecordFilterOperand } from '@/views/types/ViewFilterOperand';
|
|
||||||
|
|
||||||
export const getRecordFilterOperandsForRecordFilterDefinition = (
|
|
||||||
filterDefinition: Pick<RecordFilterDefinition, 'type' | 'compositeFieldName'>,
|
|
||||||
): RecordFilterOperand[] => {
|
|
||||||
const emptyOperands = [
|
|
||||||
RecordFilterOperand.IsEmpty,
|
|
||||||
RecordFilterOperand.IsNotEmpty,
|
|
||||||
];
|
|
||||||
|
|
||||||
const relationOperands = [RecordFilterOperand.Is, RecordFilterOperand.IsNot];
|
|
||||||
|
|
||||||
switch (filterDefinition.type) {
|
|
||||||
case 'TEXT':
|
|
||||||
case 'EMAILS':
|
|
||||||
case 'FULL_NAME':
|
|
||||||
case 'ADDRESS':
|
|
||||||
case 'LINKS':
|
|
||||||
case 'PHONES':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Contains,
|
|
||||||
RecordFilterOperand.DoesNotContain,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'CURRENCY':
|
|
||||||
case 'NUMBER':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.GreaterThan,
|
|
||||||
RecordFilterOperand.LessThan,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'RAW_JSON':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Contains,
|
|
||||||
RecordFilterOperand.DoesNotContain,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'DATE_TIME':
|
|
||||||
case 'DATE':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Is,
|
|
||||||
RecordFilterOperand.IsRelative,
|
|
||||||
RecordFilterOperand.IsInPast,
|
|
||||||
RecordFilterOperand.IsInFuture,
|
|
||||||
RecordFilterOperand.IsToday,
|
|
||||||
RecordFilterOperand.IsBefore,
|
|
||||||
RecordFilterOperand.IsAfter,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'RATING':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Is,
|
|
||||||
RecordFilterOperand.GreaterThan,
|
|
||||||
RecordFilterOperand.LessThan,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'RELATION':
|
|
||||||
return [...relationOperands, ...emptyOperands];
|
|
||||||
case 'MULTI_SELECT':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Contains,
|
|
||||||
RecordFilterOperand.DoesNotContain,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'SELECT':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Is,
|
|
||||||
RecordFilterOperand.IsNot,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'ACTOR': {
|
|
||||||
if (isActorSourceCompositeFilter(filterDefinition)) {
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Is,
|
|
||||||
RecordFilterOperand.IsNot,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Contains,
|
|
||||||
RecordFilterOperand.DoesNotContain,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
case 'ARRAY':
|
|
||||||
return [
|
|
||||||
RecordFilterOperand.Contains,
|
|
||||||
RecordFilterOperand.DoesNotContain,
|
|
||||||
...emptyOperands,
|
|
||||||
];
|
|
||||||
case 'BOOLEAN':
|
|
||||||
return [RecordFilterOperand.Is];
|
|
||||||
default:
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -5,12 +5,15 @@ import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/u
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
|
||||||
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import {
|
||||||
|
formatFieldMetadataItemAsFilterDefinition,
|
||||||
|
getFilterTypeFromFieldType,
|
||||||
|
} 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 { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
@ -115,8 +118,11 @@ export const useHandleToggleColumnFilter = ({
|
|||||||
throw new Error('Filter definition not found');
|
throw new Error('Filter definition not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const availableOperandsForFilter =
|
const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type);
|
||||||
getRecordFilterOperandsForRecordFilterDefinition(filterDefinition);
|
|
||||||
|
const availableOperandsForFilter = getRecordFilterOperands({
|
||||||
|
filterType,
|
||||||
|
});
|
||||||
|
|
||||||
const defaultOperand = availableOperandsForFilter[0];
|
const defaultOperand = availableOperandsForFilter[0];
|
||||||
|
|
||||||
|
|||||||
@ -13,15 +13,17 @@ import { currentViewIdComponentState } from '@/views/states/currentViewIdCompone
|
|||||||
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 { isDefined } from 'twenty-shared';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
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');
|
||||||
|
|
||||||
|
const mockObjectMetadataItemNameSingular = 'company';
|
||||||
|
|
||||||
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||||
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'company',
|
(item) => item.nameSingular === mockObjectMetadataItemNameSingular,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isDefined(mockObjectMetadataItem)) {
|
if (!isDefined(mockObjectMetadataItem)) {
|
||||||
@ -76,7 +78,11 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||||
|
apolloMocks: [],
|
||||||
|
componentInstanceId: 'instanceId',
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular:
|
||||||
|
mockObjectMetadataItemNameSingular,
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
snapshot.set(
|
snapshot.set(
|
||||||
currentViewIdComponentState.atomFamily({
|
currentViewIdComponentState.atomFamily({
|
||||||
@ -129,7 +135,11 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||||
|
apolloMocks: [],
|
||||||
|
componentInstanceId: 'instanceId',
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular:
|
||||||
|
mockObjectMetadataItemNameSingular,
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
snapshot.set(
|
snapshot.set(
|
||||||
currentViewIdComponentState.atomFamily({
|
currentViewIdComponentState.atomFamily({
|
||||||
@ -174,7 +184,11 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||||
|
apolloMocks: [],
|
||||||
|
componentInstanceId: 'instanceId',
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular:
|
||||||
|
mockObjectMetadataItemNameSingular,
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
snapshot.set(
|
snapshot.set(
|
||||||
currentViewIdComponentState.atomFamily({
|
currentViewIdComponentState.atomFamily({
|
||||||
|
|||||||
@ -11,18 +11,20 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
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 { isDefined } from 'twenty-shared';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { useApplyViewFiltersToCurrentRecordFilters } from '../useApplyViewFiltersToCurrentRecordFilters';
|
import { useApplyViewFiltersToCurrentRecordFilters } from '../useApplyViewFiltersToCurrentRecordFilters';
|
||||||
|
|
||||||
|
const mockObjectMetadataItemNameSingular = 'company';
|
||||||
|
|
||||||
describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
||||||
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'company',
|
(item) => item.nameSingular === mockObjectMetadataItemNameSingular,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isDefined(mockObjectMetadataItem)) {
|
if (!isDefined(mockObjectMetadataItem)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Missing mock object metadata item with name singular "company"',
|
`Missing mock object metadata item with name singular ${mockObjectMetadataItemNameSingular}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +60,12 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
|||||||
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({}),
|
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||||
|
apolloMocks: [],
|
||||||
|
componentInstanceId: 'instanceId',
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular:
|
||||||
|
mockObjectMetadataItemNameSingular,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -95,7 +102,12 @@ describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
|||||||
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
wrapper: getJestMetadataAndApolloMocksWrapper({}),
|
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||||
|
apolloMocks: [],
|
||||||
|
componentInstanceId: 'instanceId',
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular:
|
||||||
|
mockObjectMetadataItemNameSingular,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -121,7 +121,7 @@ export const WorkflowEditTriggerCronForm = ({
|
|||||||
|
|
||||||
const cronValidator = cron(newPattern);
|
const cronValidator = cron(newPattern);
|
||||||
|
|
||||||
if (cronValidator.isError()) {
|
if (cronValidator.isError() === true) {
|
||||||
setErrorMessages({
|
setErrorMessages({
|
||||||
CUSTOM: `Invalid cron pattern, ${cronValidator
|
CUSTOM: `Invalid cron pattern, ${cronValidator
|
||||||
.getError()[0]
|
.getError()[0]
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||||
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 { MockedResponse } from '@apollo/client/testing';
|
import { MockedResponse } from '@apollo/client/testing';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { MutableSnapshot } from 'recoil';
|
import { MutableSnapshot } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||||
import {
|
import {
|
||||||
JestContextStoreSetter,
|
JestContextStoreSetter,
|
||||||
JestContextStoreSetterMocks,
|
JestContextStoreSetterMocks,
|
||||||
} from '~/testing/jest/JestContextStoreSetter';
|
} from '~/testing/jest/JestContextStoreSetter';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
|
||||||
export type GetJestMetadataAndApolloMocksAndActionMenuWrapperProps = {
|
export type GetJestMetadataAndApolloMocksAndActionMenuWrapperProps = {
|
||||||
apolloMocks:
|
apolloMocks:
|
||||||
@ -32,6 +35,18 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({
|
|||||||
onInitializeRecoilSnapshot,
|
onInitializeRecoilSnapshot,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
(objectMetadataItem) =>
|
||||||
|
objectMetadataItem.nameSingular ===
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(mockObjectMetadataItem)) {
|
||||||
|
throw new Error(
|
||||||
|
`Mock object metadata item ${contextStoreCurrentObjectMetadataNameSingular} not found`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return ({ children }: { children: ReactNode }) => (
|
return ({ children }: { children: ReactNode }) => (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<RecordFiltersComponentInstanceContext.Provider
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
@ -47,18 +62,31 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({
|
|||||||
instanceId: componentInstanceId,
|
instanceId: componentInstanceId,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<JestContextStoreSetter
|
<RecordIndexContextProvider
|
||||||
contextStoreFilters={contextStoreFilters}
|
value={{
|
||||||
contextStoreTargetedRecordsRule={contextStoreTargetedRecordsRule}
|
indexIdentifierUrl: () => 'indexIdentifierUrl',
|
||||||
contextStoreNumberOfSelectedRecords={
|
onIndexRecordsLoaded: () => {},
|
||||||
contextStoreNumberOfSelectedRecords
|
objectNamePlural: mockObjectMetadataItem.namePlural,
|
||||||
}
|
objectNameSingular: mockObjectMetadataItem.nameSingular,
|
||||||
contextStoreCurrentObjectMetadataNameSingular={
|
objectMetadataItem: mockObjectMetadataItem,
|
||||||
contextStoreCurrentObjectMetadataNameSingular
|
recordIndexId: 'recordIndexId',
|
||||||
}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
<JestContextStoreSetter
|
||||||
</JestContextStoreSetter>
|
contextStoreFilters={contextStoreFilters}
|
||||||
|
contextStoreTargetedRecordsRule={
|
||||||
|
contextStoreTargetedRecordsRule
|
||||||
|
}
|
||||||
|
contextStoreNumberOfSelectedRecords={
|
||||||
|
contextStoreNumberOfSelectedRecords
|
||||||
|
}
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular={
|
||||||
|
contextStoreCurrentObjectMetadataNameSingular
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</JestContextStoreSetter>
|
||||||
|
</RecordIndexContextProvider>
|
||||||
</ActionMenuComponentInstanceContext.Provider>
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
</ContextStoreComponentInstanceContext.Provider>
|
</ContextStoreComponentInstanceContext.Provider>
|
||||||
</RecordFiltersComponentInstanceContext.Provider>
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
|
|||||||
@ -3,12 +3,10 @@ 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 { InMemoryCache } from '@apollo/client';
|
import { InMemoryCache } from '@apollo/client';
|
||||||
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,
|
||||||
@ -25,31 +23,17 @@ export const getJestMetadataAndApolloMocksWrapper = ({
|
|||||||
<RecoilRoot initializeState={onInitializeRecoilSnapshot}>
|
<RecoilRoot initializeState={onInitializeRecoilSnapshot}>
|
||||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||||
<MockedProvider mocks={apolloMocks} addTypename={false} cache={cache}>
|
<MockedProvider mocks={apolloMocks} addTypename={false} cache={cache}>
|
||||||
<RecordIndexContextProvider
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
value={{
|
value={{ instanceId: 'instanceId' }}
|
||||||
indexIdentifierUrl: () => 'indexIdentifierUrl',
|
|
||||||
onIndexRecordsLoaded: () => {},
|
|
||||||
objectNamePlural: 'objectNamePlural',
|
|
||||||
objectNameSingular: 'objectNameSingular',
|
|
||||||
objectMetadataItem:
|
|
||||||
generatedMockObjectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === 'company',
|
|
||||||
) ?? generatedMockObjectMetadataItems[0],
|
|
||||||
recordIndexId: 'recordIndexId',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<RecordFiltersComponentInstanceContext.Provider
|
<ViewComponentInstanceContext.Provider
|
||||||
value={{ instanceId: 'instanceId' }}
|
value={{ instanceId: 'instanceId' }}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider
|
<JestObjectMetadataItemSetter>
|
||||||
value={{ instanceId: 'instanceId' }}
|
{children}
|
||||||
>
|
</JestObjectMetadataItemSetter>
|
||||||
<JestObjectMetadataItemSetter>
|
</ViewComponentInstanceContext.Provider>
|
||||||
{children}
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
</JestObjectMetadataItemSetter>
|
|
||||||
</ViewComponentInstanceContext.Provider>
|
|
||||||
</RecordFiltersComponentInstanceContext.Provider>
|
|
||||||
</RecordIndexContextProvider>
|
|
||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
</SnackBarProviderScope>
|
</SnackBarProviderScope>
|
||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
|
|||||||
Reference in New Issue
Block a user