[GroupBy] Add views filters to groupBy query (#14762)
Closes https://github.com/twentyhq/core-team-issues/issues/1560 If viewId is defined in a groupBy query, we want to apply all filters of the view to the query. This required to move a lot of code from twenty-front to twenty-shared to convert the filters as stored in the db into graphql filters, applying the right combinations between filters etc., which was previously only done in the FE. This PR does not handle any field filters, it will be done in a later pr
This commit is contained in:
+1
-1
@@ -6,13 +6,13 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { useDestroyManyRecords } from '@/object-record/hooks/useDestroyManyRecords';
|
||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
|
||||
export const DestroyMultipleRecordsAction = () => {
|
||||
const { recordIndexId, objectMetadataItem } =
|
||||
|
||||
+1
-1
@@ -6,13 +6,13 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||
import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
|
||||
export const RestoreMultipleRecordsAction = () => {
|
||||
const { recordIndexId, objectMetadataItem } =
|
||||
|
||||
@@ -8,10 +8,10 @@ import { type Note } from '@/activities/types/Note';
|
||||
import { type Task } from '@/activities/types/Task';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
import { sortByAscString } from '~/utils/array/sortByAscString';
|
||||
|
||||
export const useActivities = <T extends Task | Note>({
|
||||
|
||||
+4
-2
@@ -1,8 +1,10 @@
|
||||
import { type ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { type RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import {
|
||||
type RecordFilterValueDependencies,
|
||||
ViewFilterOperand,
|
||||
} from 'twenty-shared/types';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
|
||||
describe('computeContextStoreFilters', () => {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { type ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { type RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter';
|
||||
import { turnAnyFieldFilterIntoRecordGqlFilter } from '@/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter';
|
||||
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
||||
import {
|
||||
type RecordFilterValueDependencies,
|
||||
type RecordGqlOperationFilter,
|
||||
} from 'twenty-shared/types';
|
||||
import { computeRecordGqlOperationFilter } from 'twenty-shared/utils';
|
||||
|
||||
type ComputeContextStoreFiltersProps = {
|
||||
contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// This class is used to group different error messages under the same code for sentry.
|
||||
export class CustomError extends Error {
|
||||
public code?: string;
|
||||
|
||||
constructor(message: string, code?: string) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import { AppErrorBoundaryEffect } from '@/error-handler/components/internal/AppErrorBoundaryEffect';
|
||||
import { type CustomError } from '@/error-handler/CustomError';
|
||||
import { checkIfItsAViteStaleChunkLazyLoadingError } from '@/error-handler/utils/checkIfItsAViteStaleChunkLazyLoadingError';
|
||||
import { type ErrorInfo, type ReactNode } from 'react';
|
||||
import { ErrorBoundary, type FallbackProps } from 'react-error-boundary';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type CustomError, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type AppErrorBoundaryProps = {
|
||||
children: ReactNode;
|
||||
|
||||
+1
-2
@@ -1,9 +1,8 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { type CustomError } from '@/error-handler/CustomError';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined, type CustomError } from 'twenty-shared/utils';
|
||||
|
||||
const hasErrorCode = (
|
||||
error: CustomError | any,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { FAVORITE_DROPPABLE_IDS } from '@/favorites/constants/FavoriteDroppableIds';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
|
||||
export const validateAndExtractFolderId = (
|
||||
droppableId: string,
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CustomError, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useGetObjectMetadataItemById = () => {
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CustomError, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useObjectMetadataItemById = ({
|
||||
objectId,
|
||||
|
||||
-50
@@ -1,6 +1,3 @@
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
import { type FilterableAndTSVectorFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type ObjectMetadataItem } from '../types/ObjectMetadataItem';
|
||||
|
||||
export const getRelationObjectMetadataNameSingular = ({
|
||||
@@ -10,50 +7,3 @@ export const getRelationObjectMetadataNameSingular = ({
|
||||
}): string | undefined => {
|
||||
return field.relation?.targetObjectMetadata.nameSingular;
|
||||
};
|
||||
|
||||
export const getFilterTypeFromFieldType = (
|
||||
fieldType: FieldMetadataType,
|
||||
): FilterableAndTSVectorFieldType => {
|
||||
switch (fieldType) {
|
||||
case FieldMetadataType.DATE_TIME:
|
||||
return 'DATE_TIME';
|
||||
case FieldMetadataType.DATE:
|
||||
return 'DATE';
|
||||
case FieldMetadataType.LINKS:
|
||||
return 'LINKS';
|
||||
case FieldMetadataType.FULL_NAME:
|
||||
return 'FULL_NAME';
|
||||
case FieldMetadataType.NUMBER:
|
||||
return 'NUMBER';
|
||||
case FieldMetadataType.CURRENCY:
|
||||
return 'CURRENCY';
|
||||
case FieldMetadataType.EMAILS:
|
||||
return 'EMAILS';
|
||||
case FieldMetadataType.PHONES:
|
||||
return 'PHONES';
|
||||
case FieldMetadataType.RELATION:
|
||||
return 'RELATION';
|
||||
case FieldMetadataType.SELECT:
|
||||
return 'SELECT';
|
||||
case FieldMetadataType.MULTI_SELECT:
|
||||
return 'MULTI_SELECT';
|
||||
case FieldMetadataType.ADDRESS:
|
||||
return 'ADDRESS';
|
||||
case FieldMetadataType.RATING:
|
||||
return 'RATING';
|
||||
case FieldMetadataType.ACTOR:
|
||||
return 'ACTOR';
|
||||
case FieldMetadataType.ARRAY:
|
||||
return 'ARRAY';
|
||||
case FieldMetadataType.RAW_JSON:
|
||||
return 'RAW_JSON';
|
||||
case FieldMetadataType.BOOLEAN:
|
||||
return 'BOOLEAN';
|
||||
case FieldMetadataType.TS_VECTOR:
|
||||
return 'TS_VECTOR';
|
||||
case FieldMetadataType.UUID:
|
||||
return 'UUID';
|
||||
default:
|
||||
return 'TEXT';
|
||||
}
|
||||
};
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CustomError, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type GetFieldMetadataItemByIdParams = {
|
||||
fieldMetadataId: string;
|
||||
|
||||
+2
-3
@@ -1,12 +1,10 @@
|
||||
import { ActionButton } from '@/action-menu/actions/display/components/ActionButton';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups';
|
||||
import { useDefaultFieldMetadataItemForFilter } from '@/object-record/advanced-filter/hooks/useDefaultFieldMetadataItemForFilter';
|
||||
import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow';
|
||||
import { getAdvancedFilterAddFilterRuleSelectDropdownId } from '@/object-record/advanced-filter/utils/getAdvancedFilterAddFilterRuleSelectDropdownId';
|
||||
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
|
||||
@@ -16,7 +14,8 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
import { IconLibraryPlus, IconPlus } from 'twenty-ui/display';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
+1
-1
@@ -13,13 +13,13 @@ import { ObjectFilterDropdownDateInput } from '@/object-record/object-filter-dro
|
||||
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
||||
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName';
|
||||
import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isExpectedSubFieldName } from 'twenty-shared/utils';
|
||||
|
||||
type AdvancedFilterDropdownFilterInputProps = {
|
||||
filterDropdownId: string;
|
||||
|
||||
+1
-1
@@ -10,7 +10,6 @@ import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectab
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { AdvancedFilterFieldSelectSearchInput } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput';
|
||||
import { useAdvancedFilterFieldSelectDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterFieldSelectDropdown';
|
||||
import { useSelectFieldUsedInAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown';
|
||||
@@ -27,6 +26,7 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { getFilterTypeFromFieldType } from 'twenty-shared/utils';
|
||||
|
||||
type AdvancedFilterFieldSelectMenuProps = {
|
||||
recordFilterId: string;
|
||||
|
||||
+1
-1
@@ -2,9 +2,9 @@ import { ADVANCED_FILTER_LOGICAL_OPERATOR_OPTIONS } from '@/object-record/advanc
|
||||
import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset';
|
||||
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { type RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { type RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
|
||||
type AdvancedFilterLogicalOperatorDropdownProps = {
|
||||
recordFilterGroup: RecordFilterGroup;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
|
||||
export const ADVANCED_FILTER_LOGICAL_OPERATOR_OPTIONS = [
|
||||
{
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
import { useGetFieldMetadataItemByIdOrThrow } from '@/object-metadata/hooks/useGetFieldMetadataItemById';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
@@ -18,7 +17,7 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type SelectFilterParams = {
|
||||
fieldMetadataItemId: string;
|
||||
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
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 { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { type RecordFilter } from '../../record-filter/types/RecordFilter';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
|
||||
import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isExpectedSubFieldName } from 'twenty-shared/utils';
|
||||
|
||||
export const shouldShowFilterTextInput = ({
|
||||
recordFilter,
|
||||
|
||||
-188
@@ -1,188 +0,0 @@
|
||||
export type UUIDFilterValue = string;
|
||||
|
||||
export type IsFilter = 'NULL' | 'NOT_NULL';
|
||||
|
||||
export type UUIDFilter = {
|
||||
eq?: UUIDFilterValue;
|
||||
in?: UUIDFilterValue[];
|
||||
neq?: UUIDFilterValue;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type RelationFilter = {
|
||||
is?: IsFilter;
|
||||
in?: UUIDFilterValue[];
|
||||
};
|
||||
|
||||
export type BooleanFilter = {
|
||||
eq?: boolean;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type StringFilter = {
|
||||
eq?: string;
|
||||
in?: string[];
|
||||
neq?: string;
|
||||
startsWith?: string;
|
||||
like?: string;
|
||||
ilike?: string;
|
||||
regex?: string;
|
||||
iregex?: string;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type RatingFilter = {
|
||||
eq?: string;
|
||||
in?: string[];
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type FloatFilter = {
|
||||
eq?: number;
|
||||
gt?: number;
|
||||
gte?: number;
|
||||
in?: number[];
|
||||
lt?: number;
|
||||
lte?: number;
|
||||
neq?: number;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Always use a DateFilter in the variables of a query, and never directly in the query.
|
||||
*
|
||||
* Because pg_graphql only works with ISO strings if it is passed to variables.
|
||||
*/
|
||||
export type DateFilter = {
|
||||
eq?: string;
|
||||
gt?: string;
|
||||
gte?: string;
|
||||
in?: string[];
|
||||
lt?: string;
|
||||
lte?: string;
|
||||
neq?: string;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type CurrencyFilter = {
|
||||
amountMicros?: FloatFilter;
|
||||
currencyCode?: SelectFilter;
|
||||
};
|
||||
|
||||
export type URLFilter = {
|
||||
url?: StringFilter;
|
||||
label?: StringFilter;
|
||||
};
|
||||
|
||||
export type FullNameFilter = {
|
||||
firstName?: StringFilter;
|
||||
lastName?: StringFilter;
|
||||
};
|
||||
|
||||
export type AddressFilter = {
|
||||
addressStreet1?: StringFilter;
|
||||
addressStreet2?: StringFilter;
|
||||
addressCity?: StringFilter;
|
||||
addressState?: StringFilter;
|
||||
addressCountry?: StringFilter;
|
||||
addressPostcode?: StringFilter;
|
||||
};
|
||||
|
||||
export type LinksFilter = {
|
||||
primaryLinkUrl?: StringFilter;
|
||||
primaryLinkLabel?: StringFilter;
|
||||
secondaryLinks?: RawJsonFilter;
|
||||
};
|
||||
|
||||
export type ActorFilter = {
|
||||
name?: StringFilter;
|
||||
source?: SelectFilter;
|
||||
};
|
||||
|
||||
export type EmailsFilter = {
|
||||
primaryEmail?: StringFilter;
|
||||
additionalEmails?: RawJsonFilter;
|
||||
};
|
||||
|
||||
export type PhonesFilter = {
|
||||
primaryPhoneNumber?: StringFilter;
|
||||
primaryPhoneCallingCode?: StringFilter;
|
||||
additionalPhones?: RawJsonFilter;
|
||||
};
|
||||
|
||||
export type SelectFilter = {
|
||||
is?: IsFilter;
|
||||
in?: string[];
|
||||
eq?: string;
|
||||
};
|
||||
|
||||
export type MultiSelectFilter = {
|
||||
is?: IsFilter;
|
||||
isEmptyArray?: boolean;
|
||||
containsAny?: string[];
|
||||
};
|
||||
|
||||
export type ArrayFilter = {
|
||||
is?: IsFilter;
|
||||
isEmptyArray?: boolean;
|
||||
containsIlike?: string;
|
||||
};
|
||||
|
||||
export type RawJsonFilter = {
|
||||
like?: string;
|
||||
is?: IsFilter;
|
||||
};
|
||||
|
||||
export type RichTextV2LeafFilter = {
|
||||
ilike?: string;
|
||||
};
|
||||
|
||||
export type RichTextV2Filter = {
|
||||
blocknote?: RichTextV2LeafFilter;
|
||||
markdown?: RichTextV2LeafFilter;
|
||||
};
|
||||
|
||||
export type TSVectorFilter = {
|
||||
search: string;
|
||||
};
|
||||
|
||||
export type LeafFilter =
|
||||
| UUIDFilter
|
||||
| StringFilter
|
||||
| FloatFilter
|
||||
| DateFilter
|
||||
| CurrencyFilter
|
||||
| URLFilter
|
||||
| FullNameFilter
|
||||
| BooleanFilter
|
||||
| AddressFilter
|
||||
| LinksFilter
|
||||
| ActorFilter
|
||||
| PhonesFilter
|
||||
| ArrayFilter
|
||||
| RawJsonFilter
|
||||
| RichTextV2Filter
|
||||
| TSVectorFilter
|
||||
| undefined;
|
||||
|
||||
export type AndObjectRecordFilter = {
|
||||
and?: RecordGqlOperationFilter[];
|
||||
};
|
||||
|
||||
export type OrObjectRecordFilter = {
|
||||
or?: RecordGqlOperationFilter[] | RecordGqlOperationFilter;
|
||||
};
|
||||
|
||||
export type NotObjectRecordFilter = {
|
||||
not?: RecordGqlOperationFilter;
|
||||
};
|
||||
|
||||
export type LeafObjectRecordFilter = {
|
||||
[fieldName: string]: LeafFilter;
|
||||
};
|
||||
|
||||
export type RecordGqlOperationFilter =
|
||||
| LeafObjectRecordFilter
|
||||
| AndObjectRecordFilter
|
||||
| OrObjectRecordFilter
|
||||
| NotObjectRecordFilter;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type QueryCursorDirection } from '@/object-record/utils/generateFindManyRecordsQuery';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
|
||||
export type RecordGqlOperationVariables = {
|
||||
filter?: RecordGqlOperationFilter;
|
||||
|
||||
@@ -3,12 +3,12 @@ import { useQuery } from '@apollo/client';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { type RecordGqlFieldsAggregate } from '@/object-record/graphql/types/RecordGqlFieldsAggregate';
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult';
|
||||
import { useAggregateRecordsQuery } from '@/object-record/hooks/useAggregateRecordsQuery';
|
||||
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
|
||||
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export type AggregateRecordsData = {
|
||||
|
||||
+1
-2
@@ -1,4 +1,3 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
@@ -8,7 +7,7 @@ import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphq
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CustomError, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type useAttachRelatedRecordFromRecordProps = {
|
||||
recordObjectNameSingular: string;
|
||||
|
||||
@@ -15,8 +15,8 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { type OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted';
|
||||
import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier';
|
||||
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { QUERY_DEFAULT_LIMIT_RECORDS } from 'twenty-shared/constants';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
|
||||
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
|
||||
RecordGqlOperationVariables & {
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||
@@ -23,7 +22,7 @@ import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput';
|
||||
import { isNull } from '@sniptt/guards';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CustomError, isDefined } from 'twenty-shared/utils';
|
||||
import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue';
|
||||
|
||||
type UpdateManyRecordArgs = {
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||
import { DATE_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/object-filter-dropdown/constants/DatePickerDropdownContentWidth';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const ObjectFilterDropdownContentWrapper = ({
|
||||
children,
|
||||
|
||||
+1
-2
@@ -6,14 +6,13 @@ import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropd
|
||||
import { DateTimePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { computeVariableDateViewFilterValue } from '@/views/view-filter-value/utils/computeVariableDateViewFilterValue';
|
||||
import { resolveDateViewFilterValue } from '@/views/view-filter-value/utils/resolveDateViewFilterValue';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
ViewFilterOperand,
|
||||
type VariableDateViewFilterValueDirection,
|
||||
type VariableDateViewFilterValueUnit,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined, resolveDateViewFilterValue } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const ObjectFilterDropdownDateInput = () => {
|
||||
|
||||
+1
-2
@@ -8,7 +8,6 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
||||
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
||||
import { ObjectFilterDropdownInnerSelectOperandDropdown } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown';
|
||||
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
||||
@@ -19,7 +18,7 @@ import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/consta
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type ObjectFilterDropdownFilterInputProps = {
|
||||
filterDropdownId: string;
|
||||
|
||||
+1
-2
@@ -1,4 +1,3 @@
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||
import { DATE_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/object-filter-dropdown/constants/DatePickerDropdownContentWidth';
|
||||
import { useApplyObjectFilterDropdownOperand } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand';
|
||||
@@ -11,7 +10,7 @@ import { getRecordFilterOperands } from '@/object-record/record-filter/utils/get
|
||||
import { DropdownMenuInnerSelect } from '@/ui/layout/dropdown/components/DropdownMenuInnerSelect';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
import { type SelectOption } from 'twenty-ui/input';
|
||||
|
||||
const OBJECT_FILTER_DROPDOWN_INNER_SELECT_OPERAND_DROPDOWN_ID =
|
||||
|
||||
+3
-4
@@ -1,10 +1,9 @@
|
||||
import { RATING_VALUES } from '@/object-record/record-field/ui/meta-types/constants/RatingValues';
|
||||
import { type FieldRatingValue } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { RatingInput } from '@/ui/field/input/components/RatingInput';
|
||||
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
import { RatingInput } from '@/ui/field/input/components/RatingInput';
|
||||
import styled from '@emotion/styled';
|
||||
import { RATING_VALUES } from 'twenty-shared/constants';
|
||||
import { type FieldRatingValue } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledRatingInputContainer = styled.div`
|
||||
|
||||
+5
-3
@@ -14,9 +14,11 @@ import { type SelectableItem } from '@/object-record/select/types/SelectableItem
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { type RelationFilterValue } from '@/views/view-filter-value/types/RelationFilterValue';
|
||||
import { arrayOfUuidOrVariableSchema } from '@/views/view-filter-value/validation-schemas/arrayOfUuidsOrVariablesSchema';
|
||||
import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
arrayOfUuidOrVariableSchema,
|
||||
isDefined,
|
||||
jsonRelationFilterValueSchema,
|
||||
} from 'twenty-shared/utils';
|
||||
import { IconUserCircle } from 'twenty-ui/display';
|
||||
|
||||
export const EMPTY_FILTER_VALUE: string = JSON.stringify({
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import { type FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import { type FieldType } from '@/settings/data-model/types/FieldType';
|
||||
import { type FilterableFieldType } from 'twenty-shared/types';
|
||||
|
||||
describe('getOperandsForFilterType', () => {
|
||||
const emptyOperands = [
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { type FilterableAndTSVectorFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { getDateFilterDisplayValue } from '@/object-record/record-filter/utils/getDateFilterDisplayValue';
|
||||
import { type FilterableAndTSVectorFieldType } from 'twenty-shared/types';
|
||||
|
||||
export const getInitialFilterValue = (
|
||||
newType: FilterableAndTSVectorFieldType,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type FilterableFieldType } from 'twenty-shared/types';
|
||||
|
||||
export const getSubMenuOptions = (subMenu: FilterableFieldType | null) => {
|
||||
switch (subMenu) {
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { type CompositeFilterableFieldType } from '@/object-record/record-filter/types/CompositeFilterableFieldType';
|
||||
import { FILTERABLE_FIELD_TYPES } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { COMPOSITE_FIELD_TYPES } from '@/settings/data-model/types/CompositeFieldType';
|
||||
import { type FieldType } from '@/settings/data-model/types/FieldType';
|
||||
import { FILTERABLE_FIELD_TYPES } from 'twenty-shared/types';
|
||||
|
||||
export const isCompositeFilterableFieldType = (
|
||||
type: FieldType,
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
||||
|
||||
export const isExpectedSubFieldName = <
|
||||
GivenFieldType extends keyof typeof SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS,
|
||||
CompositeFieldTypeSettings extends
|
||||
typeof SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS,
|
||||
PossibleSubFieldsForGivenFieldType extends
|
||||
CompositeFieldTypeSettings[GivenFieldType]['subFields'][number]['subFieldName'],
|
||||
>(
|
||||
fieldMetadataType: GivenFieldType,
|
||||
subFieldName: PossibleSubFieldsForGivenFieldType,
|
||||
subFieldNameToCheck: string | null | undefined,
|
||||
): subFieldNameToCheck is PossibleSubFieldsForGivenFieldType => {
|
||||
return (
|
||||
SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS[fieldMetadataType].subFields
|
||||
.map((subField) => subField.subFieldName)
|
||||
.includes(subFieldName) && subFieldName === subFieldNameToCheck
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { DateAggregateOperations } from '@/object-record/record-table/constants/DateAggregateOperations';
|
||||
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
|
||||
export const getAggregateOperationLabel = (
|
||||
operation: ExtendedAggregateOperations,
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { DateAggregateOperations } from '@/object-record/record-table/constants/DateAggregateOperations';
|
||||
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
|
||||
export const getAggregateOperationShortLabel = (
|
||||
operation: ExtendedAggregateOperations,
|
||||
|
||||
+4
-2
@@ -2,9 +2,11 @@ import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar
|
||||
import { useRecordCalendarMonthDaysRange } from '@/object-record/record-calendar/month/hooks/useRecordCalendarMonthDaysRange';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
computeRecordGqlOperationFilter,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
const DATE_RANGE_FILTER_AFTER_ID = 'DATE_RANGE_FILTER_AFTER_ID';
|
||||
const DATE_RANGE_FILTER_BEFORE_ID = 'DATE_RANGE_FILTER_BEFORE_ID';
|
||||
|
||||
+5
-2
@@ -3,7 +3,6 @@ import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords';
|
||||
import { RecordDetailSectionContainer } from '@/object-record/record-field-list/record-detail-section/components/RecordDetailSectionContainer';
|
||||
import { RecordDetailRelationRecordsList } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsList';
|
||||
@@ -24,7 +23,11 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { AppPath, ViewFilterOperand } from 'twenty-shared/types';
|
||||
import {
|
||||
AppPath,
|
||||
ViewFilterOperand,
|
||||
type RecordGqlOperationFilter,
|
||||
} from 'twenty-shared/types';
|
||||
import { getAppPath } from 'twenty-shared/utils';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
|
||||
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
export const RATING_VALUES = [
|
||||
'RATING_1',
|
||||
'RATING_2',
|
||||
'RATING_3',
|
||||
'RATING_4',
|
||||
'RATING_5',
|
||||
] as const;
|
||||
+1
-1
@@ -4,8 +4,8 @@ import { useRecoilState } from 'recoil';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
import { type FieldRatingValue } from 'twenty-shared/types';
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
import { type FieldRatingValue } from '../../types/FieldMetadata';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
import { isFieldRating } from '../../types/guards/isFieldRating';
|
||||
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { type FieldRatingValue } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
|
||||
import { type FieldRatingValue } from 'twenty-shared/types';
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
|
||||
export const useRatingFieldDisplay = () => {
|
||||
|
||||
+1
-1
@@ -1,7 +1,6 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import {
|
||||
MultiItemBaseInput,
|
||||
type MultiItemBaseInputProps,
|
||||
@@ -14,6 +13,7 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
import { IconCheck, IconPlus } from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
|
||||
+1
-1
@@ -1,9 +1,9 @@
|
||||
import { type FieldRatingValue } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { RatingInput } from '@/ui/field/input/components/RatingInput';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
|
||||
import { FieldInputEventContext } from '@/object-record/record-field/ui/contexts/FieldInputEventContext';
|
||||
import { useContext } from 'react';
|
||||
import { type FieldRatingValue } from 'twenty-shared/types';
|
||||
import { useRatingField } from '../../hooks/useRatingField';
|
||||
|
||||
export const RatingFieldInput = () => {
|
||||
|
||||
+1
-2
@@ -10,8 +10,7 @@ import { RecordFieldComponentInstanceContext } from '@/object-record/record-fiel
|
||||
import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix';
|
||||
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { type FieldRatingValue } from '../../../../types/FieldMetadata';
|
||||
import { FieldMetadataType, type FieldRatingValue } from 'twenty-shared/types';
|
||||
import { useRatingField } from '../../../hooks/useRatingField';
|
||||
import { RatingFieldInput } from '../RatingFieldInput';
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,6 @@ import {
|
||||
type FieldMultiSelectValue,
|
||||
type FieldNumberValue,
|
||||
type FieldPhonesValue,
|
||||
type FieldRatingValue,
|
||||
type FieldRelationFromManyValue,
|
||||
type FieldRelationToOneValue,
|
||||
type FieldSelectValue,
|
||||
@@ -20,6 +19,7 @@ import {
|
||||
type FieldUUidValue,
|
||||
type PhoneRecord,
|
||||
} from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { type FieldRatingValue } from 'twenty-shared/types';
|
||||
|
||||
export type FieldTextDraftValue = string;
|
||||
export type FieldNumberDraftValue = number;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation';
|
||||
import { type RATING_VALUES } from '@/object-record/record-field/ui/meta-types/constants/RatingValues';
|
||||
import { type ZodHelperLiteral } from '@/object-record/record-field/ui/types/ZodHelperLiteral';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import {
|
||||
@@ -251,7 +250,6 @@ export type FieldAddressValue = {
|
||||
addressLat: number | null;
|
||||
addressLng: number | null;
|
||||
};
|
||||
export type FieldRatingValue = (typeof RATING_VALUES)[number] | null;
|
||||
export type FieldSelectValue = string | null;
|
||||
export type FieldMultiSelectValue = string[] | null;
|
||||
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
import { RATING_VALUES } from '@/object-record/record-field/ui/meta-types/constants/RatingValues';
|
||||
|
||||
import { type FieldRatingValue } from '../FieldMetadata';
|
||||
import { RATING_VALUES } from 'twenty-shared/constants';
|
||||
import { type FieldRatingValue } from 'twenty-shared/types';
|
||||
|
||||
export const isFieldRatingValue = (
|
||||
fieldValue: unknown,
|
||||
|
||||
+1
-1
@@ -1,4 +1,3 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode';
|
||||
import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition';
|
||||
import { type FieldInputDraftValue } from '@/object-record/record-field/ui/types/FieldInputDraftValue';
|
||||
@@ -14,6 +13,7 @@ import { isFieldPhones } from '@/object-record/record-field/ui/types/guards/isFi
|
||||
import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation';
|
||||
import { isFieldText } from '@/object-record/record-field/ui/types/guards/isFieldText';
|
||||
import { isFieldUuid } from '@/object-record/record-field/ui/types/guards/isFieldUuid';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
|
||||
type computeDraftValueFromStringParams = {
|
||||
fieldDefinition: Pick<FieldDefinition<FieldMetadata>, 'type'>;
|
||||
|
||||
+1
-1
@@ -1,4 +1,3 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode';
|
||||
import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition';
|
||||
import { type FieldInputDraftValue } from '@/object-record/record-field/ui/types/FieldInputDraftValue';
|
||||
@@ -13,6 +12,7 @@ import { isFieldRawJson } from '@/object-record/record-field/ui/types/guards/isF
|
||||
import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation';
|
||||
import { isFieldText } from '@/object-record/record-field/ui/types/guards/isFieldText';
|
||||
import { isFieldUuid } from '@/object-record/record-field/ui/types/guards/isFieldUuid';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
|
||||
type computeEmptyDraftValueParams = {
|
||||
fieldDefinition: Pick<FieldDefinition<FieldMetadata>, 'type'>;
|
||||
|
||||
+1
-1
@@ -2,9 +2,9 @@ import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { act } from 'react';
|
||||
import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
import { useRemoveRecordFilterGroup } from '../useRemoveRecordFilterGroup';
|
||||
import { useUpsertRecordFilterGroup } from '../useUpsertRecordFilterGroup';
|
||||
|
||||
+1
-1
@@ -4,8 +4,8 @@ import { act } from 'react';
|
||||
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
|
||||
const Wrapper = getJestMetadataAndApolloMocksWrapper({
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { type RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
|
||||
export type RecordFilterGroup = {
|
||||
id: string;
|
||||
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
export enum RecordFilterGroupLogicalOperator {
|
||||
AND = 'AND',
|
||||
OR = 'OR',
|
||||
}
|
||||
+1
-1
@@ -1,9 +1,9 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { getFilterTypeFromFieldType } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const useCreateEmptyRecordFilterFromFieldMetadataItem = () => {
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const useCreateRecordFilterFromObjectFilterDropdownCurrentStates =
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { type RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { type RecordFilterValueDependencies } from 'twenty-shared/types';
|
||||
|
||||
export const useFilterValueDependencies = (): {
|
||||
filterValueDependencies: RecordFilterValueDependencies;
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { type FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type CompositeFieldType } from '@/settings/data-model/types/CompositeFieldType';
|
||||
import { type FilterableFieldType } from 'twenty-shared/types';
|
||||
|
||||
export type CompositeFilterableFieldType = FilterableFieldType &
|
||||
CompositeFieldType;
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
import { type FieldType } from '@/settings/data-model/types/FieldType';
|
||||
import { type PickLiteral } from '~/types/PickLiteral';
|
||||
|
||||
export const FILTERABLE_FIELD_TYPES = [
|
||||
'TEXT',
|
||||
'PHONES',
|
||||
'EMAILS',
|
||||
'DATE_TIME',
|
||||
'DATE',
|
||||
'NUMBER',
|
||||
'CURRENCY',
|
||||
'FULL_NAME',
|
||||
'LINKS',
|
||||
'RELATION',
|
||||
'ADDRESS',
|
||||
'SELECT',
|
||||
'RATING',
|
||||
'MULTI_SELECT',
|
||||
'ACTOR',
|
||||
'ARRAY',
|
||||
'RAW_JSON',
|
||||
'BOOLEAN',
|
||||
'UUID',
|
||||
] as const;
|
||||
|
||||
type FilterableFieldTypeBaseLiteral = (typeof FILTERABLE_FIELD_TYPES)[number];
|
||||
|
||||
export type FilterableFieldType = PickLiteral<
|
||||
FieldType,
|
||||
FilterableFieldTypeBaseLiteral
|
||||
>;
|
||||
|
||||
export type FilterableAndTSVectorFieldType = FilterableFieldType | 'TS_VECTOR';
|
||||
@@ -1,7 +1,9 @@
|
||||
import { type FilterableAndTSVectorFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type FILTER_OPERANDS_MAP } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import { type ViewFilterOperand } from 'twenty-shared/types';
|
||||
import {
|
||||
type FilterableAndTSVectorFieldType,
|
||||
type ViewFilterOperand,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
export type RecordFilter = {
|
||||
id: string;
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
export interface RecordFilterValueDependencies {
|
||||
currentWorkspaceMemberId?: string;
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { combineFilters } from '../combineFilters';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
import { combineFilters } from 'twenty-shared/utils';
|
||||
|
||||
describe('combineFilters', () => {
|
||||
it('should return empty object when all filters are empty', () => {
|
||||
|
||||
+8
-4
@@ -1,10 +1,14 @@
|
||||
import { type FieldCurrencyValue } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { type RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
ViewFilterOperand,
|
||||
type RecordFilterValueDependencies,
|
||||
} from 'twenty-shared/types';
|
||||
import {
|
||||
computeRecordGqlOperationFilter,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types';
|
||||
import { sortByProperty } from '~/utils/array/sortByProperty';
|
||||
import { getAllRecordFilterDescendantsOfRecordFilterGroup } from '../getAllRecordFilterDescendantsOfRecordFilterGroup';
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { type CurrencyFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { isMatchingCurrencyFilter } from '@/object-record/record-filter/utils/isMatchingCurrencyFilter';
|
||||
import { type CurrencyFilter } from 'twenty-shared/types';
|
||||
|
||||
describe('isMatchingCurrencyFilter', () => {
|
||||
describe('amountMicros', () => {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
|
||||
export const combineFilters = (
|
||||
filters: RecordGqlOperationFilter[],
|
||||
): RecordGqlOperationFilter => {
|
||||
const nonEmptyFilters = filters.filter(
|
||||
(filter) => Object.keys(filter).length > 0,
|
||||
);
|
||||
|
||||
if (nonEmptyFilters.length === 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (nonEmptyFilters.length === 1) {
|
||||
return nonEmptyFilters[0];
|
||||
}
|
||||
|
||||
return {
|
||||
and: nonEmptyFilters,
|
||||
};
|
||||
};
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import {
|
||||
type EmailsFilter,
|
||||
type RecordGqlOperationFilter,
|
||||
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
export const computeEmptyGqlOperationFilterForEmails = ({
|
||||
recordFilter,
|
||||
correspondingFieldMetadataItem,
|
||||
}: {
|
||||
recordFilter: RecordFilter;
|
||||
correspondingFieldMetadataItem: Pick<FieldMetadataItem, 'name' | 'type'>;
|
||||
}): RecordGqlOperationFilter => {
|
||||
const subFieldName = recordFilter.subFieldName;
|
||||
const isSubFieldFilter = isNonEmptyString(subFieldName);
|
||||
|
||||
if (isSubFieldFilter) {
|
||||
switch (subFieldName) {
|
||||
case 'primaryEmail': {
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: { eq: '' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: { is: 'NULL' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
case 'additionalEmails': {
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: { is: 'NULL' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: { like: '[]' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
default: {
|
||||
throw new CustomError(
|
||||
`Unknown subfield name ${subFieldName}`,
|
||||
'UNKNOWN_SUBFIELD_NAME',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
and: [
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: { eq: '' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: { is: 'NULL' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: { is: 'NULL' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: { like: '[]' },
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import {
|
||||
type LinksFilter,
|
||||
type RecordGqlOperationFilter,
|
||||
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
export const computeEmptyGqlOperationFilterForLinks = ({
|
||||
recordFilter,
|
||||
correspondingFieldMetadataItem,
|
||||
}: {
|
||||
recordFilter: RecordFilter;
|
||||
correspondingFieldMetadataItem: Pick<FieldMetadataItem, 'name' | 'type'>;
|
||||
}): RecordGqlOperationFilter => {
|
||||
const subFieldName = recordFilter.subFieldName;
|
||||
const isSubFieldFilter = isNonEmptyString(subFieldName);
|
||||
|
||||
if (isSubFieldFilter) {
|
||||
switch (subFieldName) {
|
||||
case 'primaryLinkLabel': {
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkLabel: { eq: '' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkLabel: { is: 'NULL' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
case 'primaryLinkUrl': {
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkUrl: { eq: '' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkUrl: { is: 'NULL' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
case 'secondaryLinks': {
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: { is: 'NULL' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: { like: '[]' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
default: {
|
||||
throw new CustomError(
|
||||
`Unknown subfield name ${subFieldName}`,
|
||||
'UNKNOWN_SUBFIELD_NAME',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
and: [
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkLabel: { eq: '' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkLabel: { is: 'NULL' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkUrl: { eq: '' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkUrl: { is: 'NULL' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: { is: 'NULL' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: { like: '[]' },
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { type FilterableAndTSVectorFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { isEmptinessOperand } from '@/object-record/record-filter/utils/isEmptinessOperand';
|
||||
|
||||
export const checkIfShouldComputeEmptinessFilter = ({
|
||||
recordFilter,
|
||||
correspondingFieldMetadataItem,
|
||||
}: {
|
||||
recordFilter: RecordFilter;
|
||||
correspondingFieldMetadataItem: Pick<FieldMetadataItem, 'type'>;
|
||||
}) => {
|
||||
const isAnEmptinessOperand = isEmptinessOperand(recordFilter.operand);
|
||||
|
||||
const filterTypesThatHaveNoEmptinessOperand: FilterableAndTSVectorFieldType[] =
|
||||
['BOOLEAN', 'TS_VECTOR'];
|
||||
|
||||
const filterType = getFilterTypeFromFieldType(
|
||||
correspondingFieldMetadataItem.type,
|
||||
);
|
||||
|
||||
const filterHasEmptinessOperands =
|
||||
!filterTypesThatHaveNoEmptinessOperand.includes(filterType);
|
||||
|
||||
const shouldComputeEmptinessFilter =
|
||||
filterHasEmptinessOperands && isAnEmptinessOperand;
|
||||
|
||||
return shouldComputeEmptinessFilter;
|
||||
};
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { isEmptinessOperand } from '@/object-record/record-filter/utils/isEmptinessOperand';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const checkIfShouldSkipFiltering = ({
|
||||
recordFilter,
|
||||
}: {
|
||||
recordFilter: RecordFilter;
|
||||
}) => {
|
||||
const isAnEmptinessOperand = isEmptinessOperand(recordFilter.operand);
|
||||
|
||||
const isDateOperandWithoutValue = [
|
||||
RecordFilterOperand.IsInPast,
|
||||
RecordFilterOperand.IsInFuture,
|
||||
RecordFilterOperand.IsToday,
|
||||
].includes(recordFilter.operand);
|
||||
|
||||
const isFilterValueEmpty =
|
||||
!isDefined(recordFilter.value) || recordFilter.value === '';
|
||||
|
||||
const shouldSkipFiltering =
|
||||
!isAnEmptinessOperand && !isDateOperandWithoutValue && isFilterValueEmpty;
|
||||
|
||||
return shouldSkipFiltering;
|
||||
};
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import {
|
||||
type EmailsFilter,
|
||||
type RecordGqlOperationFilter,
|
||||
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
export const computeGqlOperationFilterForEmails = ({
|
||||
recordFilter,
|
||||
correspondingFieldMetadataItem,
|
||||
subFieldName,
|
||||
}: {
|
||||
recordFilter: RecordFilter;
|
||||
correspondingFieldMetadataItem: Pick<FieldMetadataItem, 'name' | 'type'>;
|
||||
subFieldName: CompositeFieldSubFieldName | null | undefined;
|
||||
}): RecordGqlOperationFilter => {
|
||||
const isSubFieldFilter = isNonEmptyString(subFieldName);
|
||||
|
||||
if (isSubFieldFilter) {
|
||||
switch (subFieldName) {
|
||||
case 'primaryEmail': {
|
||||
switch (recordFilter.operand) {
|
||||
case RecordFilterOperand.Contains:
|
||||
return {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
};
|
||||
case RecordFilterOperand.DoesNotContain:
|
||||
return {
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${recordFilter.operand} for ${correspondingFieldMetadataItem.type} filter`,
|
||||
);
|
||||
}
|
||||
}
|
||||
case 'additionalEmails': {
|
||||
switch (recordFilter.operand) {
|
||||
case RecordFilterOperand.Contains:
|
||||
return {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
};
|
||||
case RecordFilterOperand.DoesNotContain:
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: {
|
||||
is: 'NULL',
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
default:
|
||||
throw new CustomError(
|
||||
`Unknown operand ${recordFilter.operand} for ${correspondingFieldMetadataItem.type} filter`,
|
||||
'UNKNOWN_OPERAND_FOR_FILTER',
|
||||
);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
throw new CustomError(
|
||||
`Unknown subfield name ${subFieldName}`,
|
||||
'UNKNOWN_SUBFIELD_NAME',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (recordFilter.operand) {
|
||||
case RecordFilterOperand.Contains:
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
case RecordFilterOperand.DoesNotContain:
|
||||
return {
|
||||
and: [
|
||||
{
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryEmail: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
additionalEmails: {
|
||||
is: 'NULL',
|
||||
},
|
||||
} satisfies EmailsFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${recordFilter.operand} for ${correspondingFieldMetadataItem.type} filter`,
|
||||
);
|
||||
}
|
||||
};
|
||||
-170
@@ -1,170 +0,0 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type LinksFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
export const computeGqlOperationFilterForLinks = ({
|
||||
recordFilter,
|
||||
correspondingFieldMetadataItem,
|
||||
subFieldName,
|
||||
}: {
|
||||
recordFilter: RecordFilter;
|
||||
correspondingFieldMetadataItem: Pick<FieldMetadataItem, 'name' | 'type'>;
|
||||
subFieldName: CompositeFieldSubFieldName | null | undefined;
|
||||
}) => {
|
||||
const isSubFieldFilter = isNonEmptyString(subFieldName);
|
||||
|
||||
if (isSubFieldFilter) {
|
||||
switch (subFieldName) {
|
||||
case 'primaryLinkLabel':
|
||||
case 'primaryLinkUrl': {
|
||||
switch (recordFilter.operand) {
|
||||
case RecordFilterOperand.Contains:
|
||||
return {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
[subFieldName]: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
};
|
||||
case RecordFilterOperand.DoesNotContain:
|
||||
return {
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
[subFieldName]: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${recordFilter.operand} for ${correspondingFieldMetadataItem.type} filter`,
|
||||
);
|
||||
}
|
||||
}
|
||||
case 'secondaryLinks': {
|
||||
switch (recordFilter.operand) {
|
||||
case RecordFilterOperand.Contains:
|
||||
return {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
};
|
||||
case RecordFilterOperand.DoesNotContain:
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: {
|
||||
is: 'NULL',
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${recordFilter.operand} for ${correspondingFieldMetadataItem.type} filter`,
|
||||
);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
throw new CustomError(
|
||||
`Unknown subfield name ${subFieldName}`,
|
||||
'UNKNOWN_SUBFIELD_NAME',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (recordFilter.operand) {
|
||||
case RecordFilterOperand.Contains:
|
||||
return {
|
||||
or: [
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkUrl: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkLabel: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
case RecordFilterOperand.DoesNotContain:
|
||||
return {
|
||||
and: [
|
||||
{
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkLabel: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
primaryLinkUrl: {
|
||||
ilike: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
not: {
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: {
|
||||
like: `%${recordFilter.value}%`,
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
[correspondingFieldMetadataItem.name]: {
|
||||
secondaryLinks: {
|
||||
is: 'NULL',
|
||||
},
|
||||
} satisfies LinksFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${recordFilter.operand} for ${correspondingFieldMetadataItem.type} filter`,
|
||||
);
|
||||
}
|
||||
};
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type Field } from '~/generated/graphql';
|
||||
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { type RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||
import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const turnRecordFilterGroupsIntoGqlOperationFilter = (
|
||||
filterValueDependencies: RecordFilterValueDependencies,
|
||||
filters: RecordFilter[],
|
||||
fields: Pick<Field, 'id' | 'name' | 'type'>[],
|
||||
recordFilterGroups: RecordFilterGroup[],
|
||||
currentRecordFilterGroupId?: string,
|
||||
): RecordGqlOperationFilter | undefined => {
|
||||
const currentRecordFilterGroup = recordFilterGroups.find(
|
||||
(recordFilterGroup) => recordFilterGroup.id === currentRecordFilterGroupId,
|
||||
);
|
||||
|
||||
if (!isDefined(currentRecordFilterGroup)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordFiltersInGroup = filters.filter(
|
||||
(filter) => filter.recordFilterGroupId === currentRecordFilterGroupId,
|
||||
);
|
||||
|
||||
const groupRecordGqlOperationFilters = recordFiltersInGroup
|
||||
.map((recordFilter) =>
|
||||
turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: recordFilter,
|
||||
fieldMetadataItems: fields,
|
||||
}),
|
||||
)
|
||||
.filter(isDefined);
|
||||
|
||||
const subGroupRecordGqlOperationFilters = recordFilterGroups
|
||||
.filter(
|
||||
(recordFilterGroup) =>
|
||||
recordFilterGroup.parentRecordFilterGroupId ===
|
||||
currentRecordFilterGroupId,
|
||||
)
|
||||
.map((subRecordFilterGroup) =>
|
||||
turnRecordFilterGroupsIntoGqlOperationFilter(
|
||||
filterValueDependencies,
|
||||
filters,
|
||||
fields,
|
||||
recordFilterGroups,
|
||||
subRecordFilterGroup.id,
|
||||
),
|
||||
)
|
||||
.filter(isDefined);
|
||||
|
||||
if (
|
||||
currentRecordFilterGroup.logicalOperator ===
|
||||
RecordFilterGroupLogicalOperator.AND
|
||||
) {
|
||||
return {
|
||||
and: [
|
||||
...groupRecordGqlOperationFilters,
|
||||
...subGroupRecordGqlOperationFilters,
|
||||
],
|
||||
};
|
||||
} else if (
|
||||
currentRecordFilterGroup.logicalOperator ===
|
||||
RecordFilterGroupLogicalOperator.OR
|
||||
) {
|
||||
return {
|
||||
or: [
|
||||
...groupRecordGqlOperationFilters,
|
||||
...subGroupRecordGqlOperationFilters,
|
||||
],
|
||||
};
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unknown logical operator ${currentRecordFilterGroup.logicalOperator}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
-1207
File diff suppressed because it is too large
Load Diff
-66
@@ -1,66 +0,0 @@
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type Field } from '~/generated/graphql';
|
||||
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { type RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||
|
||||
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||
import { turnRecordFilterGroupsIntoGqlOperationFilter } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterGroupIntoGqlOperationFilter';
|
||||
import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const computeRecordGqlOperationFilter = ({
|
||||
fields,
|
||||
filterValueDependencies,
|
||||
recordFilters,
|
||||
recordFilterGroups,
|
||||
}: {
|
||||
filterValueDependencies: RecordFilterValueDependencies;
|
||||
recordFilters: RecordFilter[];
|
||||
fields: Pick<Field, 'id' | 'name' | 'type'>[];
|
||||
recordFilterGroups: RecordFilterGroup[];
|
||||
}): RecordGqlOperationFilter => {
|
||||
const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] =
|
||||
recordFilters
|
||||
.filter((filter) => !isDefined(filter.recordFilterGroupId))
|
||||
.map((regularFilter) =>
|
||||
turnRecordFilterIntoRecordGqlOperationFilter({
|
||||
filterValueDependencies,
|
||||
recordFilter: regularFilter,
|
||||
fieldMetadataItems: fields,
|
||||
}),
|
||||
)
|
||||
.filter(isDefined);
|
||||
|
||||
const outermostFilterGroupId = recordFilterGroups.find(
|
||||
(recordFilterGroup) => !recordFilterGroup.parentRecordFilterGroupId,
|
||||
)?.id;
|
||||
|
||||
const advancedRecordGqlOperationFilter =
|
||||
turnRecordFilterGroupsIntoGqlOperationFilter(
|
||||
filterValueDependencies,
|
||||
recordFilters,
|
||||
fields,
|
||||
recordFilterGroups,
|
||||
outermostFilterGroupId,
|
||||
);
|
||||
|
||||
const recordGqlOperationFilters = [
|
||||
...regularRecordGqlOperationFilter,
|
||||
advancedRecordGqlOperationFilter,
|
||||
].filter(isDefined);
|
||||
|
||||
if (recordGqlOperationFilters.length === 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (recordGqlOperationFilters.length === 1) {
|
||||
return recordGqlOperationFilters[0];
|
||||
}
|
||||
|
||||
const recordGqlOperationFilter = {
|
||||
and: recordGqlOperationFilters,
|
||||
};
|
||||
|
||||
return recordGqlOperationFilter;
|
||||
};
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type FilterableAndTSVectorFieldType } from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type FilterableAndTSVectorFieldType } from 'twenty-shared/types';
|
||||
|
||||
export const getDateFilterDisplayValue = (
|
||||
value: Date,
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { assertUnreachable } from 'twenty-shared/utils';
|
||||
export const getDefaultSubFieldNameForCompositeFilterableFieldType = (
|
||||
fieldType: FieldType,
|
||||
): CompositeFieldSubFieldName | undefined => {
|
||||
if (!isCompositeFilterableFieldType(fieldType as any)) {
|
||||
if (!isCompositeFilterableFieldType(fieldType)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
-407
@@ -1,407 +0,0 @@
|
||||
import { CustomError } from '@/error-handler/CustomError';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import {
|
||||
type ActorFilter,
|
||||
type AddressFilter,
|
||||
type ArrayFilter,
|
||||
type CurrencyFilter,
|
||||
type DateFilter,
|
||||
type FloatFilter,
|
||||
type MultiSelectFilter,
|
||||
type PhonesFilter,
|
||||
type RatingFilter,
|
||||
type RawJsonFilter,
|
||||
type RecordGqlOperationFilter,
|
||||
type RelationFilter,
|
||||
type SelectFilter,
|
||||
type StringFilter,
|
||||
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { computeEmptyGqlOperationFilterForEmails } from '@/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForEmails';
|
||||
import { computeEmptyGqlOperationFilterForLinks } from '@/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForLinks';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { type Field } from '~/generated/graphql';
|
||||
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
|
||||
|
||||
type GetEmptyRecordGqlOperationFilterParams = {
|
||||
operand: ViewFilterOperand;
|
||||
correspondingField: Pick<Field, 'id' | 'name' | 'type'>;
|
||||
recordFilter: RecordFilter;
|
||||
};
|
||||
|
||||
export const getEmptyRecordGqlOperationFilter = ({
|
||||
operand,
|
||||
correspondingField,
|
||||
recordFilter,
|
||||
}: GetEmptyRecordGqlOperationFilterParams) => {
|
||||
let emptyRecordFilter: RecordGqlOperationFilter = {};
|
||||
|
||||
const compositeFieldName = recordFilter.subFieldName;
|
||||
|
||||
const isSubFieldFilter = isNonEmptyString(compositeFieldName);
|
||||
|
||||
const filterType = getFilterTypeFromFieldType(correspondingField.type);
|
||||
|
||||
switch (filterType) {
|
||||
case 'TEXT':
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{ [correspondingField.name]: { ilike: '' } as StringFilter },
|
||||
{ [correspondingField.name]: { is: 'NULL' } as StringFilter },
|
||||
],
|
||||
};
|
||||
break;
|
||||
case 'PHONES': {
|
||||
if (!isSubFieldFilter) {
|
||||
emptyRecordFilter = {
|
||||
and: [
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
primaryPhoneNumber: { is: 'NULL' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
primaryPhoneNumber: { ilike: '' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
primaryPhoneCallingCode: { is: 'NULL' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
primaryPhoneCallingCode: { ilike: '' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
additionalPhones: { is: 'NULL' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
additionalPhones: { like: '[]' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
switch (compositeFieldName) {
|
||||
case 'primaryPhoneNumber':
|
||||
case 'primaryPhoneCallingCode': {
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
[compositeFieldName]: { is: 'NULL' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
[compositeFieldName]: { ilike: '' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 'additionalPhones': {
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
additionalPhones: { is: 'NULL' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
additionalPhones: { like: '[]' },
|
||||
} as PhonesFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(
|
||||
`Unsupported composite field name ${compositeFieldName} for filter type ${filterType}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'CURRENCY':
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
amountMicros: { is: 'NULL' },
|
||||
} as CurrencyFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
case 'FULL_NAME': {
|
||||
if (!isSubFieldFilter) {
|
||||
const fullNameFilters = generateILikeFiltersForCompositeFields(
|
||||
'',
|
||||
correspondingField.name,
|
||||
['firstName', 'lastName'],
|
||||
true,
|
||||
);
|
||||
|
||||
emptyRecordFilter = {
|
||||
and: fullNameFilters,
|
||||
};
|
||||
} else {
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
[compositeFieldName]: { ilike: '' },
|
||||
},
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
[compositeFieldName]: { is: 'NULL' },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'LINKS': {
|
||||
emptyRecordFilter = computeEmptyGqlOperationFilterForLinks({
|
||||
correspondingFieldMetadataItem: correspondingField,
|
||||
recordFilter,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'ADDRESS':
|
||||
if (!isSubFieldFilter) {
|
||||
emptyRecordFilter = {
|
||||
and: [
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressStreet1: { ilike: '' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressStreet1: { is: 'NULL' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressStreet2: { ilike: '' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressStreet2: { is: 'NULL' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressCity: { ilike: '' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressCity: { is: 'NULL' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressState: { ilike: '' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressState: { is: 'NULL' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressCountry: { ilike: '' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressCountry: { is: 'NULL' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressPostcode: { ilike: '' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
addressPostcode: { is: 'NULL' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
[compositeFieldName]: { ilike: '' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
[compositeFieldName]: { is: 'NULL' },
|
||||
} as AddressFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'NUMBER':
|
||||
emptyRecordFilter = {
|
||||
[correspondingField.name]: { is: 'NULL' } as FloatFilter,
|
||||
};
|
||||
break;
|
||||
case 'RATING':
|
||||
emptyRecordFilter = {
|
||||
[correspondingField.name]: { is: 'NULL' } as RatingFilter,
|
||||
};
|
||||
break;
|
||||
case 'DATE':
|
||||
case 'DATE_TIME':
|
||||
emptyRecordFilter = {
|
||||
[correspondingField.name]: { is: 'NULL' } as DateFilter,
|
||||
};
|
||||
break;
|
||||
case 'SELECT':
|
||||
emptyRecordFilter = {
|
||||
[correspondingField.name]: { is: 'NULL' } as SelectFilter,
|
||||
};
|
||||
break;
|
||||
case 'MULTI_SELECT':
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: { is: 'NULL' } as MultiSelectFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
isEmptyArray: true,
|
||||
} as MultiSelectFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
case 'RELATION':
|
||||
emptyRecordFilter = {
|
||||
[correspondingField.name + 'Id']: { is: 'NULL' } as RelationFilter,
|
||||
};
|
||||
break;
|
||||
case 'ACTOR':
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
name: { ilike: '' },
|
||||
} as ActorFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
name: { is: 'NULL' },
|
||||
} as ActorFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
case 'ARRAY':
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: { is: 'NULL' } as ArrayFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: { isEmptyArray: true } as ArrayFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
case 'RAW_JSON':
|
||||
emptyRecordFilter = {
|
||||
or: [
|
||||
{
|
||||
[correspondingField.name]: { is: 'NULL' } as RawJsonFilter,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
case 'EMAILS':
|
||||
emptyRecordFilter = computeEmptyGqlOperationFilterForEmails({
|
||||
correspondingFieldMetadataItem: correspondingField,
|
||||
recordFilter,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new CustomError(
|
||||
`Unsupported empty filter type ${filterType}`,
|
||||
'UNSUPPORTED_EMPTY_FILTER_TYPE',
|
||||
);
|
||||
}
|
||||
|
||||
switch (operand) {
|
||||
case ViewFilterOperand.IsEmpty:
|
||||
return emptyRecordFilter;
|
||||
case ViewFilterOperand.IsNotEmpty:
|
||||
return {
|
||||
not: emptyRecordFilter,
|
||||
};
|
||||
default:
|
||||
throw new CustomError(
|
||||
`Unknown operand ${operand} for ${filterType} filter`,
|
||||
'UNKNOWN_OPERAND_FOR_FILTER',
|
||||
);
|
||||
}
|
||||
};
|
||||
+4
-7
@@ -1,15 +1,12 @@
|
||||
import { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName';
|
||||
import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField';
|
||||
import {
|
||||
type FilterableAndTSVectorFieldType,
|
||||
type FilterableFieldType,
|
||||
} from '@/object-record/record-filter/types/FilterableFieldType';
|
||||
import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
ViewFilterOperand as RecordFilterOperand,
|
||||
type FilterableAndTSVectorFieldType,
|
||||
type FilterableFieldType,
|
||||
} from 'twenty-shared/types';
|
||||
import { assertUnreachable } from 'twenty-shared/utils';
|
||||
import { assertUnreachable, isExpectedSubFieldName } from 'twenty-shared/utils';
|
||||
|
||||
export type GetRecordFilterOperandsParams = {
|
||||
filterType: FilterableAndTSVectorFieldType;
|
||||
@@ -168,7 +165,7 @@ export const getRecordFilterOperands = ({
|
||||
FieldMetadataType.CURRENCY,
|
||||
'currencyCode',
|
||||
subFieldName,
|
||||
)
|
||||
) === true
|
||||
) {
|
||||
return COMPOSITE_FIELD_FILTER_OPERANDS_MAP.CURRENCY.currencyCode;
|
||||
} else {
|
||||
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
|
||||
export const isEmptinessOperand = (operand: RecordFilterOperand): boolean => {
|
||||
return [RecordFilterOperand.IsEmpty, RecordFilterOperand.IsNotEmpty].includes(
|
||||
operand,
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type ArrayFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type ArrayFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingArrayFilter = ({
|
||||
arrayFilter,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type BooleanFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type BooleanFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingBooleanFilter = ({
|
||||
booleanFilter,
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { type CurrencyFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { type CurrencyFilter } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const isMatchingCurrencyCodeFilter = (
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
import { parseISO, isEqual, isAfter, isBefore } from 'date-fns';
|
||||
|
||||
import { type DateFilter } from '@/object-record//graphql/types/RecordGqlOperationFilter';
|
||||
import { isAfter, isBefore, isEqual, parseISO } from 'date-fns';
|
||||
import { type DateFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingDateFilter = ({
|
||||
dateFilter,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type FloatFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type FloatFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingFloatFilter = ({
|
||||
floatFilter,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type MultiSelectFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type MultiSelectFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingMultiSelectFilter = ({
|
||||
multiSelectFilter,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RatingFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RatingFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingRatingFilter = ({
|
||||
ratingFilter,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RawJsonFilter } from '../../graphql/types/RecordGqlOperationFilter';
|
||||
import { type RawJsonFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingRawJsonFilter = ({
|
||||
rawJsonFilter,
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { type RichTextV2Filter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import escapeRegExp from 'lodash.escaperegexp';
|
||||
import { type RichTextV2Filter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingRichTextV2Filter = ({
|
||||
richTextV2Filter,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type SelectFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type SelectFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingSelectFilter = ({
|
||||
selectFilter,
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { type StringFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import escapeRegExp from 'lodash.escaperegexp';
|
||||
import { type StringFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingStringFilter = ({
|
||||
stringFilter,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type TSVectorFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type TSVectorFilter } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingTSVectorFilter = ({
|
||||
tsVectorFilter,
|
||||
|
||||
+1
-4
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
type UUIDFilter,
|
||||
type UUIDFilterValue,
|
||||
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type UUIDFilter, type UUIDFilterValue } from 'twenty-shared/types';
|
||||
|
||||
export const isMatchingUUIDFilter = ({
|
||||
uuidFilter,
|
||||
|
||||
+14
-14
@@ -1,6 +1,19 @@
|
||||
import { isObject } from '@sniptt/guards';
|
||||
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { isMatchingArrayFilter } from '@/object-record/record-filter/utils/isMatchingArrayFilter';
|
||||
import { isMatchingBooleanFilter } from '@/object-record/record-filter/utils/isMatchingBooleanFilter';
|
||||
import { isMatchingCurrencyFilter } from '@/object-record/record-filter/utils/isMatchingCurrencyFilter';
|
||||
import { isMatchingDateFilter } from '@/object-record/record-filter/utils/isMatchingDateFilter';
|
||||
import { isMatchingFloatFilter } from '@/object-record/record-filter/utils/isMatchingFloatFilter';
|
||||
import { isMatchingMultiSelectFilter } from '@/object-record/record-filter/utils/isMatchingMultiSelectFilter';
|
||||
import { isMatchingRatingFilter } from '@/object-record/record-filter/utils/isMatchingRatingFilter';
|
||||
import { isMatchingRawJsonFilter } from '@/object-record/record-filter/utils/isMatchingRawJsonFilter';
|
||||
import { isMatchingRichTextV2Filter } from '@/object-record/record-filter/utils/isMatchingRichTextV2Filter';
|
||||
import { isMatchingSelectFilter } from '@/object-record/record-filter/utils/isMatchingSelectFilter';
|
||||
import { isMatchingStringFilter } from '@/object-record/record-filter/utils/isMatchingStringFilter';
|
||||
import { isMatchingTSVectorFilter } from '@/object-record/record-filter/utils/isMatchingTSVectorFilter';
|
||||
import { isMatchingUUIDFilter } from '@/object-record/record-filter/utils/isMatchingUUIDFilter';
|
||||
import {
|
||||
type ActorFilter,
|
||||
type AddressFilter,
|
||||
@@ -26,20 +39,7 @@ import {
|
||||
type StringFilter,
|
||||
type TSVectorFilter,
|
||||
type UUIDFilter,
|
||||
} from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { isMatchingArrayFilter } from '@/object-record/record-filter/utils/isMatchingArrayFilter';
|
||||
import { isMatchingBooleanFilter } from '@/object-record/record-filter/utils/isMatchingBooleanFilter';
|
||||
import { isMatchingCurrencyFilter } from '@/object-record/record-filter/utils/isMatchingCurrencyFilter';
|
||||
import { isMatchingDateFilter } from '@/object-record/record-filter/utils/isMatchingDateFilter';
|
||||
import { isMatchingFloatFilter } from '@/object-record/record-filter/utils/isMatchingFloatFilter';
|
||||
import { isMatchingMultiSelectFilter } from '@/object-record/record-filter/utils/isMatchingMultiSelectFilter';
|
||||
import { isMatchingRatingFilter } from '@/object-record/record-filter/utils/isMatchingRatingFilter';
|
||||
import { isMatchingRawJsonFilter } from '@/object-record/record-filter/utils/isMatchingRawJsonFilter';
|
||||
import { isMatchingRichTextV2Filter } from '@/object-record/record-filter/utils/isMatchingRichTextV2Filter';
|
||||
import { isMatchingSelectFilter } from '@/object-record/record-filter/utils/isMatchingSelectFilter';
|
||||
import { isMatchingStringFilter } from '@/object-record/record-filter/utils/isMatchingStringFilter';
|
||||
import { isMatchingTSVectorFilter } from '@/object-record/record-filter/utils/isMatchingTSVectorFilter';
|
||||
import { isMatchingUUIDFilter } from '@/object-record/record-filter/utils/isMatchingUUIDFilter';
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { isEmptyObject } from '~/utils/isEmptyObject';
|
||||
|
||||
+5
-3
@@ -1,13 +1,15 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter';
|
||||
import { createAnyFieldRecordFilterBaseProperties } from '@/object-record/record-filter/utils/createAnyFieldRecordFilterBaseProperties';
|
||||
import { filterSelectOptionsOfFieldMetadataItem } from '@/object-record/record-filter/utils/filterSelectOptionsOfFieldMetadataItem';
|
||||
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
import {
|
||||
isDefined,
|
||||
turnRecordFilterIntoRecordGqlOperationFilter,
|
||||
} from 'twenty-shared/utils';
|
||||
import { z } from 'zod';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { isNonEmptyArray } from '~/utils/isNonEmptyArray';
|
||||
|
||||
+5
-4
@@ -4,14 +4,15 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record-
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { combineFilters } from '@/object-record/record-filter/utils/combineFilters';
|
||||
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter';
|
||||
import { turnAnyFieldFilterIntoRecordGqlFilter } from '@/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter';
|
||||
import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition';
|
||||
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
|
||||
import {
|
||||
combineFilters,
|
||||
computeRecordGqlOperationFilter,
|
||||
} from 'twenty-shared/utils';
|
||||
export const useFindManyRecordIndexTableParams = (
|
||||
objectNameSingular: string,
|
||||
) => {
|
||||
@@ -41,9 +42,9 @@ export const useFindManyRecordIndexTableParams = (
|
||||
|
||||
const currentFilters = computeRecordGqlOperationFilter({
|
||||
fields: objectMetadataItem?.fields ?? [],
|
||||
filterValueDependencies,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
recordFilters: currentRecordFilters,
|
||||
filterValueDependencies,
|
||||
});
|
||||
|
||||
const anyFieldFilterValue = useRecoilComponentValue(
|
||||
|
||||
+1
-2
@@ -3,15 +3,14 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type UseHandleToggleTrashColumnFilterProps = {
|
||||
objectNameSingular: string;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user