From da3c3d2b9df158cb6f2ceccbaf9d7a3d68805252 Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:58:55 +0200 Subject: [PATCH] [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 --- .../DestroyMultipleRecordsAction.tsx | 2 +- .../RestoreMultipleRecordsAction.tsx | 2 +- .../modules/activities/hooks/useActivities.ts | 2 +- .../computeContextStoreFilters.test.ts | 6 +- .../utils/computeContextStoreFilters.ts | 8 +- .../components/AppErrorBoundary.tsx | 3 +- .../components/PromiseRejectionEffect.tsx | 3 +- .../utils/validateAndExtractFolderId.ts | 2 +- .../hooks/useGetObjectMetadataItemById.ts | 3 +- .../hooks/useObjectMetadataItemById.ts | 3 +- ...atFieldMetadataItemsAsFilterDefinitions.ts | 50 ---- .../utils/getFieldMetadataItemByIdOrThrow.ts | 3 +- .../AdvancedFilterAddFilterRuleSelect.tsx | 5 +- .../AdvancedFilterDropdownFilterInput.tsx | 2 +- .../AdvancedFilterFieldSelectMenu.tsx | 2 +- .../AdvancedFilterLogicalOperatorDropdown.tsx | 2 +- .../AdvancedFilterLogicalOperatorOptions.ts | 2 +- ...SelectFieldUsedInAdvancedFilterDropdown.ts | 3 +- .../utils/shouldShowFilterTextInput.ts | 6 +- .../types/RecordGqlOperationVariables.ts | 2 +- .../hooks/useAggregateRecords.ts | 2 +- .../hooks/useAttachRelatedRecordFromRecord.ts | 3 +- .../object-record/hooks/useFindManyRecords.ts | 2 +- ...useUpdateMultipleRecordsFromManyObjects.ts | 3 +- .../ObjectFilterDropdownContentWrapper.tsx | 3 +- .../ObjectFilterDropdownDateInput.tsx | 3 +- .../ObjectFilterDropdownFilterInput.tsx | 3 +- ...lterDropdownInnerSelectOperandDropdown.tsx | 3 +- .../ObjectFilterDropdownRatingInput.tsx | 7 +- .../ObjectFilterDropdownRecordSelect.tsx | 8 +- .../getOperandsForFilterType.test.ts | 2 +- .../utils/getInitialFilterValue.ts | 2 +- .../utils/getSubMenuOptions.ts | 2 +- .../utils/isCompositeFilterableFieldType.ts | 2 +- .../utils/isExpectedSubFieldName.ts | 19 -- .../utils/getAggregateOperationLabel.ts | 2 +- .../utils/getAggregateOperationShortLabel.ts | 2 +- .../useRecordCalendarQueryDateRangeFilter.tsx | 6 +- .../RecordDetailRelationSection.tsx | 7 +- .../ui/meta-types/hooks/useRatingField.ts | 2 +- .../meta-types/hooks/useRatingFieldDisplay.ts | 2 +- .../input/components/MultiItemFieldInput.tsx | 2 +- .../input/components/RatingFieldInput.tsx | 2 +- .../__stories__/RatingFieldInput.stories.tsx | 3 +- .../ui/types/FieldInputDraftValue.ts | 2 +- .../record-field/ui/types/FieldMetadata.ts | 2 - .../ui/types/guards/isFieldRatingValue.ts | 5 +- .../ui/utils/computeDraftValueFromString.ts | 2 +- .../ui/utils/computeEmptyDraftValue.ts | 2 +- .../useRemoveRecordFilterGroup.test.tsx | 2 +- .../useUpsertRecordFilterGroup.test.tsx | 2 +- .../types/RecordFilterGroup.ts | 2 +- ...eEmptyRecordFilterFromFieldMetadataItem.ts | 2 +- ...erFromObjectFilterDropdownCurrentStates.ts | 3 +- .../hooks/useFilterValueDependencies.ts | 2 +- .../types/CompositeFilterableFieldType.ts | 2 +- .../record-filter/types/RecordFilter.ts | 6 +- .../utils/__tests__/combineFilters.test.ts | 4 +- ...omputeViewRecordGqlOperationFilter.test.ts | 12 +- ...lterDescendantsOfRecordFilterGroup.test.ts | 2 +- .../isMatchingCurrencyFilter.test.ts | 2 +- .../__tests__/isRecordMatchingFilter.test.ts | 2 +- .../checkIfShouldComputeEmptinessFilter.ts | 30 --- .../utils/getDateFilterDisplayValue.ts | 2 +- ...ieldNameForCompositeFilterableFieldType.ts | 2 +- .../utils/getRecordFilterOperands.ts | 11 +- .../utils/isMatchingArrayFilter.ts | 2 +- .../utils/isMatchingBooleanFilter.ts | 2 +- .../utils/isMatchingCurrencyFilter.ts | 2 +- .../utils/isMatchingDateFilter.ts | 5 +- .../utils/isMatchingFloatFilter.ts | 2 +- .../utils/isMatchingMultiSelectFilter.ts | 2 +- .../utils/isMatchingRatingFilter.ts | 2 +- .../utils/isMatchingRawJsonFilter.ts | 2 +- .../utils/isMatchingRichTextV2Filter.ts | 2 +- .../utils/isMatchingSelectFilter.ts | 2 +- .../utils/isMatchingStringFilter.ts | 2 +- .../utils/isMatchingTSVectorFilter.ts | 2 +- .../utils/isMatchingUUIDFilter.ts | 5 +- .../utils/isRecordMatchingFilter.ts | 28 +- .../turnAnyFieldFilterIntoRecordGqlFilter.ts | 8 +- .../useFindManyRecordIndexTableParams.ts | 9 +- .../hooks/useHandleToggleTrashColumnFilter.ts | 3 +- .../hooks/useLoadRecordIndexBoardColumn.ts | 8 +- .../hooks/useAggregateRecordsForHeader.ts | 6 +- ...egateRecordsForRecordTableColumnFooter.tsx | 7 +- .../utils/buildRecordInputFromFilter.spec.ts | 6 +- ...etSpreadSheetFieldValidationDefinitions.ts | 2 +- .../utils/makeAndFilterVariables.ts | 2 +- .../utils/makeOrFilterVariables.ts | 2 +- .../accounts/hooks/useTriggerApiOAuth.ts | 2 +- .../ConfigVariableDatabaseInput.tsx | 2 +- .../utils/useSourceContent.ts | 2 +- .../SettingsCompositeFieldTypeConfigs.ts | 107 ++++++-- .../SettingsNonCompositeFieldTypeConfigs.ts | 2 +- .../utils/editDatabaseConnection.ts | 2 +- .../components/PlaygroundSetupForm.tsx | 2 +- .../ui/field/input/components/RatingInput.tsx | 4 +- .../components/RelativeDatePickerHeader.tsx | 5 +- ...wBarFilterDropdownAdvancedFilterButton.tsx | 2 +- ...ViewFiltersToCurrentRecordFilters.test.tsx | 3 +- ...ViewFiltersToCurrentRecordFilters.test.tsx | 3 +- ...ataItemFromViewBarFilterDropdown.test.tsx} | 2 +- .../internal/useGetRecordIndexTotalCount.ts | 2 +- .../hooks/internal/useViewFromQueryParams.ts | 6 +- ...eComputeRecordRelationFilterLabelValue.tsx | 8 +- .../views/hooks/useGetViewGroupsFilters.ts | 3 +- ...ldMetadataItemFromViewBarFilterDropdown.ts | 3 +- .../hooks/useVectorSearchFilterActions.ts | 3 +- ...orToViewFilterGroupLogicalOperator.test.ts | 2 +- ...RecordFilterGroupToViewFilterGroup.test.ts | 2 +- ...ToRecordFilterGroupLogicalOperator.test.ts | 2 +- ...ewFilterGroupsToRecordFilterGroups.test.ts | 2 +- .../convertCoreViewFilterToViewFilter.ts | 11 +- .../getQueryVariablesFromFiltersAndSorts.ts | 4 +- .../views/utils/getRecordFilterLabelValue.ts | 3 +- ...peratorToViewFilterGroupLogicalOperator.ts | 2 +- ...ratorToRecordFilterGroupLogicalOperator.ts | 2 +- .../views/utils/mapViewFiltersToFilters.ts | 3 +- .../types/RelationFilterValue.ts | 2 +- .../WorkflowFindRecordsAddFilterButton.tsx | 2 +- .../components/WorkflowFindRecordsFilters.tsx | 6 +- .../utils/shouldDisplayFormField.ts | 2 +- .../settings/SettingsWorkspaceMembers.tsx | 7 +- .../testing/decorators/getFieldDecorator.tsx | 3 +- packages/twenty-front/src/utils/date-utils.ts | 3 +- .../graphql-query-runner.module.ts | 2 + ...graphql-query-group-by-resolver.service.ts | 102 ++++++++ .../utils/convert-view-filter-operands.ts | 44 ++++ .../workspace-entity-manager.spec.ts | 2 +- .../core/utils/seed-feature-flags.util.ts | 2 +- .../src/utils/custom-exception.ts | 4 +- .../group-by-resolvers.integration-spec.ts | 239 ++++++++++++++++++ .../utils/group-by-operation-factory.util.ts | 35 +++ .../utils/find-many-object-metadata.util.ts | 3 +- .../CompositeFieldTypeSubFieldsNames.ts | 49 ++++ .../src}/constants/RatingValues.ts | 0 packages/twenty-shared/src/constants/index.ts | 2 + .../types/CompositeFieldSubFieldNameType.ts | 6 + .../src/types/FieldRatingValue.ts | 3 + .../src}/types/FilterableFieldType.ts | 7 +- .../src/types/PartialFieldMetadataItem.ts | 8 + .../types/RecordFilterGroupLogicalOperator.ts | 0 .../types/RecordFilterValueDependencies.ts | 0 .../src}/types/RecordGqlOperationFilter.ts | 0 packages/twenty-shared/src/types/index.ts | 42 +++ .../src/utils/errors}/CustomError.ts | 0 .../twenty-shared/src/utils/errors/index.ts | 1 + .../checkIfShouldComputeEmptinessFilter.ts | 29 +++ .../filter}/checkIfShouldSkipFiltering.ts | 15 +- .../computeGqlOperationFilterForEmails.ts | 14 +- .../computeGqlOperationFilterForLinks.ts | 18 +- ...computeEmptyGqlOperationFilterForEmails.ts | 12 +- .../computeEmptyGqlOperationFilterForLinks.ts | 12 +- .../computeRecordGqlOperationFilter.ts | 44 ++-- .../twenty-shared/src/utils/filter/index.ts | 22 ++ .../src/utils/filter}/isEmptinessOperand.ts | 2 +- ...RecordFilterGroupIntoGqlOperationFilter.ts | 46 ++-- .../turnRecordFilterIntoGqlOperationFilter.ts | 87 ++++--- .../arrayOfStringsOrVariablesSchema.test.ts | 2 +- .../arrayOfUuidOrVariableSchema.test.ts | 2 +- ...rateILikeFiltersForCompositeFields.test.ts | 2 +- .../src/utils/filter}/utils/combineFilters.ts | 2 +- .../utils/convertViewFilterValueToString.ts | 5 + .../filter/utils/fieldRatingConvertors.ts | 19 ++ .../generateILikeFiltersForCompositeFields.ts | 2 +- .../utils/getEmptyRecordGqlOperationFilter.ts | 24 +- .../utils/getFilterTypeFromFieldType.ts | 49 ++++ .../filter/utils/isExpectedSubFieldName.ts | 24 ++ .../utils/resolveDateViewFilterValue.ts | 8 +- .../arrayOfStringsOrVariablesSchema.ts | 2 +- .../arrayOfUuidsOrVariablesSchema.ts | 2 +- .../jsonRelationFilterValueSchema.ts | 0 packages/twenty-shared/src/utils/index.ts | 42 +++ 174 files changed, 1192 insertions(+), 483 deletions(-) delete mode 100644 packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isExpectedSubFieldName.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldComputeEmptinessFilter.ts rename packages/twenty-front/src/modules/views/hooks/__tests__/{useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.test.tsx => useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx} (99%) create mode 100644 packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/convert-view-filter-operands.ts create mode 100644 packages/twenty-server/test/integration/graphql/suites/group-by-resolvers.integration-spec.ts create mode 100644 packages/twenty-server/test/integration/graphql/utils/group-by-operation-factory.util.ts create mode 100644 packages/twenty-shared/src/constants/CompositeFieldTypeSubFieldsNames.ts rename packages/{twenty-front/src/modules/object-record/record-field/ui/meta-types => twenty-shared/src}/constants/RatingValues.ts (100%) create mode 100644 packages/twenty-shared/src/types/CompositeFieldSubFieldNameType.ts create mode 100644 packages/twenty-shared/src/types/FieldRatingValue.ts rename packages/{twenty-front/src/modules/object-record/record-filter => twenty-shared/src}/types/FilterableFieldType.ts (79%) create mode 100644 packages/twenty-shared/src/types/PartialFieldMetadataItem.ts rename packages/{twenty-front/src/modules/object-record/record-filter-group => twenty-shared/src}/types/RecordFilterGroupLogicalOperator.ts (100%) rename packages/{twenty-front/src/modules/object-record/record-filter => twenty-shared/src}/types/RecordFilterValueDependencies.ts (100%) rename packages/{twenty-front/src/modules/object-record/graphql => twenty-shared/src}/types/RecordGqlOperationFilter.ts (100%) rename packages/{twenty-front/src/modules/error-handler => twenty-shared/src/utils/errors}/CustomError.ts (100%) create mode 100644 packages/twenty-shared/src/utils/errors/index.ts create mode 100644 packages/twenty-shared/src/utils/filter/checkIfShouldComputeEmptinessFilter.ts rename packages/{twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter => twenty-shared/src/utils/filter}/checkIfShouldSkipFiltering.ts (60%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils => twenty-shared/src/utils/filter}/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts (88%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils => twenty-shared/src/utils/filter}/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts (87%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field => twenty-shared/src/utils/filter}/computeEmptyGqlOperationFilterForEmails.ts (84%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field => twenty-shared/src/utils/filter}/computeEmptyGqlOperationFilterForLinks.ts (88%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils => twenty-shared/src/utils/filter}/computeRecordGqlOperationFilter.ts (53%) create mode 100644 packages/twenty-shared/src/utils/filter/index.ts rename packages/{twenty-front/src/modules/object-record/record-filter/utils => twenty-shared/src/utils/filter}/isEmptinessOperand.ts (65%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter => twenty-shared/src/utils/filter}/turnRecordFilterGroupIntoGqlOperationFilter.ts (60%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter => twenty-shared/src/utils/filter}/turnRecordFilterIntoGqlOperationFilter.ts (92%) rename packages/{twenty-front/src/modules/views/view-filter-value/validation-schemas => twenty-shared/src/utils/filter/utils}/__tests__/arrayOfStringsOrVariablesSchema.test.ts (95%) rename packages/{twenty-front/src/modules/views/view-filter-value/validation-schemas => twenty-shared/src/utils/filter/utils}/__tests__/arrayOfUuidOrVariableSchema.test.ts (98%) rename packages/{twenty-front/src/utils/array => twenty-shared/src/utils/filter/utils}/__tests__/generateILikeFiltersForCompositeFields.test.ts (90%) rename packages/{twenty-front/src/modules/object-record/record-filter => twenty-shared/src/utils/filter}/utils/combineFilters.ts (78%) create mode 100644 packages/twenty-shared/src/utils/filter/utils/convertViewFilterValueToString.ts create mode 100644 packages/twenty-shared/src/utils/filter/utils/fieldRatingConvertors.ts rename packages/{twenty-front/src/utils/array => twenty-shared/src/utils/filter/utils}/generateILikeFiltersForCompositeFields.ts (90%) rename packages/{twenty-front/src/modules/object-record/record-filter => twenty-shared/src/utils/filter}/utils/getEmptyRecordGqlOperationFilter.ts (90%) create mode 100644 packages/twenty-shared/src/utils/filter/utils/getFilterTypeFromFieldType.ts create mode 100644 packages/twenty-shared/src/utils/filter/utils/isExpectedSubFieldName.ts rename packages/{twenty-front/src/modules/views/view-filter-value => twenty-shared/src/utils/filter}/utils/resolveDateViewFilterValue.ts (95%) rename packages/{twenty-front/src/modules/views/view-filter-value => twenty-shared/src/utils/filter/utils}/validation-schemas/arrayOfStringsOrVariablesSchema.ts (88%) rename packages/{twenty-front/src/modules/views/view-filter-value => twenty-shared/src/utils/filter/utils}/validation-schemas/arrayOfUuidsOrVariablesSchema.ts (91%) rename packages/{twenty-front/src/modules/views/view-filter-value => twenty-shared/src/utils/filter/utils}/validation-schemas/jsonRelationFilterValueSchema.ts (100%) diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx index a2443656cd..b306bc46e5 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/DestroyMultipleRecordsAction.tsx @@ -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 } = diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx index 223da282be..4066448259 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction.tsx @@ -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 } = diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts index 449ae2cbee..a895e37cc6 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts @@ -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 = ({ diff --git a/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts index b62850167f..6271a5516e 100644 --- a/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts +++ b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts @@ -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', () => { diff --git a/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts b/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts index e0d7f32b96..9b1ef96aa4 100644 --- a/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts +++ b/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts @@ -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; diff --git a/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx b/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx index 19da8f8396..c1c4991ecc 100644 --- a/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx +++ b/packages/twenty-front/src/modules/error-handler/components/AppErrorBoundary.tsx @@ -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; diff --git a/packages/twenty-front/src/modules/error-handler/components/PromiseRejectionEffect.tsx b/packages/twenty-front/src/modules/error-handler/components/PromiseRejectionEffect.tsx index db17fe8079..ef0eca92e3 100644 --- a/packages/twenty-front/src/modules/error-handler/components/PromiseRejectionEffect.tsx +++ b/packages/twenty-front/src/modules/error-handler/components/PromiseRejectionEffect.tsx @@ -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, diff --git a/packages/twenty-front/src/modules/favorites/utils/validateAndExtractFolderId.ts b/packages/twenty-front/src/modules/favorites/utils/validateAndExtractFolderId.ts index f2f2bbb697..62e774b413 100644 --- a/packages/twenty-front/src/modules/favorites/utils/validateAndExtractFolderId.ts +++ b/packages/twenty-front/src/modules/favorites/utils/validateAndExtractFolderId.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectMetadataItemById.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectMetadataItemById.ts index 6ae6c99c7d..df1ce4d25c 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectMetadataItemById.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectMetadataItemById.ts @@ -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); diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts index 6802ceb039..88c5cb6977 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemById.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts index ea8f7ef121..06c2d67351 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts @@ -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'; - } -}; diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getFieldMetadataItemByIdOrThrow.ts b/packages/twenty-front/src/modules/object-metadata/utils/getFieldMetadataItemByIdOrThrow.ts index e35226ea12..ea546f060b 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getFieldMetadataItemByIdOrThrow.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getFieldMetadataItemByIdOrThrow.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect.tsx index 257348a39d..5caaa9fe14 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect.tsx @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx index aef3e01d27..e2605500dc 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput.tsx @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx index b0a6aa6f96..725f7eac50 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorDropdown.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorDropdown.tsx index 1e8e79e673..0915e96e44 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorDropdown.tsx @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/constants/AdvancedFilterLogicalOperatorOptions.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/constants/AdvancedFilterLogicalOperatorOptions.ts index 8d44eb01d3..c38fa00606 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/constants/AdvancedFilterLogicalOperatorOptions.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/constants/AdvancedFilterLogicalOperatorOptions.ts @@ -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 = [ { diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts index 6581c1e507..49e586802e 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/utils/shouldShowFilterTextInput.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/utils/shouldShowFilterTextInput.ts index 72d9020f77..0a4f1f0372 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/utils/shouldShowFilterTextInput.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/utils/shouldShowFilterTextInput.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts index b625a8ed78..c10ecc52d7 100644 --- a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useAggregateRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useAggregateRecords.ts index ce162d259a..f34530163c 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useAggregateRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useAggregateRecords.ts @@ -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 = { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useAttachRelatedRecordFromRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useAttachRelatedRecordFromRecord.ts index efbfe58437..043ee620f6 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useAttachRelatedRecordFromRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useAttachRelatedRecordFromRecord.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts index abd26e9d4d..8967982e9c 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts @@ -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 = ObjectMetadataItemIdentifier & RecordGqlOperationVariables & { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useUpdateMultipleRecordsFromManyObjects.ts b/packages/twenty-front/src/modules/object-record/hooks/useUpdateMultipleRecordsFromManyObjects.ts index f3065b069f..0ba80bc018 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useUpdateMultipleRecordsFromManyObjects.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useUpdateMultipleRecordsFromManyObjects.ts @@ -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 = { diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx index fff046822f..d410fbb69a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx index 2ce6f8dd0a..a19e2a4ce0 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx @@ -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 = () => { diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx index 944fa61005..de09d92e73 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx index 3dce6df833..57cbdaf711 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx @@ -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 = diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx index cffcdc911a..0e1ac9ed5c 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput.tsx @@ -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` diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx index 1c300af128..550795c895 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx @@ -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({ diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts index 22472e01a5..21c705c314 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/__tests__/getOperandsForFilterType.test.ts @@ -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 = [ diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getInitialFilterValue.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getInitialFilterValue.ts index 046a6aae78..6b86d72acb 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getInitialFilterValue.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getInitialFilterValue.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSubMenuOptions.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSubMenuOptions.ts index 5b880be0eb..ea268d59b9 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSubMenuOptions.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getSubMenuOptions.ts @@ -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) { diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isCompositeFilterableFieldType.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isCompositeFilterableFieldType.ts index 06aa52721c..9067820b22 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isCompositeFilterableFieldType.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isCompositeFilterableFieldType.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isExpectedSubFieldName.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isExpectedSubFieldName.ts deleted file mode 100644 index 8074ec708a..0000000000 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/isExpectedSubFieldName.ts +++ /dev/null @@ -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 - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts index 2c70f380fb..e7e96809e3 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts index 98bc33957a..96776fefce 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx index a365fd78cb..6e9e063163 100644 --- a/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx +++ b/packages/twenty-front/src/modules/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter.tsx @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx index 7f9811a33f..7d9e7e1681 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationSection.tsx @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts index 51b1e56d80..dfe6560915 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingField.ts @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingFieldDisplay.ts index 1e40956347..c1dd7e25ae 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useRatingFieldDisplay.ts @@ -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 = () => { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldInput.tsx index 9f908128a9..cd0b98e03f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/MultiItemFieldInput.tsx @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RatingFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RatingFieldInput.tsx index 3c9714bb31..2e2cf50efd 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RatingFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RatingFieldInput.tsx @@ -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 = () => { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx index b576edb00d..7c4600da3a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/__stories__/RatingFieldInput.stories.tsx @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldInputDraftValue.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldInputDraftValue.ts index 899a5a546d..ea986e6432 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldInputDraftValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldInputDraftValue.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts index 29347525dc..9103fde6c2 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldRatingValue.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldRatingValue.ts index c6f15fec02..8c12a1bdab 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldRatingValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldRatingValue.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeDraftValueFromString.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeDraftValueFromString.ts index 8aa3708aca..774b0d2cec 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeDraftValueFromString.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeDraftValueFromString.ts @@ -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, 'type'>; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeEmptyDraftValue.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeEmptyDraftValue.ts index cd31119576..398fb31bf1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeEmptyDraftValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/utils/computeEmptyDraftValue.ts @@ -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, 'type'>; diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx index 1e400b09e7..18f1d71ca0 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useRemoveRecordFilterGroup.test.tsx @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx index 28c62c7146..5758fe0a37 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/hooks/__tests__/useUpsertRecordFilterGroup.test.tsx @@ -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({ diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/types/RecordFilterGroup.ts b/packages/twenty-front/src/modules/object-record/record-filter-group/types/RecordFilterGroup.ts index 58a21895cf..ab41b97ea1 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter-group/types/RecordFilterGroup.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter-group/types/RecordFilterGroup.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem.ts b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem.ts index 45bec1f193..20cb16ae05 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem.ts @@ -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 = () => { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts index 419dedab2c..a7fb151a73 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates.ts @@ -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 = diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useFilterValueDependencies.ts b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useFilterValueDependencies.ts index 7093ccde30..dc8d5fe7d1 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useFilterValueDependencies.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useFilterValueDependencies.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/types/CompositeFilterableFieldType.ts b/packages/twenty-front/src/modules/object-record/record-filter/types/CompositeFilterableFieldType.ts index 77a26bcd94..688644e041 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/types/CompositeFilterableFieldType.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/types/CompositeFilterableFieldType.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/types/RecordFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/types/RecordFilter.ts index 675b91e409..c70a76cf0c 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/types/RecordFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/types/RecordFilter.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/combineFilters.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/combineFilters.test.ts index 5564913ac2..e4f96717fe 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/combineFilters.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/combineFilters.test.ts @@ -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', () => { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts index edb540cdc8..e172f5c6e2 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/computeViewRecordGqlOperationFilter.test.ts @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/getAllRecordFilterDescendantsOfRecordFilterGroup.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/getAllRecordFilterDescendantsOfRecordFilterGroup.test.ts index ef3a58d5c7..15c6eaa759 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/getAllRecordFilterDescendantsOfRecordFilterGroup.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/getAllRecordFilterDescendantsOfRecordFilterGroup.test.ts @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingCurrencyFilter.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingCurrencyFilter.test.ts index 1448ded0f4..84533ddda6 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingCurrencyFilter.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isMatchingCurrencyFilter.test.ts @@ -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', () => { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isRecordMatchingFilter.test.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isRecordMatchingFilter.test.ts index 4712288a59..75ba860370 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isRecordMatchingFilter.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/isRecordMatchingFilter.test.ts @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldComputeEmptinessFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldComputeEmptinessFilter.ts deleted file mode 100644 index e71aca60be..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldComputeEmptinessFilter.ts +++ /dev/null @@ -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; -}) => { - 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; -}; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getDateFilterDisplayValue.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getDateFilterDisplayValue.ts index 7fd9aaa46d..1ac1f3f0a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getDateFilterDisplayValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/getDateFilterDisplayValue.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts index 68097bbee3..443dcae776 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType.ts @@ -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; } diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts index 08f5d5bbb6..d39e9e4ad2 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts @@ -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 { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingArrayFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingArrayFilter.ts index e4fa12676c..05126e7371 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingArrayFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingArrayFilter.ts @@ -1,4 +1,4 @@ -import { type ArrayFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type ArrayFilter } from 'twenty-shared/types'; export const isMatchingArrayFilter = ({ arrayFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts index 0acde71e2a..98cf6b9eb8 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts @@ -1,4 +1,4 @@ -import { type BooleanFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type BooleanFilter } from 'twenty-shared/types'; export const isMatchingBooleanFilter = ({ booleanFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts index 44aaa409ee..2ac8b32b1d 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts @@ -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 = ( diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts index 55e7ccd0eb..0693a66fbe 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts index 58c8083029..c3cca636f6 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts @@ -1,4 +1,4 @@ -import { type FloatFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type FloatFilter } from 'twenty-shared/types'; export const isMatchingFloatFilter = ({ floatFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingMultiSelectFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingMultiSelectFilter.ts index fe3f2f24f1..ce8b3760ad 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingMultiSelectFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingMultiSelectFilter.ts @@ -1,4 +1,4 @@ -import { type MultiSelectFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type MultiSelectFilter } from 'twenty-shared/types'; export const isMatchingMultiSelectFilter = ({ multiSelectFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRatingFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRatingFilter.ts index 759ef8c8b1..9bf64140b2 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRatingFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRatingFilter.ts @@ -1,4 +1,4 @@ -import { type RatingFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type RatingFilter } from 'twenty-shared/types'; export const isMatchingRatingFilter = ({ ratingFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRawJsonFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRawJsonFilter.ts index 635ea0346a..ea04317bae 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRawJsonFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRawJsonFilter.ts @@ -1,4 +1,4 @@ -import { type RawJsonFilter } from '../../graphql/types/RecordGqlOperationFilter'; +import { type RawJsonFilter } from 'twenty-shared/types'; export const isMatchingRawJsonFilter = ({ rawJsonFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRichTextV2Filter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRichTextV2Filter.ts index ef21c926fa..89f3bb9c12 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRichTextV2Filter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingRichTextV2Filter.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingSelectFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingSelectFilter.ts index 31f4b37ed4..ac52eb6ab6 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingSelectFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingSelectFilter.ts @@ -1,4 +1,4 @@ -import { type SelectFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type SelectFilter } from 'twenty-shared/types'; export const isMatchingSelectFilter = ({ selectFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts index 55a406c591..431732765e 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingTSVectorFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingTSVectorFilter.ts index 0c987e61b9..89c678ccd1 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingTSVectorFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingTSVectorFilter.ts @@ -1,4 +1,4 @@ -import { type TSVectorFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type TSVectorFilter } from 'twenty-shared/types'; export const isMatchingTSVectorFilter = ({ tsVectorFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts index 87fd891df6..af34e0bef8 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts @@ -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, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts index 2f0280db84..3993aa2d35 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter.ts index e1d221725e..bbefbce0b3 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter.ts @@ -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'; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts index e4b454ef8f..956e71b502 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts @@ -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( diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts index 5b015f71ba..ed3a4852a4 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts @@ -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; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts index 8e3e4a82a0..dbaead8be5 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts @@ -8,7 +8,6 @@ import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/use import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields'; @@ -16,11 +15,14 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState'; -import { combineFilters } from '@/object-record/record-filter/utils/combineFilters'; import { turnAnyFieldFilterIntoRecordGqlFilter } from '@/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { isDefined } from 'twenty-shared/utils'; +import { + combineFilters, + computeRecordGqlOperationFilter, + isDefined, +} from 'twenty-shared/utils'; type UseLoadRecordIndexBoardProps = { objectNameSingular: string; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useAggregateRecordsForHeader.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useAggregateRecordsForHeader.ts index ad0b2dc29b..09543c2316 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useAggregateRecordsForHeader.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useAggregateRecordsForHeader.ts @@ -6,14 +6,16 @@ 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 { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter'; import { turnAnyFieldFilterIntoRecordGqlFilter } from '@/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter'; import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { UserContext } from '@/users/contexts/UserContext'; import { useContext } from 'react'; import { useRecoilValue } from 'recoil'; -import { isDefined } from 'twenty-shared/utils'; +import { + computeRecordGqlOperationFilter, + isDefined, +} from 'twenty-shared/utils'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; type UseAggregateRecordsProps = { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx index 4d8d0c0c25..a2aa0c4104 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx @@ -4,7 +4,6 @@ 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 { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter'; import { turnAnyFieldFilterIntoRecordGqlFilter } from '@/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter'; import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; @@ -17,7 +16,11 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho import { UserContext } from '@/users/contexts/UserContext'; import { useContext } from 'react'; import { useRecoilValue } from 'recoil'; -import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils'; +import { + computeRecordGqlOperationFilter, + isDefined, + isFieldMetadataDateKind, +} from 'twenty-shared/utils'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; export const useAggregateRecordsForRecordTableColumnFooter = ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/utils/buildRecordInputFromFilter.spec.ts b/packages/twenty-front/src/modules/object-record/record-table/utils/buildRecordInputFromFilter.spec.ts index 00cf376b5f..19d8c36c00 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/utils/buildRecordInputFromFilter.spec.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/utils/buildRecordInputFromFilter.spec.ts @@ -1,8 +1,10 @@ import { type FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem'; -import { type FilterableFieldType } from '@/object-record/record-filter/types/FilterableFieldType'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { type ColorScheme } from '@/workspace-member/types/WorkspaceMember'; -import { ViewFilterOperand } from 'twenty-shared/types'; +import { + type FilterableFieldType, + ViewFilterOperand, +} from 'twenty-shared/types'; import { RelationType } from '~/generated-metadata/graphql'; import { buildValueFromFilter } from './buildRecordInputFromFilter'; diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts index a6595126d8..e36d71cb6e 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts @@ -1,10 +1,10 @@ -import { RATING_VALUES } from '@/object-record/record-field/ui/meta-types/constants/RatingValues'; import { isFieldRatingValue } from '@/object-record/record-field/ui/types/guards/isFieldRatingValue'; import { emailSchema } from '@/object-record/record-field/ui/validation-schemas/emailSchema'; import { type SpreadsheetImportFieldValidationDefinition } from '@/spreadsheet-import/types'; import { t } from '@lingui/core/macro'; import { isDate, isString } from '@sniptt/guards'; import { parsePhoneNumberWithError } from 'libphonenumber-js'; +import { RATING_VALUES } from 'twenty-shared/constants'; import { absoluteUrlSchema, getCountryCodesForCallingCode, diff --git a/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts b/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts index 6f653c5d18..0e93544ccc 100644 --- a/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts +++ b/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts @@ -1,4 +1,4 @@ -import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type RecordGqlOperationFilter } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const makeAndFilterVariables = ( diff --git a/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts b/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts index bedf68f754..33a830e7ab 100644 --- a/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts +++ b/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts @@ -1,4 +1,4 @@ -import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type RecordGqlOperationFilter } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const makeOrFilterVariables = ( diff --git a/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerApiOAuth.ts b/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerApiOAuth.ts index bd505adfa0..e3dced2239 100644 --- a/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerApiOAuth.ts +++ b/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerApiOAuth.ts @@ -2,7 +2,7 @@ import { useCallback } from 'react'; import { type AppPath, ConnectedAccountProvider } from 'twenty-shared/types'; import { useRedirect } from '@/domain-manager/hooks/useRedirect'; -import { CustomError } from '@/error-handler/CustomError'; +import { CustomError } from 'twenty-shared/utils'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { type CalendarChannelVisibility, diff --git a/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableDatabaseInput.tsx b/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableDatabaseInput.tsx index 0a8af783c9..9b5cac6a59 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableDatabaseInput.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableDatabaseInput.tsx @@ -1,4 +1,3 @@ -import { CustomError } from '@/error-handler/CustomError'; import { Select } from '@/ui/input/components/Select'; import { SelectControl } from '@/ui/input/components/SelectControl'; import { TextArea } from '@/ui/input/components/TextArea'; @@ -7,6 +6,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { type ConfigVariableValue } from 'twenty-shared/types'; +import { CustomError } from 'twenty-shared/utils'; import { MenuItemMultiSelect } from 'twenty-ui/navigation'; import { ConfigVariableType } from '~/generated/graphql'; import { type ConfigVariableOptions } from '../types/ConfigVariableOptions'; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/config-variables/utils/useSourceContent.ts b/packages/twenty-front/src/modules/settings/admin-panel/config-variables/utils/useSourceContent.ts index f64457255c..8a015a5f4a 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/config-variables/utils/useSourceContent.ts +++ b/packages/twenty-front/src/modules/settings/admin-panel/config-variables/utils/useSourceContent.ts @@ -1,6 +1,6 @@ -import { CustomError } from '@/error-handler/CustomError'; import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; +import { CustomError } from 'twenty-shared/utils'; import { ConfigSource } from '~/generated/graphql'; diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsCompositeFieldTypeConfigs.ts b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsCompositeFieldTypeConfigs.ts index 438469fdf3..72d890d373 100644 --- a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsCompositeFieldTypeConfigs.ts +++ b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsCompositeFieldTypeConfigs.ts @@ -12,6 +12,7 @@ import { import { COMPOSITE_FIELD_SUB_FIELD_LABELS } from '@/settings/data-model/constants/CompositeFieldSubFieldLabel'; import { type SettingsFieldTypeConfig } from '@/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs'; import { type CompositeFieldType } from '@/settings/data-model/types/CompositeFieldType'; +import { COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES } from 'twenty-shared/constants'; import { ConnectedAccountProvider } from 'twenty-shared/types'; import { IllustrationIconCurrency, @@ -51,7 +52,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { Icon: IllustrationIconCurrency, subFields: [ { - subFieldName: 'amountMicros', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.CURRENCY] + .amountMicros, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.CURRENCY] .amountMicros, @@ -60,7 +63,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'currencyCode', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.CURRENCY] + .currencyCode, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.CURRENCY] .currencyCode, @@ -90,7 +95,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { Icon: IllustrationIconMail, subFields: [ { - subFieldName: 'primaryEmail', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.EMAILS] + .primaryEmail, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.EMAILS] .primaryEmail, @@ -99,7 +106,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: true, }, { - subFieldName: 'additionalEmails', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.EMAILS] + .additionalEmails, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.EMAILS] .additionalEmails, @@ -133,7 +142,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { Icon: IllustrationIconLink, subFields: [ { - subFieldName: 'primaryLinkUrl', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.LINKS] + .primaryLinkUrl, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.LINKS] .primaryLinkUrl, @@ -142,7 +153,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: true, }, { - subFieldName: 'primaryLinkLabel', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.LINKS] + .primaryLinkLabel, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.LINKS] .primaryLinkLabel, @@ -151,7 +164,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'secondaryLinks', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.LINKS] + .secondaryLinks, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.LINKS] .secondaryLinks, @@ -184,7 +199,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { Icon: IllustrationIconPhone, subFields: [ { - subFieldName: 'primaryPhoneCallingCode', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.PHONES] + .primaryPhoneCallingCode, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.PHONES] .primaryPhoneCallingCode, @@ -193,7 +210,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'primaryPhoneCountryCode', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.PHONES] + .primaryPhoneCountryCode, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.PHONES] .primaryPhoneCountryCode, @@ -202,7 +221,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'primaryPhoneNumber', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.PHONES] + .primaryPhoneNumber, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.PHONES] .primaryPhoneNumber, @@ -211,7 +232,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: true, }, { - subFieldName: 'additionalPhones', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.PHONES] + .additionalPhones, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.PHONES] .additionalPhones, @@ -252,7 +275,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { Icon: IllustrationIconUser, subFields: [ { - subFieldName: 'firstName', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.FULL_NAME] + .firstName, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.FULL_NAME] .firstName, @@ -261,7 +286,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'lastName', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.FULL_NAME] + .lastName, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.FULL_NAME] .lastName, @@ -282,7 +309,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { Icon: IllustrationIconMap, subFields: [ { - subFieldName: 'addressStreet1', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressStreet1, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressStreet1, @@ -291,7 +320,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'addressStreet2', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressStreet2, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressStreet2, @@ -300,7 +331,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'addressCity', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressCity, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressCity, @@ -309,7 +342,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'addressState', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressState, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressState, @@ -318,7 +353,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'addressCountry', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressCountry, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressCountry, @@ -327,7 +364,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'addressPostcode', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressPostcode, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressPostcode, @@ -336,7 +375,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'addressLat', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressLat, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressLat, @@ -345,7 +386,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'addressLng', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ADDRESS] + .addressLng, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ADDRESS] .addressLng, @@ -394,7 +437,8 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { category: 'Basic', subFields: [ { - subFieldName: 'source', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ACTOR].source, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ACTOR].source, isImportable: true, @@ -402,7 +446,8 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'name', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ACTOR].name, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ACTOR].name, isImportable: true, @@ -410,7 +455,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'workspaceMemberId', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ACTOR] + .workspaceMemberId, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ACTOR] .workspaceMemberId, @@ -419,7 +466,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'context', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.ACTOR] + .context, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.ACTOR].context, isImportable: true, @@ -454,7 +503,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { category: 'Basic', subFields: [ { - subFieldName: 'blocknote', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.RICH_TEXT_V2] + .blocknote, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.RICH_TEXT_V2] .blocknote, @@ -463,7 +514,9 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = { isIncludedInUniqueConstraint: false, }, { - subFieldName: 'markdown', + subFieldName: + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[FieldMetadataType.RICH_TEXT_V2] + .markdown, subFieldLabel: COMPOSITE_FIELD_SUB_FIELD_LABELS[FieldMetadataType.RICH_TEXT_V2] .markdown, diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts index 5eba42bcf6..6e96ae9677 100644 --- a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts +++ b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs.ts @@ -6,7 +6,6 @@ import { type FieldJsonValue, type FieldMultiSelectValue, type FieldNumberValue, - type FieldRatingValue, type FieldRelationValue, type FieldSelectValue, type FieldTextValue, @@ -15,6 +14,7 @@ import { import { DEFAULT_DATE_VALUE } from '@/settings/data-model/constants/DefaultDateValue'; import { type SettingsFieldTypeCategoryType } from '@/settings/data-model/types/SettingsFieldTypeCategoryType'; import { type SettingsNonCompositeFieldType } from '@/settings/data-model/types/SettingsNonCompositeFieldType'; +import { type FieldRatingValue } from 'twenty-shared/types'; import { IllustrationIconArray, IllustrationIconCalendarEvent, diff --git a/packages/twenty-front/src/modules/settings/integrations/database-connection/utils/editDatabaseConnection.ts b/packages/twenty-front/src/modules/settings/integrations/database-connection/utils/editDatabaseConnection.ts index 006c89e4fa..af5e1b67eb 100644 --- a/packages/twenty-front/src/modules/settings/integrations/database-connection/utils/editDatabaseConnection.ts +++ b/packages/twenty-front/src/modules/settings/integrations/database-connection/utils/editDatabaseConnection.ts @@ -3,11 +3,11 @@ import isEmpty from 'lodash.isempty'; import pickBy from 'lodash.pickby'; import { z } from 'zod'; -import { CustomError } from '@/error-handler/CustomError'; import { settingsIntegrationPostgreSQLConnectionFormSchema, settingsIntegrationStripeConnectionFormSchema, } from '@/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionForm'; +import { CustomError } from 'twenty-shared/utils'; import { type RemoteServer } from '~/generated-metadata/graphql'; export const getEditionSchemaForForm = (databaseKey: string) => { diff --git a/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx b/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx index 103f23aaf4..fb4e79ad76 100644 --- a/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx +++ b/packages/twenty-front/src/modules/settings/playground/components/PlaygroundSetupForm.tsx @@ -1,4 +1,3 @@ -import { CustomError } from '@/error-handler/CustomError'; import { SETTINGS_PLAYGROUND_FORM_SCHEMA_SELECT_OPTIONS } from '@/settings/playground/constants/SettingsPlaygroundFormSchemaSelectOptions'; import { playgroundApiKeyState } from '@/settings/playground/states/playgroundApiKeyState'; import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas'; @@ -11,6 +10,7 @@ import { useLingui } from '@lingui/react/macro'; import { Controller, useForm } from 'react-hook-form'; import { useRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; +import { CustomError } from 'twenty-shared/utils'; import { IconApi, IconBrandGraphql } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { z } from 'zod'; diff --git a/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx index 2906d70c79..672d61aa5a 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/RatingInput.tsx @@ -2,8 +2,8 @@ import { styled } from '@linaria/react'; import { useContext, useState } from 'react'; import { useClearField } from '@/object-record/record-field/ui/hooks/useClearField'; -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 { RATING_VALUES } from 'twenty-shared/constants'; +import { type FieldRatingValue } from 'twenty-shared/types'; import { IconTwentyStarFilled } from 'twenty-ui/display'; import { THEME_COMMON, ThemeContext } from 'twenty-ui/theme'; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx index fcc0d7dc42..c54766402f 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx @@ -2,7 +2,6 @@ import { Select } from '@/ui/input/components/Select'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { RELATIVE_DATE_DIRECTION_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions'; import { RELATIVE_DATE_UNITS_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions'; -import { variableDateViewFilterValuePartsSchema } from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; import { type VariableDateViewFilterValueDirection, type VariableDateViewFilterValueUnit, @@ -10,6 +9,7 @@ import { import styled from '@emotion/styled'; import { useEffect, useState } from 'react'; +import { variableDateViewFilterValuePartsSchema } from 'twenty-shared/utils'; const StyledContainer = styled.div<{ noPadding: boolean }>` display: flex; @@ -92,7 +92,8 @@ export const RelativeDatePickerHeader = ( }; if ( - variableDateViewFilterValuePartsSchema.safeParse(valueParts).success + variableDateViewFilterValuePartsSchema.safeParse(valueParts) + .success === true ) { props.onChange?.(valueParts); } diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx index 8cc921c0f8..99bd5ef34d 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownAdvancedFilterButton.tsx @@ -10,7 +10,6 @@ import { VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS } from '@/views/constants/ViewBarF import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow'; -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; @@ -20,6 +19,7 @@ import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { useRecoilValue } from 'recoil'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { Pill } from 'twenty-ui/components'; import { IconFilter } from 'twenty-ui/display'; diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx index 875eb78002..b402584c0a 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyCurrentViewFiltersToCurrentRecordFilters.test.tsx @@ -1,7 +1,6 @@ import { renderHook } from '@testing-library/react'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; @@ -11,7 +10,7 @@ import { type View } from '@/views/types/View'; import { type ViewFilter } from '@/views/types/ViewFilter'; import { act } from 'react'; import { ViewFilterOperand } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { type CoreViewFilter, ViewFilterOperand as CoreViewFilterOperand, diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx index 2e8f2404f5..5f0ca977e1 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useApplyViewFiltersToCurrentRecordFilters.test.tsx @@ -1,12 +1,11 @@ import { act, renderHook } from '@testing-library/react'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { type ViewFilter } from '@/views/types/ViewFilter'; import { ViewFilterOperand } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; import { useApplyViewFiltersToCurrentRecordFilters } from '../useApplyViewFiltersToCurrentRecordFilters'; diff --git a/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.test.tsx b/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx similarity index 99% rename from packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.test.tsx rename to packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx index 82ba633482..e2146f630a 100644 --- a/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.test.tsx +++ b/packages/twenty-front/src/modules/views/hooks/__tests__/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.test.tsx @@ -7,7 +7,6 @@ import { selectedOperandInDropdownComponentState } from '@/object-record/object- import { useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown } from '../useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; @@ -19,6 +18,7 @@ import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentTyp import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; +import { getFilterTypeFromFieldType } from 'twenty-shared/utils'; import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; diff --git a/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts b/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts index ff07b20446..fa925b79a6 100644 --- a/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts +++ b/packages/twenty-front/src/modules/views/hooks/internal/useGetRecordIndexTotalCount.ts @@ -4,11 +4,11 @@ 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 { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter'; import { turnAnyFieldFilterIntoRecordGqlFilter } from '@/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useGetViewGroupsFilters } from '@/views/hooks/useGetViewGroupsFilters'; +import { computeRecordGqlOperationFilter } from 'twenty-shared/utils'; export const useGetRecordIndexTotalCount = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); diff --git a/packages/twenty-front/src/modules/views/hooks/internal/useViewFromQueryParams.ts b/packages/twenty-front/src/modules/views/hooks/internal/useViewFromQueryParams.ts index b9140bbe40..670fa452a9 100644 --- a/packages/twenty-front/src/modules/views/hooks/internal/useViewFromQueryParams.ts +++ b/packages/twenty-front/src/modules/views/hooks/internal/useViewFromQueryParams.ts @@ -15,9 +15,11 @@ import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery'; import { type ViewFilter } from '@/views/types/ViewFilter'; -import { relationFilterValueSchemaObject } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema'; import { ViewFilterOperand } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { + isDefined, + relationFilterValueSchemaObject, +} from 'twenty-shared/utils'; const filterQueryParamsSchema = z.object({ viewId: z.string().optional(), diff --git a/packages/twenty-front/src/modules/views/hooks/useComputeRecordRelationFilterLabelValue.tsx b/packages/twenty-front/src/modules/views/hooks/useComputeRecordRelationFilterLabelValue.tsx index a8a0f90a41..00058f9de0 100644 --- a/packages/twenty-front/src/modules/views/hooks/useComputeRecordRelationFilterLabelValue.tsx +++ b/packages/twenty-front/src/modules/views/hooks/useComputeRecordRelationFilterLabelValue.tsx @@ -5,10 +5,12 @@ import { MAX_RECORDS_TO_DISPLAY } from '@/object-record/object-filter-dropdown/c import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect'; import { getRecordFilterLabelValue } from '@/views/utils/getRecordFilterLabelValue'; -import { arrayOfUuidOrVariableSchema } from '@/views/view-filter-value/validation-schemas/arrayOfUuidsOrVariablesSchema'; -import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema'; import { t } from '@lingui/core/macro'; -import { isDefined } from 'twenty-shared/utils'; +import { + arrayOfUuidOrVariableSchema, + isDefined, + jsonRelationFilterValueSchema, +} from 'twenty-shared/utils'; type ObjectFilterDropdownRecordSelectProps = { recordFilter: RecordFilter; diff --git a/packages/twenty-front/src/modules/views/hooks/useGetViewGroupsFilters.ts b/packages/twenty-front/src/modules/views/hooks/useGetViewGroupsFilters.ts index c7ee12c977..b983e3b414 100644 --- a/packages/twenty-front/src/modules/views/hooks/useGetViewGroupsFilters.ts +++ b/packages/twenty-front/src/modules/views/hooks/useGetViewGroupsFilters.ts @@ -1,8 +1,7 @@ -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { FieldMetadataType, ViewFilterOperand } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; export const useGetViewGroupsFilters = (): RecordFilter[] => { const { currentView } = useGetCurrentViewOnly(); diff --git a/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts b/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts index 4c0efce65a..10acb7dd60 100644 --- a/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts +++ b/packages/twenty-front/src/modules/views/hooks/useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown.ts @@ -1,5 +1,4 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { useUpsertObjectFilterDropdownCurrentFilter } from '@/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter'; import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState'; @@ -15,7 +14,7 @@ import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentTyp import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; import { useRecoilCallback } from 'recoil'; -import { isDefined } from 'twenty-shared/utils'; +import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown = diff --git a/packages/twenty-front/src/modules/views/hooks/useVectorSearchFilterActions.ts b/packages/twenty-front/src/modules/views/hooks/useVectorSearchFilterActions.ts index f87942f8bf..6207223057 100644 --- a/packages/twenty-front/src/modules/views/hooks/useVectorSearchFilterActions.ts +++ b/packages/twenty-front/src/modules/views/hooks/useVectorSearchFilterActions.ts @@ -1,10 +1,9 @@ -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty'; import { useVectorSearchFieldInRecordIndexContextOrThrow } from '@/views/hooks/useVectorSearchFieldInRecordIndexContextOrThrow'; import { ViewFilterOperand } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { useVectorSearchFilterState } from './useVectorSearchFilterState'; diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.test.ts index d4c3a171f6..fa884b3976 100644 --- a/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.test.ts +++ b/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.test.ts @@ -1,6 +1,6 @@ -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator'; import { mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator } from '@/views/utils/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; describe('mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator', () => { it('should map correctly for AND', () => { diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupToViewFilterGroup.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupToViewFilterGroup.test.ts index 2fd9d6247a..b467266542 100644 --- a/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupToViewFilterGroup.test.ts +++ b/packages/twenty-front/src/modules/views/utils/__tests__/mapRecordFilterGroupToViewFilterGroup.test.ts @@ -1,5 +1,4 @@ import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; import { type View } from '@/views/types/View'; import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup'; @@ -7,6 +6,7 @@ import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLog import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { ViewType } from '@/views/types/ViewType'; import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFilterGroupToViewFilterGroup'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.test.ts index f965d1516f..d4fd95b2ba 100644 --- a/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.test.ts +++ b/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.test.ts @@ -1,6 +1,6 @@ -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator'; import { mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator } from '@/views/utils/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; describe('mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator', () => { it('should map correctly for AND', () => { diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupsToRecordFilterGroups.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupsToRecordFilterGroups.test.ts index b4ca54c011..0c0a4dc5a0 100644 --- a/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupsToRecordFilterGroups.test.ts +++ b/packages/twenty-front/src/modules/views/utils/__tests__/mapViewFilterGroupsToRecordFilterGroups.test.ts @@ -1,8 +1,8 @@ import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup'; import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator'; import { mapViewFilterGroupsToRecordFilterGroups } from '@/views/utils/mapViewFilterGroupsToRecordFilterGroups'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; describe('mapViewFilterGroupsToRecordFilterGroups', () => { it('should map empty array to empty array', () => { diff --git a/packages/twenty-front/src/modules/views/utils/convertCoreViewFilterToViewFilter.ts b/packages/twenty-front/src/modules/views/utils/convertCoreViewFilterToViewFilter.ts index b11ca64946..256942178e 100644 --- a/packages/twenty-front/src/modules/views/utils/convertCoreViewFilterToViewFilter.ts +++ b/packages/twenty-front/src/modules/views/utils/convertCoreViewFilterToViewFilter.ts @@ -1,5 +1,6 @@ import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName'; import { type ViewFilter } from '@/views/types/ViewFilter'; +import { convertViewFilterValueToString } from 'twenty-shared/utils'; import { type CoreViewFilter } from '~/generated/graphql'; import { convertViewFilterOperandFromCore } from '../utils/convertViewFilterOperandFromCore'; @@ -20,14 +21,8 @@ export const convertCoreViewFilterToViewFilter = ( id: coreViewFilter.id, fieldMetadataId: coreViewFilter.fieldMetadataId, operand: convertViewFilterOperandFromCore(coreViewFilter.operand), - value: - typeof coreViewFilter.value === 'string' - ? coreViewFilter.value - : JSON.stringify(coreViewFilter.value ?? ''), - displayValue: - typeof coreViewFilter.value === 'string' - ? coreViewFilter.value - : JSON.stringify(coreViewFilter.value ?? ''), + value: convertViewFilterValueToString(coreViewFilter.value), + displayValue: convertViewFilterValueToString(coreViewFilter.value), viewFilterGroupId: coreViewFilter.viewFilterGroupId, positionInViewFilterGroup: coreViewFilter.positionInViewFilterGroup, subFieldName: coreViewFilter.subFieldName as CompositeFieldSubFieldName, diff --git a/packages/twenty-front/src/modules/views/utils/getQueryVariablesFromFiltersAndSorts.ts b/packages/twenty-front/src/modules/views/utils/getQueryVariablesFromFiltersAndSorts.ts index 2bff7d8dd1..17a1bda720 100644 --- a/packages/twenty-front/src/modules/views/utils/getQueryVariablesFromFiltersAndSorts.ts +++ b/packages/twenty-front/src/modules/views/utils/getQueryVariablesFromFiltersAndSorts.ts @@ -2,9 +2,9 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; 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 { type RecordSort } from '@/object-record/record-sort/types/RecordSort'; +import { type RecordFilterValueDependencies } from 'twenty-shared/types'; +import { computeRecordGqlOperationFilter } from 'twenty-shared/utils'; export const getQueryVariablesFromFiltersAndSorts = ({ recordFilterGroups, diff --git a/packages/twenty-front/src/modules/views/utils/getRecordFilterLabelValue.ts b/packages/twenty-front/src/modules/views/utils/getRecordFilterLabelValue.ts index f524700ad5..0df5dfcf7d 100644 --- a/packages/twenty-front/src/modules/views/utils/getRecordFilterLabelValue.ts +++ b/packages/twenty-front/src/modules/views/utils/getRecordFilterLabelValue.ts @@ -2,9 +2,8 @@ import { type FieldMetadataItemOption } from '@/object-metadata/types/FieldMetad import { getOperandLabelShort } from '@/object-record/object-filter-dropdown/utils/getOperandLabel'; 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 { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty'; -import { parseJson } from 'twenty-shared/utils'; +import { isEmptinessOperand, parseJson } from 'twenty-shared/utils'; export const getRecordFilterLabelValue = ({ recordFilter, diff --git a/packages/twenty-front/src/modules/views/utils/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.ts b/packages/twenty-front/src/modules/views/utils/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.ts index 976a63bc91..fee1fea929 100644 --- a/packages/twenty-front/src/modules/views/utils/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.ts +++ b/packages/twenty-front/src/modules/views/utils/mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator.ts @@ -1,5 +1,5 @@ -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; export const mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator = ({ diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.ts b/packages/twenty-front/src/modules/views/utils/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.ts index 316b6d0858..6bf34f0ebb 100644 --- a/packages/twenty-front/src/modules/views/utils/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.ts +++ b/packages/twenty-front/src/modules/views/utils/mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator.ts @@ -1,5 +1,5 @@ -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLogicalOperator'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; export const mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator = ({ diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts index 7de909ca63..9f1dcf27cf 100644 --- a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts +++ b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts @@ -2,12 +2,11 @@ import { type RecordFilter } from '@/object-record/record-filter/types/RecordFil import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { isSystemSearchVectorField } from '@/object-record/utils/isSystemSearchVectorField'; import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName'; import { convertViewFilterOperandFromCore } from '@/views/utils/convertViewFilterOperandFromCore'; import { type ViewFilterOperand } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; import { type CoreViewFilter } from '~/generated/graphql'; import { type ViewFilter } from '../types/ViewFilter'; diff --git a/packages/twenty-front/src/modules/views/view-filter-value/types/RelationFilterValue.ts b/packages/twenty-front/src/modules/views/view-filter-value/types/RelationFilterValue.ts index 3919e79788..0fd4807d8a 100644 --- a/packages/twenty-front/src/modules/views/view-filter-value/types/RelationFilterValue.ts +++ b/packages/twenty-front/src/modules/views/view-filter-value/types/RelationFilterValue.ts @@ -1,4 +1,4 @@ -import { type jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema'; +import { type jsonRelationFilterValueSchema } from 'twenty-shared/utils'; import { type z } from 'zod'; export type RelationFilterValue = z.infer; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsAddFilterButton.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsAddFilterButton.tsx index 3a26b3a886..b0fcbe1c95 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsAddFilterButton.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsAddFilterButton.tsx @@ -2,13 +2,13 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector'; import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup'; -import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator'; import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem'; import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState'; import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState'; import { useContext } from 'react'; +import { RecordFilterGroupLogicalOperator } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { IconFilter } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx index d6ec563a85..00f628d971 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters.tsx @@ -7,7 +7,6 @@ import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/adv import { isRecordFilterGroupChildARecordFilterGroup } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilterGroup'; import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter'; import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; @@ -17,7 +16,10 @@ import { type FindRecordsActionFilter } from '@/workflow/workflow-steps/workflow import { WorkflowFindRecordsAddFilterButton } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsAddFilterButton'; import styled from '@emotion/styled'; import { useRecoilCallback, useRecoilValue } from 'recoil'; -import { isDefined } from 'twenty-shared/utils'; +import { + computeRecordGqlOperationFilter, + isDefined, +} from 'twenty-shared/utils'; const StyledContainer = styled.div` align-items: start; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts index a499275b43..2852628d75 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts @@ -1,6 +1,6 @@ -import { CustomError } from '@/error-handler/CustomError'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type WorkflowActionType } from '@/workflow/types/Workflow'; +import { CustomError } from 'twenty-shared/utils'; import { FieldMetadataType } from '~/generated-metadata/graphql'; const COMMON_DISPLAYABLE_FIELD_TYPES = [ diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx index 86627cd5a0..ac0ada20b5 100644 --- a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx @@ -28,7 +28,11 @@ import { WorkspaceInviteTeam } from '@/workspace/components/WorkspaceInviteTeam' import { type ApolloError } from '@apollo/client'; import { formatDistanceToNow } from 'date-fns'; import { SettingsPath } from 'twenty-shared/types'; -import { getSettingsPath, isDefined } from 'twenty-shared/utils'; +import { + generateILikeFiltersForCompositeFields, + getSettingsPath, + isDefined, +} from 'twenty-shared/utils'; import { AppTooltip, Avatar, @@ -47,7 +51,6 @@ import { useImpersonateMutation, } from '~/generated-metadata/graphql'; -import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; import { TableCell } from '../../modules/ui/layout/table/components/TableCell'; import { TableRow } from '../../modules/ui/layout/table/components/TableRow'; diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx index eae314ce56..308fc6128e 100644 --- a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx @@ -2,14 +2,13 @@ import { type Decorator } from '@storybook/react'; import { useEffect } from 'react'; import { useRecoilCallback } from 'recoil'; -import { CustomError } from '@/error-handler/CustomError'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { isDefined } from 'twenty-shared/utils'; +import { CustomError, isDefined } from 'twenty-shared/utils'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people'; import { mockedTasks } from '~/testing/mock-data/tasks'; diff --git a/packages/twenty-front/src/utils/date-utils.ts b/packages/twenty-front/src/utils/date-utils.ts index be8dcb5bd5..2046ba4187 100644 --- a/packages/twenty-front/src/utils/date-utils.ts +++ b/packages/twenty-front/src/utils/date-utils.ts @@ -13,9 +13,8 @@ import { } from 'date-fns'; import { DateFormat } from '@/localization/constants/DateFormat'; -import { isDefined } from 'twenty-shared/utils'; +import { CustomError, isDefined } from 'twenty-shared/utils'; -import { CustomError } from '@/error-handler/CustomError'; import { i18n } from '@lingui/core'; import { plural, t } from '@lingui/core/macro'; import { logError } from './logError'; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts index 448f0a915e..bf805377e3 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/graphql-query-runner.module.ts @@ -22,6 +22,7 @@ import { GraphqlQueryUpdateOneResolverService } from 'src/engine/api/graphql/gra import { WorkspaceQueryHookModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module'; import { WorkspaceQueryRunnerModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.module'; import { ApiKeyModule } from 'src/engine/core-modules/api-key/api-key.module'; +import { CoreViewModule } from 'src/engine/core-modules/view/view.module'; import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets.entity'; import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module'; @@ -52,6 +53,7 @@ const graphqlQueryResolvers = [ TypeOrmModule.forFeature([RoleTargetsEntity]), UserRoleModule, ApiKeyModule, + CoreViewModule, ], providers: [ ProcessNestedRelationsHelper, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-group-by-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-group-by-resolver.service.ts index 3b5e93389c..331e21bd38 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-group-by-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-group-by-resolver.service.ts @@ -1,5 +1,17 @@ import { Injectable } from '@nestjs/common'; +import { + CompositeFieldSubFieldName, + RecordFilterGroupLogicalOperator, +} from 'twenty-shared/types'; +import { + assertIsDefinedOrThrow, + combineFilters, + computeRecordGqlOperationFilter, + convertViewFilterValueToString, + getFilterTypeFromFieldType, +} from 'twenty-shared/utils'; + import { GraphqlQueryBaseResolverService, GraphqlQueryResolverExecutionArgs, @@ -18,7 +30,11 @@ import { GraphqlQueryRunnerExceptionCode, } from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception'; import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper'; +import { convertViewFilterOperand } from 'src/engine/api/graphql/graphql-query-runner/utils/convert-view-filter-operands'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; +import { ViewFilterGroupService } from 'src/engine/core-modules/view/services/view-filter-group.service'; +import { ViewFilterService } from 'src/engine/core-modules/view/services/view-filter.service'; +import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; import { formatColumnNamesFromCompositeFieldAndSubfields } from 'src/engine/twenty-orm/utils/format-column-names-from-composite-field-and-subfield.util'; @@ -28,6 +44,13 @@ export class GraphqlQueryGroupByResolverService extends GraphqlQueryBaseResolver GroupByResolverArgs, IGroupByConnection>[] > { + constructor( + private readonly viewFilterService: ViewFilterService, + private readonly viewFilterGroupService: ViewFilterGroupService, + ) { + super(); + } + async resolve( executionArgs: GraphqlQueryResolverExecutionArgs, _featureFlagsMap: Record, @@ -44,6 +67,14 @@ export class GraphqlQueryGroupByResolverService extends GraphqlQueryBaseResolver let appliedFilters = executionArgs.args.filter ?? ({} as ObjectRecordFilter); + if (executionArgs.args.viewId) { + appliedFilters = await this.addFiltersFromView({ + executionArgs, + objectMetadataItemWithFieldMaps, + appliedFilters, + }); + } + executionArgs.graphqlQueryParser.applyFilterToBuilder( queryBuilder, objectMetadataNameSingular, @@ -182,6 +213,77 @@ export class GraphqlQueryGroupByResolverService extends GraphqlQueryBaseResolver return groupByFields; } + private async addFiltersFromView({ + executionArgs, + objectMetadataItemWithFieldMaps, + appliedFilters, + }: { + executionArgs: GraphqlQueryResolverExecutionArgs; + objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps; + appliedFilters: ObjectRecordFilter; + }): Promise { + assertIsDefinedOrThrow(executionArgs.args.viewId); + + const workspaceId = executionArgs.options.authContext.workspace?.id; + + assertIsDefinedOrThrow(workspaceId, WorkspaceNotFoundDefaultError); + + const viewFilters = await this.viewFilterService.findByViewId( + workspaceId, + executionArgs.args.viewId, + ); + + const viewFilterGroups = await this.viewFilterGroupService.findByViewId( + workspaceId, + executionArgs.args.viewId, + ); + + const recordFilters = viewFilters.map((viewFilter) => { + const fieldMetadataItem = + objectMetadataItemWithFieldMaps.fieldsById[viewFilter.fieldMetadataId]; + + return { + id: viewFilter.id, + fieldMetadataId: viewFilter.fieldMetadataId, + value: convertViewFilterValueToString(viewFilter.value), + type: getFilterTypeFromFieldType(fieldMetadataItem.type), + operand: convertViewFilterOperand(viewFilter.operand), + recordFilterGroupId: viewFilter.viewFilterGroupId, + positionInRecordFilterGroup: viewFilter.positionInViewFilterGroup, + subFieldName: viewFilter.subFieldName as CompositeFieldSubFieldName, + }; + }); + + const recordFilterGroups = viewFilterGroups.map((viewFilterGroup) => { + return { + id: viewFilterGroup.id, + logicalOperator: + viewFilterGroup.logicalOperator as unknown as RecordFilterGroupLogicalOperator, // TODO - https://github.com/twentyhq/twenty/issues/14746 + parentRecordFilterGroupId: viewFilterGroup.parentViewFilterGroupId, + }; + }); + + const fields = Object.values( + objectMetadataItemWithFieldMaps.fieldsById, + ).map((field) => ({ + id: field.id, + name: field.name, + type: field.type, + label: field.label, + })); + + const filtersFromView = computeRecordGqlOperationFilter({ + recordFilters, + recordFilterGroups: recordFilterGroups, + fields, + filterValueDependencies: {}, + }); + + appliedFilters = combineFilters([appliedFilters, filtersFromView]); + + return appliedFilters; + } + async validate( _args: GroupByResolverArgs, _options: WorkspaceQueryRunnerOptions, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/convert-view-filter-operands.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/convert-view-filter-operands.ts new file mode 100644 index 0000000000..a486f27576 --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/convert-view-filter-operands.ts @@ -0,0 +1,44 @@ +import { ViewFilterOperand as ViewFilterOperandShared } from 'twenty-shared/types'; + +import { ViewFilterOperand } from 'src/engine/core-modules/view/enums/view-filter-operand'; + +export const convertViewFilterOperand = ( + operand: ViewFilterOperand, +): ViewFilterOperandShared => { + switch (operand) { + case ViewFilterOperand.IS: + return ViewFilterOperandShared.Is; + case ViewFilterOperand.IS_NOT_NULL: + return ViewFilterOperandShared.IsNotNull; + case ViewFilterOperand.IS_NOT: + return ViewFilterOperandShared.IsNot; + case ViewFilterOperand.LESS_THAN_OR_EQUAL: + return ViewFilterOperandShared.LessThanOrEqual; + case ViewFilterOperand.GREATER_THAN_OR_EQUAL: + return ViewFilterOperandShared.GreaterThanOrEqual; + case ViewFilterOperand.IS_BEFORE: + return ViewFilterOperandShared.IsBefore; + case ViewFilterOperand.IS_AFTER: + return ViewFilterOperandShared.IsAfter; + case ViewFilterOperand.CONTAINS: + return ViewFilterOperandShared.Contains; + case ViewFilterOperand.DOES_NOT_CONTAIN: + return ViewFilterOperandShared.DoesNotContain; + case ViewFilterOperand.IS_EMPTY: + return ViewFilterOperandShared.IsEmpty; + case ViewFilterOperand.IS_NOT_EMPTY: + return ViewFilterOperandShared.IsNotEmpty; + case ViewFilterOperand.IS_RELATIVE: + return ViewFilterOperandShared.IsRelative; + case ViewFilterOperand.IS_IN_PAST: + return ViewFilterOperandShared.IsInPast; + case ViewFilterOperand.IS_IN_FUTURE: + return ViewFilterOperandShared.IsInFuture; + case ViewFilterOperand.IS_TODAY: + return ViewFilterOperandShared.IsToday; + case ViewFilterOperand.VECTOR_SEARCH: + return ViewFilterOperandShared.VectorSearch; + default: + throw new Error(`Invalid view filter operand: ${operand}`); + } +}; diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts index 87cba55243..07273f5109 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts @@ -139,7 +139,7 @@ describe('WorkspaceEntityManager', () => { IS_WORKFLOW_ITERATOR_ENABLED: false, IS_DATABASE_EVENT_TRIGGER_ENABLED: false, IS_CALENDAR_VIEW_ENABLED: false, - IS_GROUP_BY_ENABLED: false, + IS_GROUP_BY_ENABLED: true, IS_PUBLIC_DOMAIN_ENABLED: false, IS_EMAILING_DOMAIN_ENABLED: false, IS_DYNAMIC_SEARCH_FIELDS_ENABLED: false, diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts index 40b5dcee23..a3e501d8c2 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts @@ -78,7 +78,7 @@ export const seedFeatureFlags = async ( { key: FeatureFlagKey.IS_GROUP_BY_ENABLED, workspaceId: workspaceId, - value: false, + value: true, }, { key: FeatureFlagKey.IS_PUBLIC_DOMAIN_ENABLED, diff --git a/packages/twenty-server/src/utils/custom-exception.ts b/packages/twenty-server/src/utils/custom-exception.ts index 24bda4faab..34300cc1e2 100644 --- a/packages/twenty-server/src/utils/custom-exception.ts +++ b/packages/twenty-server/src/utils/custom-exception.ts @@ -1,3 +1,5 @@ +import { CustomError } from 'twenty-shared/utils'; + const CommonExceptionCode = { INTERNAL_SERVER_ERROR: 'INTERNAL_SERVER_ERROR', } as const; @@ -18,7 +20,7 @@ export abstract class CustomException< ForceFriendlyMessage = false, ExceptionMessage extends string = string, ExceptionFriendlyMessage extends string = string, -> extends Error { +> extends CustomError { code: ExceptionCode; userFriendlyMessage?: ExceptionFriendlyMessage; diff --git a/packages/twenty-server/test/integration/graphql/suites/group-by-resolvers.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/group-by-resolvers.integration-spec.ts new file mode 100644 index 0000000000..3613b3c309 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/group-by-resolvers.integration-spec.ts @@ -0,0 +1,239 @@ +import { randomUUID } from 'crypto'; + +import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { createViewFilterGroupOperationFactory } from 'test/integration/graphql/utils/create-view-filter-group-operation-factory.util'; +import { createViewFilterOperationFactory } from 'test/integration/graphql/utils/create-view-filter-operation-factory.util'; +import { createViewOperationFactory } from 'test/integration/graphql/utils/create-view-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { groupByOperationFactory } from 'test/integration/graphql/utils/group-by-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { findManyObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata.util'; + +import { ViewFilterOperand } from 'src/engine/core-modules/view/enums/view-filter-operand'; +import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto'; +import { ViewFilterGroupLogicalOperator } from 'src/modules/view/standard-objects/view-filter-group.workspace-entity'; + +describe('group-by resolvers (integration)', () => { + describe('with viewId undefined', () => { + const testPersonId = randomUUID(); + const testPerson2Id = randomUUID(); + const testPerson3Id = randomUUID(); + + afterEach(async () => { + // cleanup created people + await makeGraphqlAPIRequest( + deleteOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPersonId, + }), + ); + await makeGraphqlAPIRequest( + deleteOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPerson2Id, + }), + ); + await makeGraphqlAPIRequest( + deleteOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPerson3Id, + }), + ); + }); + it('groups by city', async () => { + const cityA = 'City A'; + const cityB = 'City B'; + + await makeGraphqlAPIRequest( + createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { id: testPersonId, city: cityA }, + }), + ); + await makeGraphqlAPIRequest( + createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { id: testPerson2Id, city: cityB }, + }), + ); + await makeGraphqlAPIRequest( + createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { id: testPerson3Id, city: cityB }, + }), + ); + + const response = await makeGraphqlAPIRequest( + groupByOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + groupBy: [{ city: true }], + }), + ); + + const groups = response.body.data.peopleGroupBy; + + expect(groups).toBeDefined(); + expect(groups).toEqual( + expect.arrayContaining([ + expect.objectContaining({ groupByDimensionValues: [cityA] }), + expect.objectContaining({ groupByDimensionValues: [cityB] }), + ]), + ); + + const groupWithCityA = groups.find( + (group: any) => group.groupByDimensionValues[0] === cityA, + ); + + expect(groupWithCityA.groupByDimensionValues).toEqual([cityA]); + expect(groupWithCityA.totalCount).toEqual(1); + + const groupWithCityB = groups.find( + (group: any) => group.groupByDimensionValues[0] === cityB, + ); + + expect(groupWithCityB.groupByDimensionValues).toEqual([cityB]); + expect(groupWithCityB.totalCount).toEqual(2); + }); + }); + + describe('with viewId defined', () => { + const testPersonId = randomUUID(); + const testPerson2Id = randomUUID(); + const testPerson3Id = randomUUID(); + + afterEach(async () => { + // cleanup created people + await makeGraphqlAPIRequest( + deleteOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPersonId, + }), + ); + await makeGraphqlAPIRequest( + deleteOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPerson2Id, + }), + ); + await makeGraphqlAPIRequest( + deleteOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPerson3Id, + }), + ); + }); + it('groups by city', async () => { + const { objects } = await findManyObjectMetadata({ + input: { + filter: {}, + paging: { + first: 100, + }, + }, + gqlFields: 'id nameSingular fieldsList { id name }', + expectToFail: false, + }); + + const personObject = objects.find((o) => o.nameSingular === 'person'); + const personObjectMetadataId = personObject?.id; + + const cityFieldMetadata = personObject?.fieldsList?.find( + (f: FieldMetadataDTO) => f.name === 'city', + ); + const cityFieldMetadataId = cityFieldMetadata?.id; + + const cityToKeep = 'City To Keep'; + const cityToExclude = 'City To Exclude'; + + await makeGraphqlAPIRequest( + createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { id: testPersonId, city: cityToKeep }, + }), + ); + await makeGraphqlAPIRequest( + createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { id: testPerson2Id, city: cityToExclude }, + }), + ); + + // create a view with a filter: city eq cityToKeep + const createViewResponse = await makeGraphqlAPIRequest( + createViewOperationFactory({ + data: { + name: 'People View City Keep', + objectMetadataId: personObjectMetadataId, + icon: 'Icon123', + }, + }), + ); + + const viewId = createViewResponse.body.data.createCoreView.id as string; + + // create a filter group and a filter for the view + const viewFilterGroupResponse = await makeGraphqlAPIRequest( + createViewFilterGroupOperationFactory({ + data: { + viewId, + logicalOperator: ViewFilterGroupLogicalOperator.AND, + positionInViewFilterGroup: 0, + }, + }), + ); + + const viewFilterGroupId = viewFilterGroupResponse.body.data + .createCoreViewFilterGroup.id as string; + + await makeGraphqlAPIRequest( + createViewFilterOperationFactory({ + data: { + viewId, + viewFilterGroupId, + fieldMetadataId: cityFieldMetadataId, + operand: ViewFilterOperand.CONTAINS, + value: cityToKeep, + positionInViewFilterGroup: 0, + }, + }), + ); + + const response = await makeGraphqlAPIRequest( + groupByOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + groupBy: [{ city: true }], + viewId, + }), + ); + + const groups = response.body.data.peopleGroupBy; + + expect(groups).toBeDefined(); + expect(groups).toEqual( + expect.arrayContaining([ + expect.objectContaining({ groupByDimensionValues: [cityToKeep] }), + ]), + ); + // Ensure excluded city is not present + expect(groups).toEqual( + expect.not.arrayContaining([ + expect.objectContaining({ groupByDimensionValues: [cityToExclude] }), + ]), + ); + }); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/utils/group-by-operation-factory.util.ts b/packages/twenty-server/test/integration/graphql/utils/group-by-operation-factory.util.ts new file mode 100644 index 0000000000..47ca97cb90 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/utils/group-by-operation-factory.util.ts @@ -0,0 +1,35 @@ +import gql from 'graphql-tag'; +import { capitalize } from 'twenty-shared/utils'; + +type GroupByOperationFactoryParams = { + objectMetadataSingularName: string; + objectMetadataPluralName: string; + groupBy: object[]; + filter?: object; + orderBy?: object[]; + viewId?: string; +}; + +export const groupByOperationFactory = ({ + objectMetadataSingularName, + objectMetadataPluralName, + groupBy, + filter = {}, + orderBy = [], + viewId, +}: GroupByOperationFactoryParams) => ({ + query: gql` + query ${capitalize(objectMetadataPluralName)}GroupBy($groupBy: [${capitalize(objectMetadataSingularName)}GroupByInput!]!, $filter: ${capitalize(objectMetadataSingularName)}FilterInput, $orderBy: [${capitalize(objectMetadataSingularName)}OrderByWithGroupByInput!], $viewId: UUID) { + ${objectMetadataPluralName}GroupBy(groupBy: $groupBy, filter: $filter, orderBy: $orderBy, viewId: $viewId) { + groupByDimensionValues + totalCount + } + } + `, + variables: { + groupBy, + filter, + orderBy, + ...(viewId && { viewId }), + }, +}); diff --git a/packages/twenty-server/test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata.util.ts b/packages/twenty-server/test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata.util.ts index 06bd7b98ba..09fb0f215a 100644 --- a/packages/twenty-server/test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata.util.ts +++ b/packages/twenty-server/test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata.util.ts @@ -8,6 +8,7 @@ import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util'; import { type BaseGraphQLError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto'; import { type ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto'; export const findManyObjectMetadata = async ({ @@ -16,7 +17,7 @@ export const findManyObjectMetadata = async ({ expectToFail, }: PerformMetadataQueryParams): Promise<{ errors: BaseGraphQLError[]; - objects: ObjectMetadataDTO[]; + objects: (ObjectMetadataDTO & { fieldsList?: FieldMetadataDTO[] })[]; }> => { const graphqlOperation = findManyObjectMetadataQueryFactory({ input, diff --git a/packages/twenty-shared/src/constants/CompositeFieldTypeSubFieldsNames.ts b/packages/twenty-shared/src/constants/CompositeFieldTypeSubFieldsNames.ts new file mode 100644 index 0000000000..07919c6297 --- /dev/null +++ b/packages/twenty-shared/src/constants/CompositeFieldTypeSubFieldsNames.ts @@ -0,0 +1,49 @@ +import { FieldMetadataType } from '@/types'; + +export const COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES = { + [FieldMetadataType.CURRENCY]: { + 'amountMicros': 'amountMicros', + 'currencyCode': 'currencyCode', + }, + [FieldMetadataType.EMAILS]: { + 'primaryEmail': 'primaryEmail', + 'additionalEmails': 'additionalEmails', + }, + [FieldMetadataType.LINKS]: { + 'primaryLinkUrl': 'primaryLinkUrl', + 'primaryLinkLabel': 'primaryLinkLabel', + 'secondaryLinks': 'secondaryLinks', + }, + [FieldMetadataType.PHONES]: { + 'primaryPhoneCallingCode': 'primaryPhoneCallingCode', + 'primaryPhoneCountryCode': 'primaryPhoneCountryCode', + 'primaryPhoneNumber': 'primaryPhoneNumber', + 'additionalPhones': 'additionalPhones', + }, + [FieldMetadataType.FULL_NAME]: { + 'firstName': 'firstName', + 'lastName': 'lastName', + }, + [FieldMetadataType.ADDRESS]: { + 'addressStreet1': 'addressStreet1', + 'addressStreet2': 'addressStreet2', + 'addressCity': 'addressCity', + 'addressState': 'addressState', + 'addressCountry': 'addressCountry', + 'addressPostcode': 'addressPostcode', + 'addressLat': 'addressLat', + 'addressLng': 'addressLng', + }, + [FieldMetadataType.ACTOR]: { + 'source': 'source', + 'name': 'name', + 'workspaceMemberId': 'workspaceMemberId', + 'context': 'context', + }, + [FieldMetadataType.RICH_TEXT_V2]: { + 'blocknote': 'blocknote', + 'markdown': 'markdown', + }, +} as const; + + diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/constants/RatingValues.ts b/packages/twenty-shared/src/constants/RatingValues.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/constants/RatingValues.ts rename to packages/twenty-shared/src/constants/RatingValues.ts diff --git a/packages/twenty-shared/src/constants/index.ts b/packages/twenty-shared/src/constants/index.ts index 1afe9335c8..6fd8c5162f 100644 --- a/packages/twenty-shared/src/constants/index.ts +++ b/packages/twenty-shared/src/constants/index.ts @@ -7,6 +7,7 @@ * |___/ */ +export { COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES } from './CompositeFieldTypeSubFieldsNames'; export { FIELD_FOR_TOTAL_COUNT_AGGREGATE_OPERATION } from './FieldForTotalCountAggregateOperation'; export { MAX_OPTIONS_TO_DISPLAY } from './FieldMetadataMaxOptionsToDisplay'; export { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from './FieldRestrictedAdditionalPermissionsRequired'; @@ -16,6 +17,7 @@ export { PermissionsOnAllObjectRecords } from './PermissionsOnAllObjectRecords'; export { QUERY_DEFAULT_LIMIT_RECORDS } from './QueryDefaultLimitRecords'; export { QUERY_MAX_RECORDS } from './QueryMaxRecords'; export { QUOTED_STRING_REGEX } from './QuotedStringRegex'; +export { RATING_VALUES } from './RatingValues'; export { RELATION_NESTED_QUERY_KEYWORDS } from './RelationNestedQueriesKeyword'; export { STANDARD_OBJECT_RECORDS_UNDER_OBJECT_RECORDS_PERMISSIONS } from './StandardObjectRecordsUnderObjectRecordsPermissions'; export { TWENTY_COMPANIES_BASE_URL } from './TwentyCompaniesBaseUrl'; diff --git a/packages/twenty-shared/src/types/CompositeFieldSubFieldNameType.ts b/packages/twenty-shared/src/types/CompositeFieldSubFieldNameType.ts new file mode 100644 index 0000000000..5c14bb4800 --- /dev/null +++ b/packages/twenty-shared/src/types/CompositeFieldSubFieldNameType.ts @@ -0,0 +1,6 @@ +import { COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES } from '@/constants/CompositeFieldTypeSubFieldsNames'; + +const _allSubFieldValues = Object.values(COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES) + .flatMap(obj => Object.values(obj)); + +export type CompositeFieldSubFieldName = typeof _allSubFieldValues[number]; \ No newline at end of file diff --git a/packages/twenty-shared/src/types/FieldRatingValue.ts b/packages/twenty-shared/src/types/FieldRatingValue.ts new file mode 100644 index 0000000000..504bac09e6 --- /dev/null +++ b/packages/twenty-shared/src/types/FieldRatingValue.ts @@ -0,0 +1,3 @@ +import { type RATING_VALUES } from "@/constants/RatingValues"; + +export type FieldRatingValue = (typeof RATING_VALUES)[number] | null; \ No newline at end of file diff --git a/packages/twenty-front/src/modules/object-record/record-filter/types/FilterableFieldType.ts b/packages/twenty-shared/src/types/FilterableFieldType.ts similarity index 79% rename from packages/twenty-front/src/modules/object-record/record-filter/types/FilterableFieldType.ts rename to packages/twenty-shared/src/types/FilterableFieldType.ts index 9bef02876d..26e5740e01 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/types/FilterableFieldType.ts +++ b/packages/twenty-shared/src/types/FilterableFieldType.ts @@ -1,5 +1,6 @@ -import { type FieldType } from '@/settings/data-model/types/FieldType'; -import { type PickLiteral } from '~/types/PickLiteral'; +import { type FieldMetadataType } from '@/types/FieldMetadataType'; + +type PickLiteral = U; export const FILTERABLE_FIELD_TYPES = [ 'TEXT', @@ -26,7 +27,7 @@ export const FILTERABLE_FIELD_TYPES = [ type FilterableFieldTypeBaseLiteral = (typeof FILTERABLE_FIELD_TYPES)[number]; export type FilterableFieldType = PickLiteral< - FieldType, + `${FieldMetadataType}`, FilterableFieldTypeBaseLiteral >; diff --git a/packages/twenty-shared/src/types/PartialFieldMetadataItem.ts b/packages/twenty-shared/src/types/PartialFieldMetadataItem.ts new file mode 100644 index 0000000000..f4b1a77465 --- /dev/null +++ b/packages/twenty-shared/src/types/PartialFieldMetadataItem.ts @@ -0,0 +1,8 @@ +import { type FieldMetadataType } from "@/types/FieldMetadataType"; + +export type PartialFieldMetadataItem = { + id: string; + name: string; + type: FieldMetadataType; + label: string; + } \ No newline at end of file diff --git a/packages/twenty-front/src/modules/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator.ts b/packages/twenty-shared/src/types/RecordFilterGroupLogicalOperator.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator.ts rename to packages/twenty-shared/src/types/RecordFilterGroupLogicalOperator.ts diff --git a/packages/twenty-front/src/modules/object-record/record-filter/types/RecordFilterValueDependencies.ts b/packages/twenty-shared/src/types/RecordFilterValueDependencies.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/record-filter/types/RecordFilterValueDependencies.ts rename to packages/twenty-shared/src/types/RecordFilterValueDependencies.ts diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts b/packages/twenty-shared/src/types/RecordGqlOperationFilter.ts similarity index 100% rename from packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts rename to packages/twenty-shared/src/types/RecordGqlOperationFilter.ts diff --git a/packages/twenty-shared/src/types/index.ts b/packages/twenty-shared/src/types/index.ts index 27303feaee..5621145246 100644 --- a/packages/twenty-shared/src/types/index.ts +++ b/packages/twenty-shared/src/types/index.ts @@ -11,11 +11,18 @@ export type { AllowedAddressSubField } from './AddressFieldsType'; export { ALLOWED_ADDRESS_SUBFIELDS } from './AddressFieldsType'; export { AppBasePath } from './AppBasePath'; export { AppPath } from './AppPath'; +export type { CompositeFieldSubFieldName } from './CompositeFieldSubFieldNameType'; export type { ConfigVariableValue } from './ConfigVariableValue'; export { ConnectedAccountProvider } from './ConnectedAccountProvider'; export type { EnumFieldMetadataType } from './EnumFieldMetadataType'; export type { ExcludeFunctions } from './ExcludeFunctions'; export { FieldMetadataType } from './FieldMetadataType'; +export type { FieldRatingValue } from './FieldRatingValue'; +export type { + FilterableFieldType, + FilterableAndTSVectorFieldType, +} from './FilterableFieldType'; +export { FILTERABLE_FIELD_TYPES } from './FilterableFieldType'; export type { FromTo } from './FromToType'; export type { IsExactly } from './IsExactly'; export type { NonNullableRequired } from './NonNullableRequired'; @@ -27,6 +34,41 @@ export type { ObjectsPermissions } from './ObjectsPermissions'; export type { ObjectsPermissionsByRoleId } from './ObjectsPermissionsByRoleId'; export type { ObjectsPermissionsByRoleIdDeprecated } from './ObjectsPermissionsByRoleIdDeprecated'; export type { ObjectsPermissionsDeprecated } from './ObjectsPermissionsDeprecated'; +export type { PartialFieldMetadataItem } from './PartialFieldMetadataItem'; +export { RecordFilterGroupLogicalOperator } from './RecordFilterGroupLogicalOperator'; +export type { RecordFilterValueDependencies } from './RecordFilterValueDependencies'; +export type { + UUIDFilterValue, + IsFilter, + UUIDFilter, + RelationFilter, + BooleanFilter, + StringFilter, + RatingFilter, + FloatFilter, + DateFilter, + CurrencyFilter, + URLFilter, + FullNameFilter, + AddressFilter, + LinksFilter, + ActorFilter, + EmailsFilter, + PhonesFilter, + SelectFilter, + MultiSelectFilter, + ArrayFilter, + RawJsonFilter, + RichTextV2LeafFilter, + RichTextV2Filter, + TSVectorFilter, + LeafFilter, + AndObjectRecordFilter, + OrObjectRecordFilter, + NotObjectRecordFilter, + LeafObjectRecordFilter, + RecordGqlOperationFilter, +} from './RecordGqlOperationFilter'; export type { RelationAndMorphRelationFieldMetadataType } from './RelationAndMorphRelationFieldMetadataType'; export type { RelationCreationPayload } from './RelationCreationPayload'; export { RelationType } from './RelationType'; diff --git a/packages/twenty-front/src/modules/error-handler/CustomError.ts b/packages/twenty-shared/src/utils/errors/CustomError.ts similarity index 100% rename from packages/twenty-front/src/modules/error-handler/CustomError.ts rename to packages/twenty-shared/src/utils/errors/CustomError.ts diff --git a/packages/twenty-shared/src/utils/errors/index.ts b/packages/twenty-shared/src/utils/errors/index.ts new file mode 100644 index 0000000000..4aef179e5a --- /dev/null +++ b/packages/twenty-shared/src/utils/errors/index.ts @@ -0,0 +1 @@ +export { CustomError } from './CustomError'; diff --git a/packages/twenty-shared/src/utils/filter/checkIfShouldComputeEmptinessFilter.ts b/packages/twenty-shared/src/utils/filter/checkIfShouldComputeEmptinessFilter.ts new file mode 100644 index 0000000000..c20a20ec58 --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/checkIfShouldComputeEmptinessFilter.ts @@ -0,0 +1,29 @@ +import { type FieldMetadataType, type FilterableAndTSVectorFieldType, type ViewFilterOperand } from '@/types'; +import { isEmptinessOperand } from '@/utils/filter/isEmptinessOperand'; +import { getFilterTypeFromFieldType } from '@/utils/filter/utils/getFilterTypeFromFieldType'; + +export const checkIfShouldComputeEmptinessFilter = ({ + recordFilterOperand, + correspondingFieldMetadataItem, +}: { + recordFilterOperand: ViewFilterOperand; + correspondingFieldMetadataItem: {type: FieldMetadataType}; +}) => { + const isAnEmptinessOperand = isEmptinessOperand(recordFilterOperand); + + if (!isAnEmptinessOperand) { + return false; + } + + const filterTypesThatHaveNoEmptinessOperand: FilterableAndTSVectorFieldType[] = + ['BOOLEAN', 'TS_VECTOR']; + + const filterType = getFilterTypeFromFieldType( + correspondingFieldMetadataItem.type, + ); + + const filterHasEmptinessOperands = + !filterTypesThatHaveNoEmptinessOperand.includes(filterType); + + return filterHasEmptinessOperands === true; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldSkipFiltering.ts b/packages/twenty-shared/src/utils/filter/checkIfShouldSkipFiltering.ts similarity index 60% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldSkipFiltering.ts rename to packages/twenty-shared/src/utils/filter/checkIfShouldSkipFiltering.ts index 47676852ad..b4665beecd 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldSkipFiltering.ts +++ b/packages/twenty-shared/src/utils/filter/checkIfShouldSkipFiltering.ts @@ -1,13 +1,14 @@ -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'; +import { ViewFilterOperand as RecordFilterOperand } from '@/types'; +import { isDefined } from '@/utils'; +import { isEmptinessOperand, type RecordFilter } from '@/utils/filter'; + +type CheckIfShouldSkipFilteringParams = { + recordFilter: Pick; +}; export const checkIfShouldSkipFiltering = ({ recordFilter, -}: { - recordFilter: RecordFilter; -}) => { +}: CheckIfShouldSkipFilteringParams) => { const isAnEmptinessOperand = isEmptinessOperand(recordFilter.operand); const isDateOperandWithoutValue = [ diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts b/packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts similarity index 88% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts rename to packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts index 1e9cbe9551..6ffcf9f203 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts +++ b/packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts @@ -1,13 +1,13 @@ -import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { + type CompositeFieldSubFieldName, type EmailsFilter, + type PartialFieldMetadataItem, + ViewFilterOperand as RecordFilterOperand, type RecordGqlOperationFilter, -} from '@/object-record/graphql/types/RecordGqlOperationFilter'; +} from '@/types'; +import { CustomError } from '@/utils/errors'; -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 { type RecordFilter } from '@/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter'; import { isNonEmptyString } from '@sniptt/guards'; export const computeGqlOperationFilterForEmails = ({ @@ -16,7 +16,7 @@ export const computeGqlOperationFilterForEmails = ({ subFieldName, }: { recordFilter: RecordFilter; - correspondingFieldMetadataItem: Pick; + correspondingFieldMetadataItem: Pick; subFieldName: CompositeFieldSubFieldName | null | undefined; }): RecordGqlOperationFilter => { const isSubFieldFilter = isNonEmptyString(subFieldName); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts b/packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts similarity index 87% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts rename to packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts index d9ee9e0e42..5fe3aaa614 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts +++ b/packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts @@ -1,9 +1,6 @@ -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 { ViewFilterOperand as RecordFilterOperand, type CompositeFieldSubFieldName, type LinksFilter, type PartialFieldMetadataItem } from '@/types'; +import { CustomError } from '@/utils/errors'; +import { type RecordFilter } from '@/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter'; import { isNonEmptyString } from '@sniptt/guards'; export const computeGqlOperationFilterForLinks = ({ @@ -12,7 +9,7 @@ export const computeGqlOperationFilterForLinks = ({ subFieldName, }: { recordFilter: RecordFilter; - correspondingFieldMetadataItem: Pick; + correspondingFieldMetadataItem: Pick subFieldName: CompositeFieldSubFieldName | null | undefined; }) => { const isSubFieldFilter = isNonEmptyString(subFieldName); @@ -41,8 +38,9 @@ export const computeGqlOperationFilterForLinks = ({ }, }; default: - throw new Error( + throw new CustomError( `Unknown operand ${recordFilter.operand} for ${correspondingFieldMetadataItem.type} filter`, + 'UNKNOWN_OPERAND_FOR_FILTER', ); } } @@ -84,9 +82,9 @@ export const computeGqlOperationFilterForLinks = ({ } } default: { - throw new CustomError( + throw new Error( // TODO `Unknown subfield name ${subFieldName}`, - 'UNKNOWN_SUBFIELD_NAME', + // 'UNKNOWN_SUBFIELD_NAME', ); } } diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForEmails.ts b/packages/twenty-shared/src/utils/filter/computeEmptyGqlOperationFilterForEmails.ts similarity index 84% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForEmails.ts rename to packages/twenty-shared/src/utils/filter/computeEmptyGqlOperationFilterForEmails.ts index 4051a4914d..c676370bda 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForEmails.ts +++ b/packages/twenty-shared/src/utils/filter/computeEmptyGqlOperationFilterForEmails.ts @@ -1,11 +1,11 @@ -import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type EmailsFilter, + type PartialFieldMetadataItem, type RecordGqlOperationFilter, -} from '@/object-record/graphql/types/RecordGqlOperationFilter'; +} from '@/types'; +import { CustomError } from '@/utils/errors'; -import { CustomError } from '@/error-handler/CustomError'; -import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { type RecordFilter } from '@/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter'; import { isNonEmptyString } from '@sniptt/guards'; export const computeEmptyGqlOperationFilterForEmails = ({ @@ -13,7 +13,7 @@ export const computeEmptyGqlOperationFilterForEmails = ({ correspondingFieldMetadataItem, }: { recordFilter: RecordFilter; - correspondingFieldMetadataItem: Pick; + correspondingFieldMetadataItem: Pick; }): RecordGqlOperationFilter => { const subFieldName = recordFilter.subFieldName; const isSubFieldFilter = isNonEmptyString(subFieldName); @@ -53,7 +53,7 @@ export const computeEmptyGqlOperationFilterForEmails = ({ }; } default: { - throw new CustomError( + throw new CustomError( `Unknown subfield name ${subFieldName}`, 'UNKNOWN_SUBFIELD_NAME', ); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForLinks.ts b/packages/twenty-shared/src/utils/filter/computeEmptyGqlOperationFilterForLinks.ts similarity index 88% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForLinks.ts rename to packages/twenty-shared/src/utils/filter/computeEmptyGqlOperationFilterForLinks.ts index d0f712b4cd..ef78023fcf 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-empty-record-gql-operation-filter/for-composite-field/computeEmptyGqlOperationFilterForLinks.ts +++ b/packages/twenty-shared/src/utils/filter/computeEmptyGqlOperationFilterForLinks.ts @@ -1,11 +1,11 @@ -import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type LinksFilter, + type PartialFieldMetadataItem, type RecordGqlOperationFilter, -} from '@/object-record/graphql/types/RecordGqlOperationFilter'; +} from '@/types'; +import { CustomError } from '@/utils/errors'; -import { CustomError } from '@/error-handler/CustomError'; -import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { type RecordFilter } from '@/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter'; import { isNonEmptyString } from '@sniptt/guards'; export const computeEmptyGqlOperationFilterForLinks = ({ @@ -13,7 +13,7 @@ export const computeEmptyGqlOperationFilterForLinks = ({ correspondingFieldMetadataItem, }: { recordFilter: RecordFilter; - correspondingFieldMetadataItem: Pick; + correspondingFieldMetadataItem: Pick; }): RecordGqlOperationFilter => { const subFieldName = recordFilter.subFieldName; const isSubFieldFilter = isNonEmptyString(subFieldName); @@ -69,7 +69,7 @@ export const computeEmptyGqlOperationFilterForLinks = ({ }; } default: { - throw new CustomError( + throw new CustomError( `Unknown subfield name ${subFieldName}`, 'UNKNOWN_SUBFIELD_NAME', ); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/computeRecordGqlOperationFilter.ts b/packages/twenty-shared/src/utils/filter/computeRecordGqlOperationFilter.ts similarity index 53% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/computeRecordGqlOperationFilter.ts rename to packages/twenty-shared/src/utils/filter/computeRecordGqlOperationFilter.ts index ab920cc770..6fad5201c8 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/computeRecordGqlOperationFilter.ts +++ b/packages/twenty-shared/src/utils/filter/computeRecordGqlOperationFilter.ts @@ -1,35 +1,38 @@ -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'; +import { + type PartialFieldMetadataItem, + type RecordFilterValueDependencies, + type RecordGqlOperationFilter, +} from '@/types'; +import { + isDefined, + turnRecordFilterGroupsIntoGqlOperationFilter, + turnRecordFilterIntoRecordGqlOperationFilter, + type RecordFilter, + type RecordFilterGroup, +} from '@/utils'; export const computeRecordGqlOperationFilter = ({ fields, - filterValueDependencies, recordFilters, recordFilterGroups, + filterValueDependencies, }: { - filterValueDependencies: RecordFilterValueDependencies; recordFilters: RecordFilter[]; - fields: Pick[]; + fields: PartialFieldMetadataItem[]; recordFilterGroups: RecordFilterGroup[]; + filterValueDependencies: RecordFilterValueDependencies; }): RecordGqlOperationFilter => { const regularRecordGqlOperationFilter: RecordGqlOperationFilter[] = recordFilters .filter((filter) => !isDefined(filter.recordFilterGroupId)) - .map((regularFilter) => - turnRecordFilterIntoRecordGqlOperationFilter({ - filterValueDependencies, + .map((regularFilter) => { + return turnRecordFilterIntoRecordGqlOperationFilter({ recordFilter: regularFilter, fieldMetadataItems: fields, - }), - ) + filterValueDependencies, + }); + }) .filter(isDefined); const outermostFilterGroupId = recordFilterGroups.find( @@ -37,12 +40,13 @@ export const computeRecordGqlOperationFilter = ({ )?.id; const advancedRecordGqlOperationFilter = - turnRecordFilterGroupsIntoGqlOperationFilter( + turnRecordFilterGroupsIntoGqlOperationFilter({ filterValueDependencies, - recordFilters, + filters: recordFilters, fields, recordFilterGroups, - outermostFilterGroupId, + currentRecordFilterGroupId: outermostFilterGroupId, + } ); const recordGqlOperationFilters = [ diff --git a/packages/twenty-shared/src/utils/filter/index.ts b/packages/twenty-shared/src/utils/filter/index.ts new file mode 100644 index 0000000000..d8b3917394 --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/index.ts @@ -0,0 +1,22 @@ +export * from './checkIfShouldComputeEmptinessFilter'; +export * from './checkIfShouldSkipFiltering'; +export * from './compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails'; +export * from './compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks'; +export * from './computeEmptyGqlOperationFilterForEmails'; +export * from './computeEmptyGqlOperationFilterForLinks'; +export * from './computeRecordGqlOperationFilter'; +export * from './isEmptinessOperand'; +export * from './turnRecordFilterGroupIntoGqlOperationFilter'; +export * from './turnRecordFilterIntoGqlOperationFilter'; +export * from './utils/combineFilters'; +export * from './utils/fieldRatingConvertors'; +export * from './utils/generateILikeFiltersForCompositeFields'; +export * from './utils/getEmptyRecordGqlOperationFilter'; +export * from './utils/getFilterTypeFromFieldType'; +export * from './utils/isExpectedSubFieldName'; +export * from './utils/resolveDateViewFilterValue'; +export * from './utils/validation-schemas/arrayOfStringsOrVariablesSchema'; +export * from './utils/validation-schemas/arrayOfUuidsOrVariablesSchema'; +export * from './utils/validation-schemas/jsonRelationFilterValueSchema'; + + diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isEmptinessOperand.ts b/packages/twenty-shared/src/utils/filter/isEmptinessOperand.ts similarity index 65% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/isEmptinessOperand.ts rename to packages/twenty-shared/src/utils/filter/isEmptinessOperand.ts index db1b3b03e1..94528ab8ba 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isEmptinessOperand.ts +++ b/packages/twenty-shared/src/utils/filter/isEmptinessOperand.ts @@ -1,4 +1,4 @@ -import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; +import { ViewFilterOperand as RecordFilterOperand } from '@/types'; export const isEmptinessOperand = (operand: RecordFilterOperand): boolean => { return [RecordFilterOperand.IsEmpty, RecordFilterOperand.IsNotEmpty].includes( diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterGroupIntoGqlOperationFilter.ts b/packages/twenty-shared/src/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter.ts similarity index 60% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterGroupIntoGqlOperationFilter.ts rename to packages/twenty-shared/src/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter.ts index bc09020e27..7e4f4e20b0 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterGroupIntoGqlOperationFilter.ts +++ b/packages/twenty-shared/src/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter.ts @@ -1,21 +1,37 @@ -import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; -import { type Field } from '~/generated/graphql'; +import { type CompositeFieldSubFieldName, type FilterableAndTSVectorFieldType, type PartialFieldMetadataItem, RecordFilterGroupLogicalOperator, type RecordFilterValueDependencies, type RecordGqlOperationFilter, type ViewFilterOperand } from '@/types'; -import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { type RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies'; +import { isDefined } from '@/utils'; +import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter'; -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 type RecordFilter = { + id: string; + fieldMetadataId: string; + value: string; + type: FilterableAndTSVectorFieldType; + recordFilterGroupId?: string | null; + operand: ViewFilterOperand; + subFieldName?: CompositeFieldSubFieldName | null | undefined; +}; -export const turnRecordFilterGroupsIntoGqlOperationFilter = ( +export type RecordFilterGroup = { + id: string; + parentRecordFilterGroupId?: string | null; + logicalOperator: RecordFilterGroupLogicalOperator; +} + +export const turnRecordFilterGroupsIntoGqlOperationFilter = ({ + filterValueDependencies, + filters, + fields, + recordFilterGroups, + currentRecordFilterGroupId, +}: { filterValueDependencies: RecordFilterValueDependencies, filters: RecordFilter[], - fields: Pick[], + fields: PartialFieldMetadataItem[], recordFilterGroups: RecordFilterGroup[], currentRecordFilterGroupId?: string, -): RecordGqlOperationFilter | undefined => { +}): RecordGqlOperationFilter | undefined => { const currentRecordFilterGroup = recordFilterGroups.find( (recordFilterGroup) => recordFilterGroup.id === currentRecordFilterGroupId, ); @@ -29,7 +45,7 @@ export const turnRecordFilterGroupsIntoGqlOperationFilter = ( ); const groupRecordGqlOperationFilters = recordFiltersInGroup - .map((recordFilter) => + .map((recordFilter) => turnRecordFilterIntoRecordGqlOperationFilter({ filterValueDependencies, recordFilter: recordFilter, @@ -45,13 +61,13 @@ export const turnRecordFilterGroupsIntoGqlOperationFilter = ( currentRecordFilterGroupId, ) .map((subRecordFilterGroup) => - turnRecordFilterGroupsIntoGqlOperationFilter( + turnRecordFilterGroupsIntoGqlOperationFilter({ filterValueDependencies, filters, fields, recordFilterGroups, - subRecordFilterGroup.id, - ), + currentRecordFilterGroupId: subRecordFilterGroup.id, + }), ) .filter(isDefined); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter.ts b/packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts similarity index 92% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter.ts rename to packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts index 009df00c8e..c9ca89aef2 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/compute-record-gql-operation-filter/turnRecordFilterIntoGqlOperationFilter.ts +++ b/packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts @@ -1,6 +1,8 @@ import { isNonEmptyString } from '@sniptt/guards'; import { + FieldMetadataType, + ViewFilterOperand as RecordFilterOperand, type ActorFilter, type AddressFilter, type ArrayFilter, @@ -12,52 +14,54 @@ import { type PhonesFilter, type RatingFilter, type RawJsonFilter, + type RecordFilterValueDependencies, type RecordGqlOperationFilter, type RelationFilter, type SelectFilter, type StringFilter, type TSVectorFilter, type UUIDFilter, -} from '@/object-record/graphql/types/RecordGqlOperationFilter'; -import { type Field } from '~/generated/graphql'; -import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; +} from '@/types'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { + computeGqlOperationFilterForEmails, + computeGqlOperationFilterForLinks, convertGreaterThanOrEqualRatingToArrayOfRatingValues, convertLessThanOrEqualRatingToArrayOfRatingValues, convertRatingToRatingValue, -} from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput'; -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 { getEmptyRecordGqlOperationFilter } from '@/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter'; + generateILikeFiltersForCompositeFields, getEmptyRecordGqlOperationFilter, + isExpectedSubFieldName, +} from '@/utils/filter'; -import { resolveDateViewFilterValue } from '@/views/view-filter-value/utils/resolveDateViewFilterValue'; -import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema'; +import { resolveDateViewFilterValue } from '@/utils/filter/utils/resolveDateViewFilterValue'; import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns'; import { z } from 'zod'; -import { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName'; -import { checkIfShouldComputeEmptinessFilter } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldComputeEmptinessFilter'; -import { checkIfShouldSkipFiltering } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/checkIfShouldSkipFiltering'; -import { computeGqlOperationFilterForEmails } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails'; -import { computeGqlOperationFilterForLinks } from '@/object-record/record-filter/utils/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks'; -import { arrayOfStringsOrVariablesSchema } from '@/views/view-filter-value/validation-schemas/arrayOfStringsOrVariablesSchema'; -import { arrayOfUuidOrVariableSchema } from '@/views/view-filter-value/validation-schemas/arrayOfUuidsOrVariablesSchema'; -import { FieldMetadataType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { checkIfShouldComputeEmptinessFilter, checkIfShouldSkipFiltering, CustomError, getFilterTypeFromFieldType, isDefined, type RecordFilter } from '@/utils'; +import { arrayOfStringsOrVariablesSchema } from '@/utils/filter/utils/validation-schemas/arrayOfStringsOrVariablesSchema'; +import { arrayOfUuidOrVariableSchema } from '@/utils/filter/utils/validation-schemas/arrayOfUuidsOrVariablesSchema'; +import { jsonRelationFilterValueSchema } from '@/utils/filter/utils/validation-schemas/jsonRelationFilterValueSchema'; + +type FieldShared = { + id: string; + name: string; + type: FieldMetadataType; + label: string; +} type TurnRecordFilterIntoRecordGqlOperationFilterParams = { - filterValueDependencies: RecordFilterValueDependencies; + filterValueDependencies?: RecordFilterValueDependencies; recordFilter: RecordFilter; - fieldMetadataItems: Pick[]; + fieldMetadataItems: FieldShared[]; + recordIdsForUuid?: string[]; }; + export const turnRecordFilterIntoRecordGqlOperationFilter = ({ - filterValueDependencies, recordFilter, fieldMetadataItems, + recordIdsForUuid, + filterValueDependencies, }: TurnRecordFilterIntoRecordGqlOperationFilterParams): | RecordGqlOperationFilter | undefined => { @@ -76,7 +80,7 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ } const shouldComputeEmptinessFilter = checkIfShouldComputeEmptinessFilter({ - recordFilter, + recordFilterOperand: recordFilter.operand, correspondingFieldMetadataItem, }); @@ -116,8 +120,9 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ }, }; default: - throw new Error( + throw new CustomError( `Unknown operand ${recordFilter.operand} for ${filterType} filter`, + 'UNKNOWN_OPERAND_FOR_FILTER', ); } case 'TS_VECTOR': @@ -328,11 +333,11 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ const recordIds = isCurrentWorkspaceMemberSelected ? [ ...selectedRecordIds, - filterValueDependencies.currentWorkspaceMemberId, + filterValueDependencies?.currentWorkspaceMemberId, ] : selectedRecordIds; - if (recordIds.length === 0) return; + if (!isDefined (recordIds) || recordIds.length === 0) return; switch (recordFilter.operand) { case RecordFilterOperand.Is: @@ -342,7 +347,7 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ } as RelationFilter, }; case RecordFilterOperand.IsNot: { - if (recordIds.length === 0) return; + if (!isDefined (recordIds) || recordIds.length === 0) return; return { or: [ { @@ -942,10 +947,15 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ }, }; } - default: - throw new Error( - `Unknown operand ${recordFilter.operand} for ${recordFilter.label} filter`, + default: { + const fieldForRecordFilter = fieldMetadataItems.find( + (field) => field.id === recordFilter.fieldMetadataId, ); + + throw new Error( + `Unknown operand ${recordFilter.operand} for ${fieldForRecordFilter?.label ?? ''} filter`, + ); + } } } @@ -976,10 +986,15 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ }, ], }; - default: - throw new Error( - `Unknown operand ${recordFilter.operand} for ${recordFilter.label} filter`, + default: { + const fieldForRecordFilter = fieldMetadataItems.find( + (field) => field.id === recordFilter.fieldMetadataId, ); + + throw new Error( + `Unknown operand ${recordFilter.operand} for ${fieldForRecordFilter?.label ?? ''} filter`, + ); + } } } case 'EMAILS': { @@ -1184,9 +1199,9 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({ }; } case 'UUID': { - const recordIds = arrayOfUuidOrVariableSchema.parse(recordFilter.value); + const recordIds = recordIdsForUuid; - if (recordIds.length === 0) return; + if (!isDefined (recordIds) || recordIds.length === 0) return; switch (recordFilter.operand) { case RecordFilterOperand.Is: diff --git a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/__tests__/arrayOfStringsOrVariablesSchema.test.ts b/packages/twenty-shared/src/utils/filter/utils/__tests__/arrayOfStringsOrVariablesSchema.test.ts similarity index 95% rename from packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/__tests__/arrayOfStringsOrVariablesSchema.test.ts rename to packages/twenty-shared/src/utils/filter/utils/__tests__/arrayOfStringsOrVariablesSchema.test.ts index c37a2e9093..a7af5ac248 100644 --- a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/__tests__/arrayOfStringsOrVariablesSchema.test.ts +++ b/packages/twenty-shared/src/utils/filter/utils/__tests__/arrayOfStringsOrVariablesSchema.test.ts @@ -1,4 +1,4 @@ -import { arrayOfStringsOrVariablesSchema } from '../arrayOfStringsOrVariablesSchema'; +import { arrayOfStringsOrVariablesSchema } from "@/utils/filter/utils/validation-schemas/arrayOfStringsOrVariablesSchema"; describe('arrayOfStringsOrVariablesSchema', () => { describe('Empty value handling', () => { diff --git a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/__tests__/arrayOfUuidOrVariableSchema.test.ts b/packages/twenty-shared/src/utils/filter/utils/__tests__/arrayOfUuidOrVariableSchema.test.ts similarity index 98% rename from packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/__tests__/arrayOfUuidOrVariableSchema.test.ts rename to packages/twenty-shared/src/utils/filter/utils/__tests__/arrayOfUuidOrVariableSchema.test.ts index f635b5edf5..04668ee53e 100644 --- a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/__tests__/arrayOfUuidOrVariableSchema.test.ts +++ b/packages/twenty-shared/src/utils/filter/utils/__tests__/arrayOfUuidOrVariableSchema.test.ts @@ -1,4 +1,4 @@ -import { arrayOfUuidOrVariableSchema } from '../arrayOfUuidsOrVariablesSchema'; +import { arrayOfUuidOrVariableSchema } from '../validation-schemas/arrayOfUuidsOrVariablesSchema'; describe('arrayOfUuidOrVariableSchema', () => { describe('UUID validation', () => { diff --git a/packages/twenty-front/src/utils/array/__tests__/generateILikeFiltersForCompositeFields.test.ts b/packages/twenty-shared/src/utils/filter/utils/__tests__/generateILikeFiltersForCompositeFields.test.ts similarity index 90% rename from packages/twenty-front/src/utils/array/__tests__/generateILikeFiltersForCompositeFields.test.ts rename to packages/twenty-shared/src/utils/filter/utils/__tests__/generateILikeFiltersForCompositeFields.test.ts index d4b37f60dc..e4ae7a3441 100644 --- a/packages/twenty-front/src/utils/array/__tests__/generateILikeFiltersForCompositeFields.test.ts +++ b/packages/twenty-shared/src/utils/filter/utils/__tests__/generateILikeFiltersForCompositeFields.test.ts @@ -1,4 +1,4 @@ -import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; +import { generateILikeFiltersForCompositeFields } from "@/utils/filter/utils/generateILikeFiltersForCompositeFields"; describe('generateILikeFiltersForCompositeFields', () => { it('should format composite filters for simple filter string', () => { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/combineFilters.ts b/packages/twenty-shared/src/utils/filter/utils/combineFilters.ts similarity index 78% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/combineFilters.ts rename to packages/twenty-shared/src/utils/filter/utils/combineFilters.ts index 569927fc93..1301365fa7 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/combineFilters.ts +++ b/packages/twenty-shared/src/utils/filter/utils/combineFilters.ts @@ -1,4 +1,4 @@ -import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type RecordGqlOperationFilter } from '@/types'; export const combineFilters = ( filters: RecordGqlOperationFilter[], diff --git a/packages/twenty-shared/src/utils/filter/utils/convertViewFilterValueToString.ts b/packages/twenty-shared/src/utils/filter/utils/convertViewFilterValueToString.ts new file mode 100644 index 0000000000..7719942f3f --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/utils/convertViewFilterValueToString.ts @@ -0,0 +1,5 @@ +export const convertViewFilterValueToString = (value: any) => { + return typeof value === 'string' + ? value + : JSON.stringify(value ?? ''); +}; \ No newline at end of file diff --git a/packages/twenty-shared/src/utils/filter/utils/fieldRatingConvertors.ts b/packages/twenty-shared/src/utils/filter/utils/fieldRatingConvertors.ts new file mode 100644 index 0000000000..7900f81714 --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/utils/fieldRatingConvertors.ts @@ -0,0 +1,19 @@ +import { RATING_VALUES } from "@/constants"; +import { type FieldRatingValue } from "@/types"; + +export const convertGreaterThanOrEqualRatingToArrayOfRatingValues = ( + greaterThanValue: number, +) => + RATING_VALUES.filter( + (ratingValue) => +ratingValue.split('_')[1] >= greaterThanValue, + ); + +export const convertLessThanOrEqualRatingToArrayOfRatingValues = ( + lessThanValue: number, +) => + RATING_VALUES.filter( + (ratingValue) => +ratingValue.split('_')[1] <= lessThanValue, + ); + +export const convertRatingToRatingValue = (rating: number) => + `RATING_${rating}` as FieldRatingValue; diff --git a/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts b/packages/twenty-shared/src/utils/filter/utils/generateILikeFiltersForCompositeFields.ts similarity index 90% rename from packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts rename to packages/twenty-shared/src/utils/filter/utils/generateILikeFiltersForCompositeFields.ts index 606051c5a8..b11e4b806b 100644 --- a/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts +++ b/packages/twenty-shared/src/utils/filter/utils/generateILikeFiltersForCompositeFields.ts @@ -1,4 +1,4 @@ -import { type RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { type RecordGqlOperationFilter } from '@/types'; export const generateILikeFiltersForCompositeFields = ( filterString: string, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter.ts b/packages/twenty-shared/src/utils/filter/utils/getEmptyRecordGqlOperationFilter.ts similarity index 90% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter.ts rename to packages/twenty-shared/src/utils/filter/utils/getEmptyRecordGqlOperationFilter.ts index 211a37573a..c7c62d56a5 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/getEmptyRecordGqlOperationFilter.ts +++ b/packages/twenty-shared/src/utils/filter/utils/getEmptyRecordGqlOperationFilter.ts @@ -1,6 +1,5 @@ -import { CustomError } from '@/error-handler/CustomError'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { + ViewFilterOperand, type ActorFilter, type AddressFilter, type ArrayFilter, @@ -8,6 +7,7 @@ import { type DateFilter, type FloatFilter, type MultiSelectFilter, + type PartialFieldMetadataItem, type PhonesFilter, type RatingFilter, type RawJsonFilter, @@ -15,18 +15,18 @@ import { 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'; +} from '@/types'; +import { CustomError } from '@/utils/errors'; +import { computeEmptyGqlOperationFilterForEmails } from '@/utils/filter/computeEmptyGqlOperationFilterForEmails'; +import { computeEmptyGqlOperationFilterForLinks } from '@/utils/filter/computeEmptyGqlOperationFilterForLinks'; +import { type RecordFilter } from '@/utils/filter/turnRecordFilterGroupIntoGqlOperationFilter'; +import { generateILikeFiltersForCompositeFields } from '@/utils/filter/utils/generateILikeFiltersForCompositeFields'; +import { getFilterTypeFromFieldType } from '@/utils/filter/utils/getFilterTypeFromFieldType'; 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; + correspondingField: Pick; recordFilter: RecordFilter; }; @@ -385,7 +385,7 @@ export const getEmptyRecordGqlOperationFilter = ({ }); break; default: - throw new CustomError( + throw new CustomError( `Unsupported empty filter type ${filterType}`, 'UNSUPPORTED_EMPTY_FILTER_TYPE', ); @@ -399,7 +399,7 @@ export const getEmptyRecordGqlOperationFilter = ({ not: emptyRecordFilter, }; default: - throw new CustomError( + throw new CustomError( `Unknown operand ${operand} for ${filterType} filter`, 'UNKNOWN_OPERAND_FOR_FILTER', ); diff --git a/packages/twenty-shared/src/utils/filter/utils/getFilterTypeFromFieldType.ts b/packages/twenty-shared/src/utils/filter/utils/getFilterTypeFromFieldType.ts new file mode 100644 index 0000000000..e1d9642c00 --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/utils/getFilterTypeFromFieldType.ts @@ -0,0 +1,49 @@ +import { FieldMetadataType, type FilterableAndTSVectorFieldType } from "@/types"; + + +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'; + } +}; \ No newline at end of file diff --git a/packages/twenty-shared/src/utils/filter/utils/isExpectedSubFieldName.ts b/packages/twenty-shared/src/utils/filter/utils/isExpectedSubFieldName.ts new file mode 100644 index 0000000000..19c741bce4 --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/utils/isExpectedSubFieldName.ts @@ -0,0 +1,24 @@ +import { COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES } from '@/constants/CompositeFieldTypeSubFieldsNames'; +import { type CompositeFieldSubFieldName } from '@/types'; + +type CompositeMap = typeof COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES; + +export const isExpectedSubFieldName = < + FieldMetadataType extends keyof CompositeMap, + PossibleSubFieldName extends CompositeFieldSubFieldName, +>( + fieldMetadataType: FieldMetadataType, + subFieldName: PossibleSubFieldName, + subFieldNameToCheck: string | null | undefined, +): subFieldNameToCheck is PossibleSubFieldName => { + const allowedSubFields = Object.values(COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES[ + fieldMetadataType + ]) as readonly string[]; + + return ( + allowedSubFields.includes(subFieldName as string) && + subFieldName === subFieldNameToCheck + ); +}; + + diff --git a/packages/twenty-front/src/modules/views/view-filter-value/utils/resolveDateViewFilterValue.ts b/packages/twenty-shared/src/utils/filter/utils/resolveDateViewFilterValue.ts similarity index 95% rename from packages/twenty-front/src/modules/views/view-filter-value/utils/resolveDateViewFilterValue.ts rename to packages/twenty-shared/src/utils/filter/utils/resolveDateViewFilterValue.ts index 9633fdb072..f952cbf631 100644 --- a/packages/twenty-front/src/modules/views/view-filter-value/utils/resolveDateViewFilterValue.ts +++ b/packages/twenty-shared/src/utils/filter/utils/resolveDateViewFilterValue.ts @@ -1,4 +1,4 @@ -import { type ViewFilter } from '@/views/types/ViewFilter'; +import { ViewFilterOperand } from '@/types'; import { addDays, addMonths, @@ -18,7 +18,6 @@ import { subWeeks, subYears, } from 'date-fns'; -import { ViewFilterOperand } from 'twenty-shared/types'; import { z } from 'zod'; const variableDateViewFilterValueDirectionSchema = z.enum([ @@ -170,10 +169,7 @@ export type ResolvedDateViewFilterValue = ? ReturnType : Date | null; -type PartialViewFilter = Pick< - ViewFilter, - 'value' -> & { operand: O }; +type PartialViewFilter = {value: string, operand: O} // TODO, was done to avoid ViewFilter export export const resolveDateViewFilterValue = ( viewFilter: PartialViewFilter, diff --git a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/arrayOfStringsOrVariablesSchema.ts b/packages/twenty-shared/src/utils/filter/utils/validation-schemas/arrayOfStringsOrVariablesSchema.ts similarity index 88% rename from packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/arrayOfStringsOrVariablesSchema.ts rename to packages/twenty-shared/src/utils/filter/utils/validation-schemas/arrayOfStringsOrVariablesSchema.ts index d17ea019ba..17690b4476 100644 --- a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/arrayOfStringsOrVariablesSchema.ts +++ b/packages/twenty-shared/src/utils/filter/utils/validation-schemas/arrayOfStringsOrVariablesSchema.ts @@ -1,4 +1,4 @@ -import { isValidVariable } from 'twenty-shared/utils'; +import { isValidVariable } from '@/utils'; import { z } from 'zod'; export const arrayOfStringsOrVariablesSchema = z diff --git a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/arrayOfUuidsOrVariablesSchema.ts b/packages/twenty-shared/src/utils/filter/utils/validation-schemas/arrayOfUuidsOrVariablesSchema.ts similarity index 91% rename from packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/arrayOfUuidsOrVariablesSchema.ts rename to packages/twenty-shared/src/utils/filter/utils/validation-schemas/arrayOfUuidsOrVariablesSchema.ts index 64b573f19c..16c6128d42 100644 --- a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/arrayOfUuidsOrVariablesSchema.ts +++ b/packages/twenty-shared/src/utils/filter/utils/validation-schemas/arrayOfUuidsOrVariablesSchema.ts @@ -1,4 +1,4 @@ -import { isValidUuid, isValidVariable } from 'twenty-shared/utils'; +import { isValidUuid, isValidVariable } from '@/utils'; import { z } from 'zod'; export const arrayOfUuidOrVariableSchema = z diff --git a/packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema.ts b/packages/twenty-shared/src/utils/filter/utils/validation-schemas/jsonRelationFilterValueSchema.ts similarity index 100% rename from packages/twenty-front/src/modules/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema.ts rename to packages/twenty-shared/src/utils/filter/utils/validation-schemas/jsonRelationFilterValueSchema.ts diff --git a/packages/twenty-shared/src/utils/index.ts b/packages/twenty-shared/src/utils/index.ts index d8651c8a72..27f97d77b6 100644 --- a/packages/twenty-shared/src/utils/index.ts +++ b/packages/twenty-shared/src/utils/index.ts @@ -16,8 +16,50 @@ export { sumByProperty } from './array/sumByProperty'; export { assertUnreachable } from './assertUnreachable'; export { computeDiffBetweenObjects } from './compute-diff-between-objects'; export { deepMerge } from './deepMerge'; +export { CustomError } from './errors/CustomError'; export { extractAndSanitizeObjectStringFields } from './extractAndSanitizeObjectStringFields'; export { isFieldMetadataDateKind } from './fieldMetadata/isFieldMetadataDateKind'; +export { checkIfShouldComputeEmptinessFilter } from './filter/checkIfShouldComputeEmptinessFilter'; +export { checkIfShouldSkipFiltering } from './filter/checkIfShouldSkipFiltering'; +export { computeGqlOperationFilterForEmails } from './filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails'; +export { computeGqlOperationFilterForLinks } from './filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks'; +export { computeEmptyGqlOperationFilterForEmails } from './filter/computeEmptyGqlOperationFilterForEmails'; +export { computeEmptyGqlOperationFilterForLinks } from './filter/computeEmptyGqlOperationFilterForLinks'; +export { computeRecordGqlOperationFilter } from './filter/computeRecordGqlOperationFilter'; +export { isEmptinessOperand } from './filter/isEmptinessOperand'; +export type { + RecordFilter, + RecordFilterGroup, +} from './filter/turnRecordFilterGroupIntoGqlOperationFilter'; +export { turnRecordFilterGroupsIntoGqlOperationFilter } from './filter/turnRecordFilterGroupIntoGqlOperationFilter'; +export { turnRecordFilterIntoRecordGqlOperationFilter } from './filter/turnRecordFilterIntoGqlOperationFilter'; +export { combineFilters } from './filter/utils/combineFilters'; +export { convertViewFilterValueToString } from './filter/utils/convertViewFilterValueToString'; +export { + convertGreaterThanOrEqualRatingToArrayOfRatingValues, + convertLessThanOrEqualRatingToArrayOfRatingValues, + convertRatingToRatingValue, +} from './filter/utils/fieldRatingConvertors'; +export { generateILikeFiltersForCompositeFields } from './filter/utils/generateILikeFiltersForCompositeFields'; +export { getEmptyRecordGqlOperationFilter } from './filter/utils/getEmptyRecordGqlOperationFilter'; +export { getFilterTypeFromFieldType } from './filter/utils/getFilterTypeFromFieldType'; +export { isExpectedSubFieldName } from './filter/utils/isExpectedSubFieldName'; +export type { + VariableDateViewFilterValueDirection, + VariableDateViewFilterValueUnit, + ResolvedDateViewFilterValue, +} from './filter/utils/resolveDateViewFilterValue'; +export { + variableDateViewFilterValueUnitSchema, + variableDateViewFilterValuePartsSchema, + resolveDateViewFilterValue, +} from './filter/utils/resolveDateViewFilterValue'; +export { arrayOfStringsOrVariablesSchema } from './filter/utils/validation-schemas/arrayOfStringsOrVariablesSchema'; +export { arrayOfUuidOrVariableSchema } from './filter/utils/validation-schemas/arrayOfUuidsOrVariablesSchema'; +export { + relationFilterValueSchemaObject, + jsonRelationFilterValueSchema, +} from './filter/utils/validation-schemas/jsonRelationFilterValueSchema'; export { fromArrayToUniqueKeyRecord } from './from-array-to-unique-key-record.util'; export { fromArrayToValuesByKeyRecord } from './fromArrayToValuesByKeyRecord.util'; export { getURLSafely } from './getURLSafely';