From f33396e425da06679e0de3ede0fb7ee488be064e Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Tue, 30 Sep 2025 18:13:40 +0200 Subject: [PATCH] [GroupBy] Add views filters to groupBy query 2/2: handle anyFieldFilter (#14791) Following https://github.com/twentyhq/twenty/pull/14762 In this PR - moved logic around any field filter formatting to twenty-shared - added any field filter to the filters applied to groupBy when viewId is defined - added integration test --- .../utils/computeContextStoreFilters.ts | 8 +- .../types/FieldMetadataItem.ts | 7 +- ...useGenerateCombinedFindManyRecordsQuery.ts | 3 +- ...teCombinedFindManyRecordsQueryVariables.ts | 3 +- .../components/FormCurrencyFieldInput.tsx | 2 +- .../FormCurrencyFieldInput.stories.tsx | 2 +- .../input/components/CurrencyFieldInput.tsx | 2 +- .../record-field/ui/types/CurrencyCode.ts | 155 -------- .../ui/types/FieldInputDraftValue.ts | 2 +- .../record-field/ui/types/FieldMetadata.ts | 2 +- .../ui/types/guards/isFieldCurrencyValue.ts | 2 +- .../ui/utils/computeDraftValueFromString.ts | 2 +- .../ui/utils/computeEmptyDraftValue.ts | 2 +- .../validation-schemas/currencyCodeSchema.ts | 2 +- .../currencyFieldDefaultValueSchema.ts | 2 +- ...reateAnyFieldRecordFilterBaseProperties.ts | 22 -- .../useFindManyRecordIndexTableParams.ts | 4 +- .../hooks/useLoadRecordIndexBoardColumn.ts | 4 +- .../hooks/useAggregateRecordsForHeader.ts | 4 +- ...egateRecordsForRecordTableColumnFooter.tsx | 4 +- .../components/RecordTableCellsVisible.tsx | 3 +- .../SettingsCompositeFieldTypeConfigs.ts | 6 +- .../constants/SettingsFieldCurrencyCodes.ts | 336 ++++++++++-------- .../useCurrencySettingsFormInitialValues.ts | 2 +- .../getCurrencyFieldPreviewValue.test.ts | 2 +- .../utils/getCurrencyFieldPreviewValue.ts | 2 +- ...sObjectLevelObjectFieldPermissionTable.tsx | 2 +- .../roles/role/hooks/useSaveDraftRoleToDB.ts | 9 +- .../CurrencyPickerDropdownButton.tsx | 2 +- .../internal/useGetRecordIndexTotalCount.ts | 8 +- ...graphql-query-group-by-resolver.service.ts | 27 +- .../group-by-resolvers.integration-spec.ts | 141 ++++++-- .../src/constants/CurrencyCode.ts | 156 ++++++++ .../src/constants/CurrencyCodeLabels.ts | 160 +++++++++ packages/twenty-shared/src/constants/index.ts | 2 + .../src/types/PartialFieldMetadataItem.ts | 2 + .../src/types/PartialFieldMetadataOption.ts | 7 + packages/twenty-shared/src/types/index.ts | 1 + .../utils/__tests__/isNonEmptyArray.test.ts | 2 +- .../src/utils/array}/isNonEmptyArray.ts | 0 .../twenty-shared/src/utils/filter/index.ts | 1 + .../turnAnyFieldFilterIntoRecordGqlFilter.ts | 96 ++--- ...nAnyFieldFilterIntoRecordGqlFilter.test.ts | 125 ++----- ...reateAnyFieldRecordFilterBaseProperties.ts | 20 ++ .../filterSelectOptionsOfFieldMetadataItem.ts | 4 +- packages/twenty-shared/src/utils/index.ts | 4 + 46 files changed, 805 insertions(+), 549 deletions(-) delete mode 100644 packages/twenty-front/src/modules/object-record/record-field/ui/types/CurrencyCode.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-filter/utils/createAnyFieldRecordFilterBaseProperties.ts create mode 100644 packages/twenty-shared/src/constants/CurrencyCode.ts create mode 100644 packages/twenty-shared/src/constants/CurrencyCodeLabels.ts create mode 100644 packages/twenty-shared/src/types/PartialFieldMetadataOption.ts rename packages/{twenty-front => twenty-shared}/src/utils/__tests__/isNonEmptyArray.test.ts (88%) rename packages/{twenty-front/src/utils => twenty-shared/src/utils/array}/isNonEmptyArray.ts (100%) rename packages/{twenty-front/src/modules/object-record/record-filter/utils => twenty-shared/src/utils/filter}/turnAnyFieldFilterIntoRecordGqlFilter.ts (70%) rename packages/{twenty-front/src/modules/object-record/record-filter => twenty-shared/src/utils/filter}/utils/__tests__/turnAnyFieldFilterIntoRecordGqlFilter.test.ts (78%) create mode 100644 packages/twenty-shared/src/utils/filter/utils/createAnyFieldRecordFilterBaseProperties.ts rename packages/{twenty-front/src/modules/object-record/record-filter => twenty-shared/src/utils/filter}/utils/filterSelectOptionsOfFieldMetadataItem.ts (81%) 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 9b1ef96aa41..f37e60f9a17 100644 --- a/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts +++ b/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts @@ -2,13 +2,15 @@ import { type ContextStoreTargetedRecordsRule } from '@/context-store/states/con import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -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'; +import { + computeRecordGqlOperationFilter, + turnAnyFieldFilterIntoRecordGqlFilter, +} from 'twenty-shared/utils'; type ComputeContextStoreFiltersProps = { contextStoreTargetedRecordsRule: ContextStoreTargetedRecordsRule; @@ -32,7 +34,7 @@ export const computeContextStoreFilters = ({ const { recordGqlOperationFilter: recordGqlFilterForAnyFieldFilter } = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue: contextStoreAnyFieldFilterValue, - objectMetadataItem, + fields: objectMetadataItem.fields, }); if (contextStoreTargetedRecordsRule.mode === 'exclusion') { diff --git a/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts index 319a3ebc3c6..b6e1e42a40d 100644 --- a/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/types/FieldMetadataItem.ts @@ -1,15 +1,12 @@ import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation'; import { type FieldDateMetadataSettings } from '@/object-record/record-field/ui/types/FieldMetadata'; +import { type PartialFieldMetadataItemOption } from 'twenty-shared/types'; import { type ThemeColor } from 'twenty-ui/theme'; import { type Field } from '~/generated-metadata/graphql'; -export type FieldMetadataItemOption = { +export type FieldMetadataItemOption = PartialFieldMetadataItemOption & { color: ThemeColor; - id: string; - label: string; - position: number; - value: string; }; export type FieldMetadataItem = Omit< diff --git a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts index 8d07c42bf65..b9597832083 100644 --- a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts @@ -1,5 +1,5 @@ import { gql } from '@apollo/client'; -import { isUndefined } from '@sniptt/guards'; +import { isNonEmptyArray, isUndefined } from '@sniptt/guards'; import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; @@ -11,7 +11,6 @@ import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions import { getCombinedFindManyRecordsQueryFilteringPart } from '@/object-record/multiple-objects/utils/getCombinedFindManyRecordsQueryFilteringPart'; import isEmpty from 'lodash.isempty'; import { capitalize } from 'twenty-shared/utils'; -import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; export const useGenerateCombinedFindManyRecordsQuery = ({ operationSignatures, diff --git a/packages/twenty-front/src/modules/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables.ts b/packages/twenty-front/src/modules/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables.ts index c13d922db4d..f067aab636d 100644 --- a/packages/twenty-front/src/modules/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables.ts +++ b/packages/twenty-front/src/modules/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables.ts @@ -1,7 +1,6 @@ import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; import { isNonEmptyString } from '@sniptt/guards'; -import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; -import { capitalize, isDefined } from 'twenty-shared/utils'; +import { capitalize, isDefined, isNonEmptyArray } from 'twenty-shared/utils'; export const generateCombinedFindManyRecordsQueryVariables = ({ operationSignatures, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormCurrencyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormCurrencyFieldInput.tsx index 2a84033ad8c..c664184c107 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormCurrencyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormCurrencyFieldInput.tsx @@ -3,11 +3,11 @@ import { FormNestedFieldInputContainer } from '@/object-record/record-field/ui/f import { FormNumberFieldInput } from '@/object-record/record-field/ui/form-types/components/FormNumberFieldInput'; import { FormSelectFieldInput } from '@/object-record/record-field/ui/form-types/components/FormSelectFieldInput'; import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent'; -import { type CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { type FormFieldCurrencyValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { CURRENCIES } from '@/settings/data-model/constants/Currencies'; import { InputLabel } from '@/ui/input/components/InputLabel'; import { useMemo } from 'react'; +import { type CurrencyCode } from 'twenty-shared/constants'; import { IconCircleOff } from 'twenty-ui/display'; type FormCurrencyFieldInputProps = { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormCurrencyFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormCurrencyFieldInput.stories.tsx index fe47bec9e9c..89dcbed214c 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormCurrencyFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormCurrencyFieldInput.stories.tsx @@ -1,7 +1,7 @@ -import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { type FieldCurrencyValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { type Meta, type StoryObj } from '@storybook/react'; import { expect, within } from '@storybook/test'; +import { CurrencyCode } from 'twenty-shared/constants'; import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator'; import { MOCKED_STEP_ID } from '~/testing/mock-data/workflow'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/CurrencyFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/CurrencyFieldInput.tsx index b51b8bb8e22..6a2252009d2 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/CurrencyFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/CurrencyFieldInput.tsx @@ -1,8 +1,8 @@ import { isNonEmptyString } from '@sniptt/guards'; -import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { type FieldCurrencyValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { CurrencyInput } from '@/ui/field/input/components/CurrencyInput'; +import { CurrencyCode } from 'twenty-shared/constants'; import { useCurrencyField } from '../../hooks/useCurrencyField'; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/types/CurrencyCode.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/types/CurrencyCode.ts deleted file mode 100644 index 48e49d4102b..00000000000 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/types/CurrencyCode.ts +++ /dev/null @@ -1,155 +0,0 @@ -export enum CurrencyCode { - AED = 'AED', - AFN = 'AFN', - ALL = 'ALL', - AMD = 'AMD', - ANG = 'ANG', - AOA = 'AOA', - ARS = 'ARS', - AUD = 'AUD', - AWG = 'AWG', - AZN = 'AZN', - BAM = 'BAM', - BBD = 'BBD', - BDT = 'BDT', - BGN = 'BGN', - BHD = 'BHD', - BIF = 'BIF', - BMD = 'BMD', - BND = 'BND', - BOB = 'BOB', - BRL = 'BRL', - BSD = 'BSD', - BTN = 'BTN', - BWP = 'BWP', - BYN = 'BYN', - BZD = 'BZD', - CAD = 'CAD', - CDF = 'CDF', - CHF = 'CHF', - CLP = 'CLP', - CNY = 'CNY', - COP = 'COP', - CRC = 'CRC', - CUP = 'CUP', - CVE = 'CVE', - CZK = 'CZK', - DJF = 'DJF', - DKK = 'DKK', - DOP = 'DOP', - DZD = 'DZD', - EGP = 'EGP', - ERN = 'ERN', - ETB = 'ETB', - EUR = 'EUR', - FJD = 'FJD', - FKP = 'FKP', - GBP = 'GBP', - GEL = 'GEL', - GHS = 'GHS', - GIP = 'GIP', - GMD = 'GMD', - GNF = 'GNF', - GTQ = 'GTQ', - GYD = 'GYD', - HKD = 'HKD', - HNL = 'HNL', - HTG = 'HTG', - HUF = 'HUF', - IDR = 'IDR', - ILS = 'ILS', - INR = 'INR', - IQD = 'IQD', - IRR = 'IRR', - ISK = 'ISK', - JMD = 'JMD', - JOD = 'JOD', - JPY = 'JPY', - KES = 'KES', - KGS = 'KGS', - KHR = 'KHR', - KMF = 'KMF', - KPW = 'KPW', - KRW = 'KRW', - KWD = 'KWD', - KYD = 'KYD', - KZT = 'KZT', - LAK = 'LAK', - LBP = 'LBP', - LKR = 'LKR', - LRD = 'LRD', - LSL = 'LSL', - LYD = 'LYD', - MAD = 'MAD', - MDL = 'MDL', - MGA = 'MGA', - MKD = 'MKD', - MMK = 'MMK', - MNT = 'MNT', - MOP = 'MOP', - MRU = 'MRU', - MUR = 'MUR', - MVR = 'MVR', - MWK = 'MWK', - MXN = 'MXN', - MYR = 'MYR', - MZN = 'MZN', - NAD = 'NAD', - NGN = 'NGN', - NIO = 'NIO', - NOK = 'NOK', - NPR = 'NPR', - NZD = 'NZD', - OMR = 'OMR', - PAB = 'PAB', - PEN = 'PEN', - PGK = 'PGK', - PHP = 'PHP', - PKR = 'PKR', - PLN = 'PLN', - PYG = 'PYG', - QAR = 'QAR', - RON = 'RON', - RSD = 'RSD', - RUB = 'RUB', - RWF = 'RWF', - SAR = 'SAR', - SBD = 'SBD', - SCR = 'SCR', - SDG = 'SDG', - SEK = 'SEK', - SGD = 'SGD', - SHP = 'SHP', - SLE = 'SLE', - SOS = 'SOS', - SRD = 'SRD', - SSP = 'SSP', - STN = 'STN', - SVC = 'SVC', - SYP = 'SYP', - SZL = 'SZL', - THB = 'THB', - TJS = 'TJS', - TMT = 'TMT', - TND = 'TND', - TOP = 'TOP', - TRY = 'TRY', - TTD = 'TTD', - TWD = 'TWD', - TZS = 'TZS', - UAH = 'UAH', - UGX = 'UGX', - USD = 'USD', - UYU = 'UYU', - UZS = 'UZS', - VES = 'VES', - VND = 'VND', - VUV = 'VUV', - WST = 'WST', - XCD = 'XCD', - XOF = 'XOF', - YER = 'YER', - ZAR = 'ZAR', - ZMW = 'ZMW', - ZWG = 'ZWG', -} 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 ea986e64327..f40baedab82 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 @@ -1,4 +1,3 @@ -import { type CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { type FieldActorValue, type FieldAddressValue, @@ -19,6 +18,7 @@ import { type FieldUUidValue, type PhoneRecord, } from '@/object-record/record-field/ui/types/FieldMetadata'; +import { type CurrencyCode } from 'twenty-shared/constants'; import { type FieldRatingValue } from 'twenty-shared/types'; export type FieldTextDraftValue = string; 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 9103fde6c20..45b73840d00 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,6 +1,7 @@ import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation'; import { type ZodHelperLiteral } from '@/object-record/record-field/ui/types/ZodHelperLiteral'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { type CurrencyCode } from 'twenty-shared/constants'; import { ConnectedAccountProvider, type AllowedAddressSubField, @@ -8,7 +9,6 @@ import { import { type ThemeColor } from 'twenty-ui/theme'; import { z } from 'zod'; import { type RelationType } from '~/generated-metadata/graphql'; -import { type CurrencyCode } from './CurrencyCode'; type BaseFieldMetadata = { fieldName: string; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldCurrencyValue.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldCurrencyValue.ts index ae2d006f5f7..eb9e6ff1c69 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldCurrencyValue.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/types/guards/isFieldCurrencyValue.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { CurrencyCode } from '../CurrencyCode'; +import { CurrencyCode } from 'twenty-shared/constants'; import { type FieldCurrencyValue } from '../FieldMetadata'; const currencySchema = z.object({ 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 774b0d2cec6..c610258ecad 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 { 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'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; @@ -13,6 +12,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 { CurrencyCode } from 'twenty-shared/constants'; import { CustomError } from 'twenty-shared/utils'; type computeDraftValueFromStringParams = { 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 398fb31bf10..d0a7ced4190 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 { 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'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; @@ -12,6 +11,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 { CurrencyCode } from 'twenty-shared/constants'; import { CustomError } from 'twenty-shared/utils'; type computeEmptyDraftValueParams = { diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyCodeSchema.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyCodeSchema.ts index 90dd9710198..e6353371162 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyCodeSchema.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyCodeSchema.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; +import { CurrencyCode } from 'twenty-shared/constants'; export const currencyCodeSchema = z.enum(CurrencyCode); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyFieldDefaultValueSchema.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyFieldDefaultValueSchema.ts index f1ceca165c7..549c3396602 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyFieldDefaultValueSchema.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/validation-schemas/currencyFieldDefaultValueSchema.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; -import { type CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { currencyCodeSchema } from '@/object-record/record-field/ui/validation-schemas/currencyCodeSchema'; +import { type CurrencyCode } from 'twenty-shared/constants'; import { stripSimpleQuotesFromString } from '~/utils/string/stripSimpleQuotesFromString'; import { simpleQuotesStringSchema } from '~/utils/validation-schemas/simpleQuotesStringSchema'; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/createAnyFieldRecordFilterBaseProperties.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/createAnyFieldRecordFilterBaseProperties.ts deleted file mode 100644 index 18c3e6a5073..00000000000 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/createAnyFieldRecordFilterBaseProperties.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { v4 } from 'uuid'; - -export const createAnyFieldRecordFilterBaseProperties = ({ - filterValue, - fieldMetadataItem, -}: { - filterValue: string; - fieldMetadataItem: FieldMetadataItem; -}): Pick< - RecordFilter, - 'id' | 'value' | 'displayValue' | 'label' | 'fieldMetadataId' -> => { - return { - id: v4(), - value: filterValue, - displayValue: '', - label: '', - fieldMetadataId: fieldMetadataItem.id, - }; -}; 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 956e71b5028..8b2ea75c5a6 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,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 { 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'; @@ -12,6 +11,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho import { combineFilters, computeRecordGqlOperationFilter, + turnAnyFieldFilterIntoRecordGqlFilter, } from 'twenty-shared/utils'; export const useFindManyRecordIndexTableParams = ( objectNameSingular: string, @@ -53,7 +53,7 @@ export const useFindManyRecordIndexTableParams = ( const { recordGqlOperationFilter: anyFieldFilter } = turnAnyFieldFilterIntoRecordGqlFilter({ - objectMetadataItem, + fields: objectMetadataItem?.fields ?? [], filterValue: anyFieldFilterValue, }); 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 dbaead8be54..8a083ab5a19 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 @@ -15,13 +15,13 @@ 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 { 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 { combineFilters, computeRecordGqlOperationFilter, isDefined, + turnAnyFieldFilterIntoRecordGqlFilter, } from 'twenty-shared/utils'; type UseLoadRecordIndexBoardProps = { @@ -74,7 +74,7 @@ export const useLoadRecordIndexBoardColumn = ({ const { recordGqlOperationFilter: anyFieldFilter } = turnAnyFieldFilterIntoRecordGqlFilter({ - objectMetadataItem, + fields: objectMetadataItem.fields, filterValue: anyFieldFilterValue, }); 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 09543c23169..2a59db84a75 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,7 +6,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 { 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'; @@ -15,6 +14,7 @@ import { useRecoilValue } from 'recoil'; import { computeRecordGqlOperationFilter, isDefined, + turnAnyFieldFilterIntoRecordGqlFilter, } from 'twenty-shared/utils'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; @@ -64,7 +64,7 @@ export const useAggregateRecordsForHeader = ({ const { recordGqlOperationFilter: anyFieldFilter } = turnAnyFieldFilterIntoRecordGqlFilter({ - objectMetadataItem, + fields: objectMetadataItem.fields, filterValue: anyFieldFilterValue, }); 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 a2aa0c41049..36c76f18960 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 { 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'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; @@ -20,6 +19,7 @@ import { computeRecordGqlOperationFilter, isDefined, isFieldMetadataDateKind, + turnAnyFieldFilterIntoRecordGqlFilter, } from 'twenty-shared/utils'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; @@ -96,7 +96,7 @@ export const useAggregateRecordsForRecordTableColumnFooter = ( const { recordGqlOperationFilter: anyFieldFilter } = turnAnyFieldFilterIntoRecordGqlFilter({ - objectMetadataItem, + fields: objectMetadataItem.fields, filterValue: anyFieldFilterValue, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx index c6e2d9d8f8e..6e548269f42 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx @@ -8,8 +8,7 @@ import { RecordTableCellStyleWrapper } from '@/object-record/record-table/record import { RecordTableCellWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellWrapper'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { isDefined } from 'twenty-shared/utils'; -import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; +import { isDefined, isNonEmptyArray } from 'twenty-shared/utils'; export const RecordTableCellsVisible = () => { const { isSelected, rowIndex } = useRecordTableRowContextOrThrow(); 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 72d890d3736..07271bf318d 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 @@ -1,4 +1,3 @@ -import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { type FieldActorValue, type FieldAddressValue, @@ -12,7 +11,10 @@ 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 { + COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES, + CurrencyCode, +} from 'twenty-shared/constants'; import { ConnectedAccountProvider } from 'twenty-shared/types'; import { IllustrationIconCurrency, diff --git a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts index 4f448dd697c..960a397b930 100644 --- a/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts +++ b/packages/twenty-front/src/modules/settings/data-model/constants/SettingsFieldCurrencyCodes.ts @@ -1,4 +1,7 @@ -import { type CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; +import { + CURRENCY_CODE_LABELS, + type CurrencyCode, +} from 'twenty-shared/constants'; import { IconCoins, IconCurrencyAfghani, @@ -53,162 +56,185 @@ import { IconCurrencyZloty, type IconComponent, } from 'twenty-ui/display'; - export const SETTINGS_FIELD_CURRENCY_CODES: Record< CurrencyCode, { label: string; Icon: IconComponent } > = { - AED: { label: 'UAE dirham', Icon: IconCurrencyDirham }, - AFN: { label: 'Afghan afghani', Icon: IconCurrencyAfghani }, - ALL: { label: 'Albanian lek', Icon: IconCurrencyLeu }, - AMD: { label: 'Armenian dram', Icon: IconCurrencyDram }, - ANG: { label: 'Netherlands Antillean guilder', Icon: IconCurrencyFlorin }, - AOA: { label: 'Angolan kwanza', Icon: IconCoins }, - ARS: { label: 'Argentine peso', Icon: IconCoins }, - AUD: { label: 'Australian dollar', Icon: IconCurrencyDollarAustralian }, - AWG: { label: 'Aruban florin', Icon: IconCurrencyFlorin }, - AZN: { label: 'Azerbaijani manat', Icon: IconCurrencyManat }, - BAM: { label: 'Bosnia and Herzegovina mark', Icon: IconCoins }, - BBD: { label: 'Barbados dollar', Icon: IconCurrencyDollar }, - BDT: { label: 'Bangladeshi taka', Icon: IconCurrencyTaka }, - BGN: { label: 'Bulgarian lev', Icon: IconCoins }, - BHD: { label: 'Bahraini dinar', Icon: IconCurrencyBahraini }, - BIF: { label: 'Burundian franc', Icon: IconCoins }, - BMD: { label: 'Bermudian dollar', Icon: IconCurrencyDollar }, - BND: { label: 'Brunei dollar', Icon: IconCurrencyDollarBrunei }, - BOB: { label: 'Boliviano', Icon: IconCoins }, - BRL: { label: 'Brazilian real', Icon: IconCurrencyReal }, - BSD: { label: 'Bahamian dollar', Icon: IconCurrencyDollar }, - BTN: { label: 'Bhutanese ngultrum', Icon: IconCurrencyDollar }, - BWP: { label: 'Botswana pula', Icon: IconCoins }, - BYN: { label: 'Belarusian ruble', Icon: IconCoins }, - BZD: { label: 'Belize dollar', Icon: IconCurrencyDollar }, - CAD: { label: 'Canadian dollar', Icon: IconCurrencyDollarCanadian }, - CDF: { label: 'Congolese franc', Icon: IconCoins }, - CHF: { label: 'Swiss franc', Icon: IconCurrencyFrank }, - CLP: { label: 'Chilean peso', Icon: IconCoins }, - CNY: { label: 'Chinese yuan', Icon: IconCurrencyYuan }, - COP: { label: 'Colombian peso', Icon: IconCoins }, - CRC: { label: 'Costa Rican colon', Icon: IconCoins }, - CUP: { label: 'Cuban peso', Icon: IconCoins }, - CVE: { label: 'Cape Verdean escudo', Icon: IconCoins }, - CZK: { label: 'Czech koruna', Icon: IconCurrencyKroneCzech }, - DJF: { label: 'Djiboutian franc', Icon: IconCoins }, - DKK: { label: 'Danish krone', Icon: IconCurrencyKroneDanish }, - DOP: { label: 'Dominican peso', Icon: IconCoins }, - DZD: { label: 'Algerian Dinar', Icon: IconCoins }, - EGP: { label: 'Egyptian pound', Icon: IconCoins }, - ERN: { label: 'Eritrean nakfa', Icon: IconCoins }, - ETB: { label: 'Ethiopian birr', Icon: IconCoins }, - EUR: { label: 'Euro', Icon: IconCurrencyEuro }, - FJD: { label: 'Fiji dollar', Icon: IconCurrencyDollar }, - FKP: { label: 'Falkland Islands pound', Icon: IconCoins }, - GBP: { label: 'British pound', Icon: IconCurrencyPound }, - GEL: { label: 'Georgian lari', Icon: IconCurrencyLari }, - GHS: { label: 'Ghanaian cedi', Icon: IconCoins }, - GIP: { label: 'Gibraltar pound', Icon: IconCoins }, - GMD: { label: 'Gambian dalasi', Icon: IconCoins }, - GNF: { label: 'Guinean franc', Icon: IconCoins }, - GTQ: { label: 'Guatemalan quetzal', Icon: IconCurrencyQuetzal }, - GYD: { label: 'Guyanese dollar', Icon: IconCurrencyDollarGuyanese }, - HKD: { label: 'Hong Kong dollar', Icon: IconCurrencyRenminbi }, - HNL: { label: 'Honduran lempira', Icon: IconCurrencyLeu }, - HTG: { label: 'Haitian gourde', Icon: IconCoins }, - HUF: { label: 'Hungarian forint', Icon: IconCurrencyForint }, - IDR: { label: 'Indonesian rupiah', Icon: IconCoins }, - ILS: { label: 'Israeli shekel', Icon: IconCurrencyShekel }, - INR: { label: 'Indian rupee', Icon: IconCurrencyRupee }, - IQD: { label: 'Iraqi dinar', Icon: IconCoins }, - IRR: { label: 'Iranian rial', Icon: IconCurrencyIranianRial }, - ISK: { label: 'Icelandic króna', Icon: IconCoins }, - JMD: { label: 'Jamaican dollar', Icon: IconCurrencyDollar }, - JOD: { label: 'Jordanian dinar', Icon: IconCoins }, - JPY: { label: 'Japanese yen', Icon: IconCurrencyYen }, - KES: { label: 'Kenyan shilling', Icon: IconCoins }, - KGS: { label: 'Kyrgyzstani som', Icon: IconCurrencySom }, - KHR: { label: 'Cambodian riel', Icon: IconCoins }, - KMF: { label: 'Comoro franc', Icon: IconCoins }, - KPW: { label: 'North Korean won', Icon: IconCurrencyWon }, - KRW: { label: 'South Korean won', Icon: IconCurrencyWon }, - KWD: { label: 'Kuwaiti dinar', Icon: IconCurrencyDinar }, - KYD: { label: 'Cayman Islands dollar', Icon: IconCurrencyDollar }, - KZT: { label: 'Kazakhstani tenge', Icon: IconCurrencyTenge }, - LAK: { label: 'Lao kip', Icon: IconCurrencyKip }, - LBP: { label: 'Lebanese pound', Icon: IconCoins }, - LKR: { label: 'Sri Lankan rupee', Icon: IconCoins }, - LRD: { label: 'Liberian dollar', Icon: IconCurrencyDollar }, - LSL: { label: 'Lesotho loti', Icon: IconCurrencyLeu }, - LYD: { label: 'Libyan dinar', Icon: IconCurrencyLyd }, - MAD: { label: 'Moroccan dirham', Icon: IconCurrencyDirham }, - MDL: { label: 'Moldovan leu', Icon: IconCurrencyLeu }, - MGA: { label: 'Malagasy ariary', Icon: IconCoins }, - MKD: { label: 'Macedonian denar', Icon: IconCoins }, - MMK: { label: 'Myanmar kyat', Icon: IconCoins }, - MNT: { label: 'Mongolian tögrög', Icon: IconCurrencyTugrik }, - MOP: { label: 'Macanese pataca', Icon: IconCurrencyRenminbi }, - MRU: { label: 'Mauritanian ouguiya', Icon: IconCoins }, - MUR: { label: 'Mauritian rupee', Icon: IconCoins }, - MVR: { label: 'Maldivian rufiyaa', Icon: IconCurrencyRufiyaa }, - MWK: { label: 'Malawian kwacha', Icon: IconCoins }, - MXN: { label: 'Mexican peso', Icon: IconCoins }, - MYR: { label: 'Malaysian ringgit', Icon: IconCoins }, - MZN: { label: 'Mozambican metical', Icon: IconCoins }, - NAD: { label: 'Namibian dollar', Icon: IconCurrencyDollar }, - NGN: { label: 'Nigerian naira', Icon: IconCurrencyNaira }, - NIO: { label: 'Nicaraguan córdoba', Icon: IconCoins }, - NOK: { label: 'Norwegian krone', Icon: IconCurrencyKroneSwedish }, - NPR: { label: 'Nepalese rupee', Icon: IconCurrencyRupeeNepalese }, - NZD: { label: 'New Zealand dollar', Icon: IconCurrencyDollar }, - OMR: { label: 'Omani rial', Icon: IconCoins }, - PAB: { label: 'Panamanian balboa', Icon: IconCoins }, - PEN: { label: 'Peruvian sol', Icon: IconCoins }, - PGK: { label: 'Papua New Guinean kina', Icon: IconCoins }, - PHP: { label: 'Philippine peso', Icon: IconCurrencyPeso }, - PKR: { label: 'Pakistani rupee', Icon: IconCoins }, - PLN: { label: 'Polish złoty', Icon: IconCurrencyZloty }, - PYG: { label: 'Paraguayan guaraní', Icon: IconCurrencyGuarani }, - QAR: { label: 'Qatari riyal', Icon: IconCurrencyRiyal }, - RON: { label: 'Romanian leu', Icon: IconCurrencyLeu }, - RSD: { label: 'Serbian dinar', Icon: IconCoins }, - RUB: { label: 'Russian ruble', Icon: IconCurrencyRubel }, - RWF: { label: 'Rwandan franc', Icon: IconCoins }, - SAR: { label: 'Saudi riyal', Icon: IconCoins }, - SBD: { label: 'Solomon Islands dollar', Icon: IconCurrencyDollar }, - SCR: { label: 'Seychelles rupee', Icon: IconCoins }, - SDG: { label: 'Sudanese pound', Icon: IconCoins }, - SEK: { label: 'Swedish krona', Icon: IconCurrencyKroneSwedish }, - SGD: { label: 'Singapore dollar', Icon: IconCurrencyDollarSingapore }, - SHP: { label: 'Saint Helena pound', Icon: IconCoins }, - SLE: { label: 'Sierra Leonean leone', Icon: IconCoins }, - SOS: { label: 'Somalian shilling', Icon: IconCoins }, - SRD: { label: 'Surinamese dollar', Icon: IconCurrencyDollar }, - SSP: { label: 'South Sudanese pound', Icon: IconCoins }, - STN: { label: 'São Tomé and Príncipe dobra', Icon: IconCoins }, - SVC: { label: 'Salvadoran colón', Icon: IconCoins }, - SYP: { label: 'Syrian pound', Icon: IconCoins }, - SZL: { label: 'Swazi lilangeni', Icon: IconCurrencyLeu }, - THB: { label: 'Thai Baht', Icon: IconCurrencyBaht }, - TJS: { label: 'Tajikistani somoni', Icon: IconCoins }, - TMT: { label: 'Turkmenistan manat', Icon: IconCurrencyManat }, - TND: { label: 'Tunisian dinar', Icon: IconCoins }, - TOP: { label: 'Tongan paʻanga', Icon: IconCurrencyPaanga }, - TRY: { label: 'Turkish lira', Icon: IconCurrencyLira }, - TTD: { label: 'Trinidad and Tobago dollar', Icon: IconCurrencyDollar }, - TWD: { label: 'Taiwanese dollar', Icon: IconCurrencyRenminbi }, - TZS: { label: 'Tanzanian shilling', Icon: IconCoins }, - UAH: { label: 'Ukrainian hryvnia', Icon: IconCurrencyHryvnia }, - UGX: { label: 'Ugandan shilling', Icon: IconCoins }, - USD: { label: 'United States dollar', Icon: IconCurrencyDollar }, - UYU: { label: 'Uruguayan peso', Icon: IconCoins }, - UZS: { label: 'Uzbekistani sum', Icon: IconCoins }, - VES: { label: 'Venezuelan bolívar', Icon: IconCoins }, - VND: { label: 'Vietnamese đồng', Icon: IconCurrencyDong }, - VUV: { label: 'Vanuatu vatu', Icon: IconCoins }, - WST: { label: 'Samoan tala', Icon: IconCoins }, - XOF: { label: 'West African CFA franc', Icon: IconCoins }, - XCD: { label: 'East Caribbean dollar', Icon: IconCurrencyDollar }, - YER: { label: 'Yemeni rial', Icon: IconCoins }, - ZAR: { label: 'South African rand', Icon: IconCoins }, - ZMW: { label: 'Zambian kwacha', Icon: IconCoins }, - ZWG: { label: 'Zimbabwe Gold', Icon: IconCoins }, + AED: { label: CURRENCY_CODE_LABELS.AED.label, Icon: IconCurrencyDirham }, + AFN: { label: CURRENCY_CODE_LABELS.AFN.label, Icon: IconCurrencyAfghani }, + ALL: { label: CURRENCY_CODE_LABELS.ALL.label, Icon: IconCurrencyLeu }, + AMD: { label: CURRENCY_CODE_LABELS.AMD.label, Icon: IconCurrencyDram }, + ANG: { label: CURRENCY_CODE_LABELS.ANG.label, Icon: IconCurrencyFlorin }, + AOA: { label: CURRENCY_CODE_LABELS.AOA.label, Icon: IconCoins }, + ARS: { label: CURRENCY_CODE_LABELS.ARS.label, Icon: IconCoins }, + AUD: { + label: CURRENCY_CODE_LABELS.AUD.label, + Icon: IconCurrencyDollarAustralian, + }, + AWG: { label: CURRENCY_CODE_LABELS.AWG.label, Icon: IconCurrencyFlorin }, + AZN: { label: CURRENCY_CODE_LABELS.AZN.label, Icon: IconCurrencyManat }, + BAM: { label: CURRENCY_CODE_LABELS.BAM.label, Icon: IconCoins }, + BBD: { label: CURRENCY_CODE_LABELS.BBD.label, Icon: IconCurrencyDollar }, + BDT: { label: CURRENCY_CODE_LABELS.BDT.label, Icon: IconCurrencyTaka }, + BGN: { label: CURRENCY_CODE_LABELS.BGN.label, Icon: IconCoins }, + BHD: { label: CURRENCY_CODE_LABELS.BHD.label, Icon: IconCurrencyBahraini }, + BIF: { label: CURRENCY_CODE_LABELS.BIF.label, Icon: IconCoins }, + BMD: { label: CURRENCY_CODE_LABELS.BMD.label, Icon: IconCurrencyDollar }, + BND: { + label: CURRENCY_CODE_LABELS.BND.label, + Icon: IconCurrencyDollarBrunei, + }, + BOB: { label: CURRENCY_CODE_LABELS.BOB.label, Icon: IconCoins }, + BRL: { label: CURRENCY_CODE_LABELS.BRL.label, Icon: IconCurrencyReal }, + BSD: { label: CURRENCY_CODE_LABELS.BSD.label, Icon: IconCurrencyDollar }, + BTN: { label: CURRENCY_CODE_LABELS.BTN.label, Icon: IconCurrencyDollar }, + BWP: { label: CURRENCY_CODE_LABELS.BWP.label, Icon: IconCoins }, + BYN: { label: CURRENCY_CODE_LABELS.BYN.label, Icon: IconCoins }, + BZD: { label: CURRENCY_CODE_LABELS.BZD.label, Icon: IconCurrencyDollar }, + CAD: { + label: CURRENCY_CODE_LABELS.CAD.label, + Icon: IconCurrencyDollarCanadian, + }, + CDF: { label: CURRENCY_CODE_LABELS.CDF.label, Icon: IconCoins }, + CHF: { label: CURRENCY_CODE_LABELS.CHF.label, Icon: IconCurrencyFrank }, + CLP: { label: CURRENCY_CODE_LABELS.CLP.label, Icon: IconCoins }, + CNY: { label: CURRENCY_CODE_LABELS.CNY.label, Icon: IconCurrencyYuan }, + COP: { label: CURRENCY_CODE_LABELS.COP.label, Icon: IconCoins }, + CRC: { label: CURRENCY_CODE_LABELS.CRC.label, Icon: IconCoins }, + CUP: { label: CURRENCY_CODE_LABELS.CUP.label, Icon: IconCoins }, + CVE: { label: CURRENCY_CODE_LABELS.CVE.label, Icon: IconCoins }, + CZK: { label: CURRENCY_CODE_LABELS.CZK.label, Icon: IconCurrencyKroneCzech }, + DJF: { label: CURRENCY_CODE_LABELS.DJF.label, Icon: IconCoins }, + DKK: { label: CURRENCY_CODE_LABELS.DKK.label, Icon: IconCurrencyKroneDanish }, + DOP: { label: CURRENCY_CODE_LABELS.DOP.label, Icon: IconCoins }, + DZD: { label: CURRENCY_CODE_LABELS.DZD.label, Icon: IconCoins }, + EGP: { label: CURRENCY_CODE_LABELS.EGP.label, Icon: IconCoins }, + ERN: { label: CURRENCY_CODE_LABELS.ERN.label, Icon: IconCoins }, + ETB: { label: CURRENCY_CODE_LABELS.ETB.label, Icon: IconCoins }, + EUR: { label: CURRENCY_CODE_LABELS.EUR.label, Icon: IconCurrencyEuro }, + FJD: { label: CURRENCY_CODE_LABELS.FJD.label, Icon: IconCurrencyDollar }, + FKP: { label: CURRENCY_CODE_LABELS.FKP.label, Icon: IconCoins }, + GBP: { label: CURRENCY_CODE_LABELS.GBP.label, Icon: IconCurrencyPound }, + GEL: { label: CURRENCY_CODE_LABELS.GEL.label, Icon: IconCurrencyLari }, + GHS: { label: CURRENCY_CODE_LABELS.GHS.label, Icon: IconCoins }, + GIP: { label: CURRENCY_CODE_LABELS.GIP.label, Icon: IconCoins }, + GMD: { label: CURRENCY_CODE_LABELS.GMD.label, Icon: IconCoins }, + GNF: { label: CURRENCY_CODE_LABELS.GNF.label, Icon: IconCoins }, + GTQ: { label: CURRENCY_CODE_LABELS.GTQ.label, Icon: IconCurrencyQuetzal }, + GYD: { + label: CURRENCY_CODE_LABELS.GYD.label, + Icon: IconCurrencyDollarGuyanese, + }, + HKD: { label: CURRENCY_CODE_LABELS.HKD.label, Icon: IconCurrencyRenminbi }, + HNL: { label: CURRENCY_CODE_LABELS.HNL.label, Icon: IconCurrencyLeu }, + HTG: { label: CURRENCY_CODE_LABELS.HTG.label, Icon: IconCoins }, + HUF: { label: CURRENCY_CODE_LABELS.HUF.label, Icon: IconCurrencyForint }, + IDR: { label: CURRENCY_CODE_LABELS.IDR.label, Icon: IconCoins }, + ILS: { label: CURRENCY_CODE_LABELS.ILS.label, Icon: IconCurrencyShekel }, + INR: { label: CURRENCY_CODE_LABELS.INR.label, Icon: IconCurrencyRupee }, + IQD: { label: CURRENCY_CODE_LABELS.IQD.label, Icon: IconCoins }, + IRR: { label: CURRENCY_CODE_LABELS.IRR.label, Icon: IconCurrencyIranianRial }, + ISK: { label: CURRENCY_CODE_LABELS.ISK.label, Icon: IconCoins }, + JMD: { label: CURRENCY_CODE_LABELS.JMD.label, Icon: IconCurrencyDollar }, + JOD: { label: CURRENCY_CODE_LABELS.JOD.label, Icon: IconCoins }, + JPY: { label: CURRENCY_CODE_LABELS.JPY.label, Icon: IconCurrencyYen }, + KES: { label: CURRENCY_CODE_LABELS.KES.label, Icon: IconCoins }, + KGS: { label: CURRENCY_CODE_LABELS.KGS.label, Icon: IconCurrencySom }, + KHR: { label: CURRENCY_CODE_LABELS.KHR.label, Icon: IconCoins }, + KMF: { label: CURRENCY_CODE_LABELS.KMF.label, Icon: IconCoins }, + KPW: { label: CURRENCY_CODE_LABELS.KPW.label, Icon: IconCurrencyWon }, + KRW: { label: CURRENCY_CODE_LABELS.KRW.label, Icon: IconCurrencyWon }, + KWD: { label: CURRENCY_CODE_LABELS.KWD.label, Icon: IconCurrencyDinar }, + KYD: { label: CURRENCY_CODE_LABELS.KYD.label, Icon: IconCurrencyDollar }, + KZT: { label: CURRENCY_CODE_LABELS.KZT.label, Icon: IconCurrencyTenge }, + LAK: { label: CURRENCY_CODE_LABELS.LAK.label, Icon: IconCurrencyKip }, + LBP: { label: CURRENCY_CODE_LABELS.LBP.label, Icon: IconCoins }, + LKR: { label: CURRENCY_CODE_LABELS.LKR.label, Icon: IconCoins }, + LRD: { label: CURRENCY_CODE_LABELS.LRD.label, Icon: IconCurrencyDollar }, + LSL: { label: CURRENCY_CODE_LABELS.LSL.label, Icon: IconCurrencyLeu }, + LYD: { label: CURRENCY_CODE_LABELS.LYD.label, Icon: IconCurrencyLyd }, + MAD: { label: CURRENCY_CODE_LABELS.MAD.label, Icon: IconCurrencyDirham }, + MDL: { label: CURRENCY_CODE_LABELS.MDL.label, Icon: IconCurrencyLeu }, + MGA: { label: CURRENCY_CODE_LABELS.MGA.label, Icon: IconCoins }, + MKD: { label: CURRENCY_CODE_LABELS.MKD.label, Icon: IconCoins }, + MMK: { label: CURRENCY_CODE_LABELS.MMK.label, Icon: IconCoins }, + MNT: { label: CURRENCY_CODE_LABELS.MNT.label, Icon: IconCurrencyTugrik }, + MOP: { label: CURRENCY_CODE_LABELS.MOP.label, Icon: IconCurrencyRenminbi }, + MRU: { label: CURRENCY_CODE_LABELS.MRU.label, Icon: IconCoins }, + MUR: { label: CURRENCY_CODE_LABELS.MUR.label, Icon: IconCoins }, + MVR: { label: CURRENCY_CODE_LABELS.MVR.label, Icon: IconCurrencyRufiyaa }, + MWK: { label: CURRENCY_CODE_LABELS.MWK.label, Icon: IconCoins }, + MXN: { label: CURRENCY_CODE_LABELS.MXN.label, Icon: IconCoins }, + MYR: { label: CURRENCY_CODE_LABELS.MYR.label, Icon: IconCoins }, + MZN: { label: CURRENCY_CODE_LABELS.MZN.label, Icon: IconCoins }, + NAD: { label: CURRENCY_CODE_LABELS.NAD.label, Icon: IconCurrencyDollar }, + NGN: { label: CURRENCY_CODE_LABELS.NGN.label, Icon: IconCurrencyNaira }, + NIO: { label: CURRENCY_CODE_LABELS.NIO.label, Icon: IconCoins }, + NOK: { + label: CURRENCY_CODE_LABELS.NOK.label, + Icon: IconCurrencyKroneSwedish, + }, + NPR: { + label: CURRENCY_CODE_LABELS.NPR.label, + Icon: IconCurrencyRupeeNepalese, + }, + NZD: { label: CURRENCY_CODE_LABELS.NZD.label, Icon: IconCurrencyDollar }, + OMR: { label: CURRENCY_CODE_LABELS.OMR.label, Icon: IconCoins }, + PAB: { label: CURRENCY_CODE_LABELS.PAB.label, Icon: IconCoins }, + PEN: { label: CURRENCY_CODE_LABELS.PEN.label, Icon: IconCoins }, + PGK: { label: CURRENCY_CODE_LABELS.PGK.label, Icon: IconCoins }, + PHP: { label: CURRENCY_CODE_LABELS.PHP.label, Icon: IconCurrencyPeso }, + PKR: { label: CURRENCY_CODE_LABELS.PKR.label, Icon: IconCoins }, + PLN: { label: CURRENCY_CODE_LABELS.PLN.label, Icon: IconCurrencyZloty }, + PYG: { label: CURRENCY_CODE_LABELS.PYG.label, Icon: IconCurrencyGuarani }, + QAR: { label: CURRENCY_CODE_LABELS.QAR.label, Icon: IconCurrencyRiyal }, + RON: { label: CURRENCY_CODE_LABELS.RON.label, Icon: IconCurrencyLeu }, + RSD: { label: CURRENCY_CODE_LABELS.RSD.label, Icon: IconCoins }, + RUB: { label: CURRENCY_CODE_LABELS.RUB.label, Icon: IconCurrencyRubel }, + RWF: { label: CURRENCY_CODE_LABELS.RWF.label, Icon: IconCoins }, + SAR: { label: CURRENCY_CODE_LABELS.SAR.label, Icon: IconCoins }, + SBD: { label: CURRENCY_CODE_LABELS.SBD.label, Icon: IconCurrencyDollar }, + SCR: { label: CURRENCY_CODE_LABELS.SCR.label, Icon: IconCoins }, + SDG: { label: CURRENCY_CODE_LABELS.SDG.label, Icon: IconCoins }, + SEK: { + label: CURRENCY_CODE_LABELS.SEK.label, + Icon: IconCurrencyKroneSwedish, + }, + SGD: { + label: CURRENCY_CODE_LABELS.SGD.label, + Icon: IconCurrencyDollarSingapore, + }, + SHP: { label: CURRENCY_CODE_LABELS.SHP.label, Icon: IconCoins }, + SLE: { label: CURRENCY_CODE_LABELS.SLE.label, Icon: IconCoins }, + SOS: { label: CURRENCY_CODE_LABELS.SOS.label, Icon: IconCoins }, + SRD: { label: CURRENCY_CODE_LABELS.SRD.label, Icon: IconCurrencyDollar }, + SSP: { label: CURRENCY_CODE_LABELS.SSP.label, Icon: IconCoins }, + STN: { label: CURRENCY_CODE_LABELS.STN.label, Icon: IconCoins }, + SVC: { label: CURRENCY_CODE_LABELS.SVC.label, Icon: IconCoins }, + SYP: { label: CURRENCY_CODE_LABELS.SYP.label, Icon: IconCoins }, + SZL: { label: CURRENCY_CODE_LABELS.SZL.label, Icon: IconCurrencyLeu }, + THB: { label: CURRENCY_CODE_LABELS.THB.label, Icon: IconCurrencyBaht }, + TJS: { label: CURRENCY_CODE_LABELS.TJS.label, Icon: IconCoins }, + TMT: { label: CURRENCY_CODE_LABELS.TMT.label, Icon: IconCurrencyManat }, + TND: { label: CURRENCY_CODE_LABELS.TND.label, Icon: IconCoins }, + TOP: { label: CURRENCY_CODE_LABELS.TOP.label, Icon: IconCurrencyPaanga }, + TRY: { label: CURRENCY_CODE_LABELS.TRY.label, Icon: IconCurrencyLira }, + TTD: { label: CURRENCY_CODE_LABELS.TTD.label, Icon: IconCurrencyDollar }, + TWD: { label: CURRENCY_CODE_LABELS.TWD.label, Icon: IconCurrencyRenminbi }, + TZS: { label: CURRENCY_CODE_LABELS.TZS.label, Icon: IconCoins }, + UAH: { label: CURRENCY_CODE_LABELS.UAH.label, Icon: IconCurrencyHryvnia }, + UGX: { label: CURRENCY_CODE_LABELS.UGX.label, Icon: IconCoins }, + USD: { label: CURRENCY_CODE_LABELS.USD.label, Icon: IconCurrencyDollar }, + UYU: { label: CURRENCY_CODE_LABELS.UYU.label, Icon: IconCoins }, + UZS: { label: CURRENCY_CODE_LABELS.UZS.label, Icon: IconCoins }, + VES: { label: CURRENCY_CODE_LABELS.VES.label, Icon: IconCoins }, + VND: { label: CURRENCY_CODE_LABELS.VND.label, Icon: IconCurrencyDong }, + VUV: { label: CURRENCY_CODE_LABELS.VUV.label, Icon: IconCoins }, + WST: { label: CURRENCY_CODE_LABELS.WST.label, Icon: IconCoins }, + XOF: { label: CURRENCY_CODE_LABELS.XOF.label, Icon: IconCoins }, + XCD: { label: CURRENCY_CODE_LABELS.XCD.label, Icon: IconCurrencyDollar }, + YER: { label: CURRENCY_CODE_LABELS.YER.label, Icon: IconCoins }, + ZAR: { label: CURRENCY_CODE_LABELS.ZAR.label, Icon: IconCoins }, + ZMW: { label: CURRENCY_CODE_LABELS.ZMW.label, Icon: IconCoins }, + ZWG: { label: CURRENCY_CODE_LABELS.ZWG.label, Icon: IconCoins }, }; diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues.ts b/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues.ts index bec48daf895..b427ab1ce2c 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues.ts +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues.ts @@ -1,9 +1,9 @@ import { useFormContext } from 'react-hook-form'; import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById'; -import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { type SettingsDataModelFieldCurrencyFormValues } from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm'; import { isNonEmptyString } from '@sniptt/guards'; +import { CurrencyCode } from 'twenty-shared/constants'; import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString'; import { stripSimpleQuotesFromString } from '~/utils/string/stripSimpleQuotesFromString'; diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts index 3620c405dda..dc91d9087e0 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/__tests__/getCurrencyFieldPreviewValue.test.ts @@ -1,8 +1,8 @@ -import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; import { getCurrencyFieldPreviewValue } from '../getCurrencyFieldPreviewValue'; +import { CurrencyCode } from 'twenty-shared/constants'; const mockedCompanyObjectMetadataItem = generatedMockObjectMetadataItems.find( (item) => item.nameSingular === 'company', diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/getCurrencyFieldPreviewValue.ts b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/getCurrencyFieldPreviewValue.ts index c97a638f75f..b6c790b93cb 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/getCurrencyFieldPreviewValue.ts +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/utils/getCurrencyFieldPreviewValue.ts @@ -1,8 +1,8 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { type CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { type FieldCurrencyValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { currencyFieldDefaultValueSchema } from '@/object-record/record-field/ui/validation-schemas/currencyFieldDefaultValueSchema'; import { getSettingsFieldTypeConfig } from '@/settings/data-model/utils/getSettingsFieldTypeConfig'; +import { type CurrencyCode } from 'twenty-shared/constants'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { stripSimpleQuotesFromString } from '~/utils/string/stripSimpleQuotesFromString'; diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx index b2fc8f1f066..27d1c99f8f9 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx @@ -17,10 +17,10 @@ import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { useRecoilValue } from 'recoil'; +import { isNonEmptyArray } from 'twenty-shared/utils'; import { H2Title, IconSearch } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; import { sortByProperty } from '~/utils/array/sortByProperty'; -import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; import { turnOrderByIntoSort } from '~/utils/turnOrderByIntoSort'; export const SETTINGS_ROLE_PERMISSION_OBJECT_LEVEL_FIELD_PERMISSION_TABLE_ID = diff --git a/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts b/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts index 3c2cb1e488b..174a25767f5 100644 --- a/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts +++ b/packages/twenty-front/src/modules/settings/roles/role/hooks/useSaveDraftRoleToDB.ts @@ -9,7 +9,7 @@ import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settin import { getOperationName } from '@apollo/client/utilities'; import { useRecoilValue } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, isNonEmptyArray } from 'twenty-shared/utils'; import { useCreateOneRoleMutation, useUpdateOneRoleMutation, @@ -20,7 +20,6 @@ import { import { type Role } from '~/generated/graphql'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { getDirtyFields } from '~/utils/getDirtyFields'; -import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; const ROLE_BASIC_KEYS: Array = [ 'label', @@ -105,7 +104,7 @@ export const useSaveDraftRoleToDB = ({ if ( isNonEmptyArray( fieldPermissionsThatShouldntBeCreatedBecauseTheyAreUseless, - ) + ) === true ) { for (const fieldPermissionToRemoveInDraftRole of fieldPermissionsThatShouldntBeCreatedBecauseTheyAreUseless) { removeFieldPermissionInDraftRole( @@ -183,7 +182,7 @@ export const useSaveDraftRoleToDB = ({ }); } - if (isNonEmptyArray(fieldPermissionsToUpsert)) { + if (isNonEmptyArray(fieldPermissionsToUpsert) === true) { await upsertFieldPermissions({ variables: { upsertFieldPermissionsInput: { @@ -306,7 +305,7 @@ export const useSaveDraftRoleToDB = ({ }); } - if (isNonEmptyArray(fieldPermissionsToUpsert)) { + if (isNonEmptyArray(fieldPermissionsToUpsert) === true) { await upsertFieldPermissions({ variables: { upsertFieldPermissionsInput: { diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx index a76ce8b3b57..dd3f608df12 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx @@ -1,8 +1,8 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { CurrencyCode } from '@/object-record/record-field/ui/types/CurrencyCode'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; +import { CurrencyCode } from 'twenty-shared/constants'; import { CURRENCIES } from '@/settings/data-model/constants/Currencies'; import { type Currency } from '@/ui/input/components/internal/types/Currency'; 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 fa925b79a6e..62020923878 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,13 @@ 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 { 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'; +import { + computeRecordGqlOperationFilter, + turnAnyFieldFilterIntoRecordGqlFilter, +} from 'twenty-shared/utils'; export const useGetRecordIndexTotalCount = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); @@ -38,7 +40,7 @@ export const useGetRecordIndexTotalCount = () => { const { recordGqlOperationFilter: anyFieldFilter } = turnAnyFieldFilterIntoRecordGqlFilter({ - objectMetadataItem, + fields: objectMetadataItem.fields, filterValue: anyFieldFilterValue, }); 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 f9b91c6e3d2..a907852ba3c 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 @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { CompositeFieldSubFieldName, + PartialFieldMetadataItemOption, RecordFilterGroupLogicalOperator, } from 'twenty-shared/types'; import { @@ -10,6 +11,7 @@ import { computeRecordGqlOperationFilter, convertViewFilterValueToString, getFilterTypeFromFieldType, + turnAnyFieldFilterIntoRecordGqlFilter, } from 'twenty-shared/utils'; import { @@ -31,8 +33,10 @@ import { } 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 { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; +import { ViewEntity } from 'src/engine/core-modules/view/entities/view.entity'; 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 { ViewService } from 'src/engine/core-modules/view/services/view.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'; @@ -46,6 +50,7 @@ export class GraphqlQueryGroupByResolverService extends GraphqlQueryBaseResolver constructor( private readonly viewFilterService: ViewFilterService, private readonly viewFilterGroupService: ViewFilterGroupService, + private readonly viewService: ViewService, ) { super(); } @@ -269,6 +274,7 @@ export class GraphqlQueryGroupByResolverService extends GraphqlQueryBaseResolver name: field.name, type: field.type, label: field.label, + options: field.options as PartialFieldMetadataItemOption[], })); const filtersFromView = computeRecordGqlOperationFilter({ @@ -278,7 +284,26 @@ export class GraphqlQueryGroupByResolverService extends GraphqlQueryBaseResolver filterValueDependencies: {}, }); - appliedFilters = combineFilters([appliedFilters, filtersFromView]); + let view: ViewEntity | null = viewFilters[0]?.view; + + if (!view) { + view = await this.viewService.findById( + executionArgs.args.viewId, + workspaceId, + ); + } + + const { recordGqlOperationFilter: anyFieldFilter } = + turnAnyFieldFilterIntoRecordGqlFilter({ + fields, + filterValue: view?.anyFieldFilterValue ?? '', + }); + + appliedFilters = combineFilters([ + appliedFilters, + filtersFromView, + anyFieldFilter, + ]); return appliedFilters; } 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 index 19027f1881c..c5d2f3d960f 100644 --- 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 @@ -5,13 +5,14 @@ import { createOneOperationFactory } from 'test/integration/graphql/utils/create 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 { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-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 'twenty-shared/types'; 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'; import { ViewFilterGroupLogicalOperator } from 'src/modules/view/standard-objects/view-filter-group.workspace-entity'; describe('group-by resolvers (integration)', () => { @@ -23,21 +24,21 @@ describe('group-by resolvers (integration)', () => { afterEach(async () => { // cleanup created people await makeGraphqlAPIRequest( - deleteOneOperationFactory({ + destroyOneOperationFactory({ objectMetadataSingularName: 'person', gqlFields: 'id', recordId: testPersonId, }), ); await makeGraphqlAPIRequest( - deleteOneOperationFactory({ + destroyOneOperationFactory({ objectMetadataSingularName: 'person', gqlFields: 'id', recordId: testPerson2Id, }), ); await makeGraphqlAPIRequest( - deleteOneOperationFactory({ + destroyOneOperationFactory({ objectMetadataSingularName: 'person', gqlFields: 'id', recordId: testPerson3Id, @@ -108,32 +109,12 @@ describe('group-by resolvers (integration)', () => { const testPersonId = randomUUID(); const testPerson2Id = randomUUID(); const testPerson3Id = randomUUID(); + let personObjectMetadataId: string; + let personObject: ObjectMetadataDTO & { + fieldsList?: FieldMetadataDTO[]; + }; - 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 () => { + beforeAll(async () => { const { objects } = await findManyObjectMetadata({ input: { filter: {}, @@ -145,9 +126,42 @@ describe('group-by resolvers (integration)', () => { expectToFail: false, }); - const personObject = objects.find((o) => o.nameSingular === 'person'); - const personObjectMetadataId = personObject?.id; + const person = objects.find((o) => o.nameSingular === 'person'); + if (!person || !person.id) { + throw new Error('Person object not found'); + } + + personObject = person; + + personObjectMetadataId = personObject.id; + }); + + afterEach(async () => { + // cleanup created people + await makeGraphqlAPIRequest( + destroyOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPersonId, + }), + ); + await makeGraphqlAPIRequest( + destroyOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPerson2Id, + }), + ); + await makeGraphqlAPIRequest( + destroyOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: 'id', + recordId: testPerson3Id, + }), + ); + }); + it('groups by city', async () => { const cityFieldMetadata = personObject?.fieldsList?.find( (f: FieldMetadataDTO) => f.name === 'city', ); @@ -235,5 +249,70 @@ describe('group-by resolvers (integration)', () => { ]), ); }); + + it('groups by city with any field filter', 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 }, + }), + ); + + // create a view with any field filter + const createViewResponse = await makeGraphqlAPIRequest( + createViewOperationFactory({ + data: { + name: 'People View City Keep', + objectMetadataId: personObjectMetadataId, + icon: 'Icon123', + anyFieldFilterValue: cityA, + }, + }), + ); + + const viewId = createViewResponse.body.data.createCoreView.id as string; + + 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: [cityA] }), + ]), + ); + // Ensure excluded city is not present + expect(groups).toEqual( + expect.not.arrayContaining([ + expect.objectContaining({ groupByDimensionValues: [cityB] }), + ]), + ); + }); }); }); diff --git a/packages/twenty-shared/src/constants/CurrencyCode.ts b/packages/twenty-shared/src/constants/CurrencyCode.ts new file mode 100644 index 00000000000..cfb98224303 --- /dev/null +++ b/packages/twenty-shared/src/constants/CurrencyCode.ts @@ -0,0 +1,156 @@ +export enum CurrencyCode { + AED = 'AED', + AFN = 'AFN', + ALL = 'ALL', + AMD = 'AMD', + ANG = 'ANG', + AOA = 'AOA', + ARS = 'ARS', + AUD = 'AUD', + AWG = 'AWG', + AZN = 'AZN', + BAM = 'BAM', + BBD = 'BBD', + BDT = 'BDT', + BGN = 'BGN', + BHD = 'BHD', + BIF = 'BIF', + BMD = 'BMD', + BND = 'BND', + BOB = 'BOB', + BRL = 'BRL', + BSD = 'BSD', + BTN = 'BTN', + BWP = 'BWP', + BYN = 'BYN', + BZD = 'BZD', + CAD = 'CAD', + CDF = 'CDF', + CHF = 'CHF', + CLP = 'CLP', + CNY = 'CNY', + COP = 'COP', + CRC = 'CRC', + CUP = 'CUP', + CVE = 'CVE', + CZK = 'CZK', + DJF = 'DJF', + DKK = 'DKK', + DOP = 'DOP', + DZD = 'DZD', + EGP = 'EGP', + ERN = 'ERN', + ETB = 'ETB', + EUR = 'EUR', + FJD = 'FJD', + FKP = 'FKP', + GBP = 'GBP', + GEL = 'GEL', + GHS = 'GHS', + GIP = 'GIP', + GMD = 'GMD', + GNF = 'GNF', + GTQ = 'GTQ', + GYD = 'GYD', + HKD = 'HKD', + HNL = 'HNL', + HTG = 'HTG', + HUF = 'HUF', + IDR = 'IDR', + ILS = 'ILS', + INR = 'INR', + IQD = 'IQD', + IRR = 'IRR', + ISK = 'ISK', + JMD = 'JMD', + JOD = 'JOD', + JPY = 'JPY', + KES = 'KES', + KGS = 'KGS', + KHR = 'KHR', + KMF = 'KMF', + KPW = 'KPW', + KRW = 'KRW', + KWD = 'KWD', + KYD = 'KYD', + KZT = 'KZT', + LAK = 'LAK', + LBP = 'LBP', + LKR = 'LKR', + LRD = 'LRD', + LSL = 'LSL', + LYD = 'LYD', + MAD = 'MAD', + MDL = 'MDL', + MGA = 'MGA', + MKD = 'MKD', + MMK = 'MMK', + MNT = 'MNT', + MOP = 'MOP', + MRU = 'MRU', + MUR = 'MUR', + MVR = 'MVR', + MWK = 'MWK', + MXN = 'MXN', + MYR = 'MYR', + MZN = 'MZN', + NAD = 'NAD', + NGN = 'NGN', + NIO = 'NIO', + NOK = 'NOK', + NPR = 'NPR', + NZD = 'NZD', + OMR = 'OMR', + PAB = 'PAB', + PEN = 'PEN', + PGK = 'PGK', + PHP = 'PHP', + PKR = 'PKR', + PLN = 'PLN', + PYG = 'PYG', + QAR = 'QAR', + RON = 'RON', + RSD = 'RSD', + RUB = 'RUB', + RWF = 'RWF', + SAR = 'SAR', + SBD = 'SBD', + SCR = 'SCR', + SDG = 'SDG', + SEK = 'SEK', + SGD = 'SGD', + SHP = 'SHP', + SLE = 'SLE', + SOS = 'SOS', + SRD = 'SRD', + SSP = 'SSP', + STN = 'STN', + SVC = 'SVC', + SYP = 'SYP', + SZL = 'SZL', + THB = 'THB', + TJS = 'TJS', + TMT = 'TMT', + TND = 'TND', + TOP = 'TOP', + TRY = 'TRY', + TTD = 'TTD', + TWD = 'TWD', + TZS = 'TZS', + UAH = 'UAH', + UGX = 'UGX', + USD = 'USD', + UYU = 'UYU', + UZS = 'UZS', + VES = 'VES', + VND = 'VND', + VUV = 'VUV', + WST = 'WST', + XCD = 'XCD', + XOF = 'XOF', + YER = 'YER', + ZAR = 'ZAR', + ZMW = 'ZMW', + ZWG = 'ZWG', + } + \ No newline at end of file diff --git a/packages/twenty-shared/src/constants/CurrencyCodeLabels.ts b/packages/twenty-shared/src/constants/CurrencyCodeLabels.ts new file mode 100644 index 00000000000..4ddd49a1762 --- /dev/null +++ b/packages/twenty-shared/src/constants/CurrencyCodeLabels.ts @@ -0,0 +1,160 @@ +import { type CurrencyCode } from "@/constants/CurrencyCode"; + +export const CURRENCY_CODE_LABELS: Record< + CurrencyCode, + { label: string } +> = { + AED: { label: 'UAE dirham' }, + AFN: { label: 'Afghan afghani' }, + ALL: { label: 'Albanian lek' }, + AMD: { label: 'Armenian dram' }, + ANG: { label: 'Netherlands Antillean guilder' }, + AOA: { label: 'Angolan kwanza' }, + ARS: { label: 'Argentine peso' }, + AUD: { label: 'Australian dollar' }, + AWG: { label: 'Aruban florin' }, + AZN: { label: 'Azerbaijani manat' }, + BAM: { label: 'Bosnia and Herzegovina mark' }, + BBD: { label: 'Barbados dollar' }, + BDT: { label: 'Bangladeshi taka' }, + BGN: { label: 'Bulgarian lev' }, + BHD: { label: 'Bahraini dinar' }, + BIF: { label: 'Burundian franc' }, + BMD: { label: 'Bermudian dollar' }, + BND: { label: 'Brunei dollar' }, + BOB: { label: 'Boliviano' }, + BRL: { label: 'Brazilian real' }, + BSD: { label: 'Bahamian dollar' }, + BTN: { label: 'Bhutanese ngultrum' }, + BWP: { label: 'Botswana pula' }, + BYN: { label: 'Belarusian ruble' }, + BZD: { label: 'Belize dollar' }, + CAD: { label: 'Canadian dollar' }, + CDF: { label: 'Congolese franc' }, + CHF: { label: 'Swiss franc' }, + CLP: { label: 'Chilean peso' }, + CNY: { label: 'Chinese yuan' }, + COP: { label: 'Colombian peso' }, + CRC: { label: 'Costa Rican colon' }, + CUP: { label: 'Cuban peso' }, + CVE: { label: 'Cape Verdean escudo' }, + CZK: { label: 'Czech koruna' }, + DJF: { label: 'Djiboutian franc' }, + DKK: { label: 'Danish krone' }, + DOP: { label: 'Dominican peso' }, + DZD: { label: 'Algerian Dinar' }, + EGP: { label: 'Egyptian pound' }, + ERN: { label: 'Eritrean nakfa' }, + ETB: { label: 'Ethiopian birr' }, + EUR: { label: 'Euro' }, + FJD: { label: 'Fiji dollar' }, + FKP: { label: 'Falkland Islands pound' }, + GBP: { label: 'British pound' }, + GEL: { label: 'Georgian lari' }, + GHS: { label: 'Ghanaian cedi' }, + GIP: { label: 'Gibraltar pound' }, + GMD: { label: 'Gambian dalasi' }, + GNF: { label: 'Guinean franc' }, + GTQ: { label: 'Guatemalan quetzal' }, + GYD: { label: 'Guyanese dollar' }, + HKD: { label: 'Hong Kong dollar' }, + HNL: { label: 'Honduran lempira' }, + HTG: { label: 'Haitian gourde' }, + HUF: { label: 'Hungarian forint' }, + IDR: { label: 'Indonesian rupiah' }, + ILS: { label: 'Israeli shekel' }, + INR: { label: 'Indian rupee' }, + IQD: { label: 'Iraqi dinar' }, + IRR: { label: 'Iranian rial' }, + ISK: { label: 'Icelandic króna' }, + JMD: { label: 'Jamaican dollar' }, + JOD: { label: 'Jordanian dinar' }, + JPY: { label: 'Japanese yen' }, + KES: { label: 'Kenyan shilling' }, + KGS: { label: 'Kyrgyzstani som' }, + KHR: { label: 'Cambodian riel' }, + KMF: { label: 'Comoro franc' }, + KPW: { label: 'North Korean won' }, + KRW: { label: 'South Korean won' }, + KWD: { label: 'Kuwaiti dinar' }, + KYD: { label: 'Cayman Islands dollar' }, + KZT: { label: 'Kazakhstani tenge' }, + LAK: { label: 'Lao kip' }, + LBP: { label: 'Lebanese pound' }, + LKR: { label: 'Sri Lankan rupee' }, + LRD: { label: 'Liberian dollar' }, + LSL: { label: 'Lesotho loti' }, + LYD: { label: 'Libyan dinar' }, + MAD: { label: 'Moroccan dirham' }, + MDL: { label: 'Moldovan leu' }, + MGA: { label: 'Malagasy ariary' }, + MKD: { label: 'Macedonian denar' }, + MMK: { label: 'Myanmar kyat' }, + MNT: { label: 'Mongolian tögrög' }, + MOP: { label: 'Macanese pataca' }, + MRU: { label: 'Mauritanian ouguiya' }, + MUR: { label: 'Mauritian rupee' }, + MVR: { label: 'Maldivian rufiyaa' }, + MWK: { label: 'Malawian kwacha' }, + MXN: { label: 'Mexican peso' }, + MYR: { label: 'Malaysian ringgit' }, + MZN: { label: 'Mozambican metical' }, + NAD: { label: 'Namibian dollar' }, + NGN: { label: 'Nigerian naira' }, + NIO: { label: 'Nicaraguan córdoba' }, + NOK: { label: 'Norwegian krone' }, + NPR: { label: 'Nepalese rupee' }, + NZD: { label: 'New Zealand dollar' }, + OMR: { label: 'Omani rial' }, + PAB: { label: 'Panamanian balboa' }, + PEN: { label: 'Peruvian sol' }, + PGK: { label: 'Papua New Guinean kina' }, + PHP: { label: 'Philippine peso' }, + PKR: { label: 'Pakistani rupee' }, + PLN: { label: 'Polish złoty' }, + PYG: { label: 'Paraguayan guaraní' }, + QAR: { label: 'Qatari riyal' }, + RON: { label: 'Romanian leu' }, + RSD: { label: 'Serbian dinar' }, + RUB: { label: 'Russian ruble' }, + RWF: { label: 'Rwandan franc' }, + SAR: { label: 'Saudi riyal' }, + SBD: { label: 'Solomon Islands dollar' }, + SCR: { label: 'Seychelles rupee' }, + SDG: { label: 'Sudanese pound' }, + SEK: { label: 'Swedish krona' }, + SGD: { label: 'Singapore dollar' }, + SHP: { label: 'Saint Helena pound' }, + SLE: { label: 'Sierra Leonean leone' }, + SOS: { label: 'Somalian shilling' }, + SRD: { label: 'Surinamese dollar' }, + SSP: { label: 'South Sudanese pound' }, + STN: { label: 'São Tomé and Príncipe dobra' }, + SVC: { label: 'Salvadoran colón' }, + SYP: { label: 'Syrian pound' }, + SZL: { label: 'Swazi lilangeni' }, + THB: { label: 'Thai Baht' }, + TJS: { label: 'Tajikistani somoni' }, + TMT: { label: 'Turkmenistan manat' }, + TND: { label: 'Tunisian dinar' }, + TOP: { label: 'Tongan paʻanga' }, + TRY: { label: 'Turkish lira' }, + TTD: { label: 'Trinidad and Tobago dollar' }, + TWD: { label: 'Taiwanese dollar' }, + TZS: { label: 'Tanzanian shilling' }, + UAH: { label: 'Ukrainian hryvnia' }, + UGX: { label: 'Ugandan shilling' }, + USD: { label: 'United States dollar' }, + UYU: { label: 'Uruguayan peso' }, + UZS: { label: 'Uzbekistani sum' }, + VES: { label: 'Venezuelan bolívar' }, + VND: { label: 'Vietnamese đồng' }, + VUV: { label: 'Vanuatu vatu' }, + WST: { label: 'Samoan tala' }, + XOF: { label: 'West African CFA franc' }, + XCD: { label: 'East Caribbean dollar' }, + YER: { label: 'Yemeni rial' }, + ZAR: { label: 'South African rand' }, + ZMW: { label: 'Zambian kwacha' }, + ZWG: { label: 'Zimbabwe Gold' }, +}; \ No newline at end of file diff --git a/packages/twenty-shared/src/constants/index.ts b/packages/twenty-shared/src/constants/index.ts index 6fd8c5162f2..94f83e229da 100644 --- a/packages/twenty-shared/src/constants/index.ts +++ b/packages/twenty-shared/src/constants/index.ts @@ -8,6 +8,8 @@ */ export { COMPOSITE_FIELD_TYPE_SUB_FIELDS_NAMES } from './CompositeFieldTypeSubFieldsNames'; +export { CurrencyCode } from './CurrencyCode'; +export { CURRENCY_CODE_LABELS } from './CurrencyCodeLabels'; export { FIELD_FOR_TOTAL_COUNT_AGGREGATE_OPERATION } from './FieldForTotalCountAggregateOperation'; export { MAX_OPTIONS_TO_DISPLAY } from './FieldMetadataMaxOptionsToDisplay'; export { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from './FieldRestrictedAdditionalPermissionsRequired'; diff --git a/packages/twenty-shared/src/types/PartialFieldMetadataItem.ts b/packages/twenty-shared/src/types/PartialFieldMetadataItem.ts index f4b1a774651..4708a530b19 100644 --- a/packages/twenty-shared/src/types/PartialFieldMetadataItem.ts +++ b/packages/twenty-shared/src/types/PartialFieldMetadataItem.ts @@ -1,8 +1,10 @@ import { type FieldMetadataType } from "@/types/FieldMetadataType"; +import { type PartialFieldMetadataItemOption } from "@/types/PartialFieldMetadataOption"; export type PartialFieldMetadataItem = { id: string; name: string; type: FieldMetadataType; label: string; + options?: PartialFieldMetadataItemOption[] | null; } \ No newline at end of file diff --git a/packages/twenty-shared/src/types/PartialFieldMetadataOption.ts b/packages/twenty-shared/src/types/PartialFieldMetadataOption.ts new file mode 100644 index 00000000000..f20481dcccd --- /dev/null +++ b/packages/twenty-shared/src/types/PartialFieldMetadataOption.ts @@ -0,0 +1,7 @@ + +export type PartialFieldMetadataItemOption = { + id: string; + label: string; + position: number; + value: string; + }; \ No newline at end of file diff --git a/packages/twenty-shared/src/types/index.ts b/packages/twenty-shared/src/types/index.ts index 5621145246f..a45d030bce2 100644 --- a/packages/twenty-shared/src/types/index.ts +++ b/packages/twenty-shared/src/types/index.ts @@ -35,6 +35,7 @@ export type { ObjectsPermissionsByRoleId } from './ObjectsPermissionsByRoleId'; export type { ObjectsPermissionsByRoleIdDeprecated } from './ObjectsPermissionsByRoleIdDeprecated'; export type { ObjectsPermissionsDeprecated } from './ObjectsPermissionsDeprecated'; export type { PartialFieldMetadataItem } from './PartialFieldMetadataItem'; +export type { PartialFieldMetadataItemOption } from './PartialFieldMetadataOption'; export { RecordFilterGroupLogicalOperator } from './RecordFilterGroupLogicalOperator'; export type { RecordFilterValueDependencies } from './RecordFilterValueDependencies'; export type { diff --git a/packages/twenty-front/src/utils/__tests__/isNonEmptyArray.test.ts b/packages/twenty-shared/src/utils/__tests__/isNonEmptyArray.test.ts similarity index 88% rename from packages/twenty-front/src/utils/__tests__/isNonEmptyArray.test.ts rename to packages/twenty-shared/src/utils/__tests__/isNonEmptyArray.test.ts index 14457448ae1..844ac18cb67 100644 --- a/packages/twenty-front/src/utils/__tests__/isNonEmptyArray.test.ts +++ b/packages/twenty-shared/src/utils/__tests__/isNonEmptyArray.test.ts @@ -1,4 +1,4 @@ -import { isNonEmptyArray } from '../isNonEmptyArray'; +import { isNonEmptyArray } from "@/utils/array/isNonEmptyArray"; describe('isNonEmptyArray', () => { it('should return true for a non empty array', () => { diff --git a/packages/twenty-front/src/utils/isNonEmptyArray.ts b/packages/twenty-shared/src/utils/array/isNonEmptyArray.ts similarity index 100% rename from packages/twenty-front/src/utils/isNonEmptyArray.ts rename to packages/twenty-shared/src/utils/array/isNonEmptyArray.ts diff --git a/packages/twenty-shared/src/utils/filter/index.ts b/packages/twenty-shared/src/utils/filter/index.ts index d8b39173946..2f92c94ab73 100644 --- a/packages/twenty-shared/src/utils/filter/index.ts +++ b/packages/twenty-shared/src/utils/filter/index.ts @@ -6,6 +6,7 @@ export * from './computeEmptyGqlOperationFilterForEmails'; export * from './computeEmptyGqlOperationFilterForLinks'; export * from './computeRecordGqlOperationFilter'; export * from './isEmptinessOperand'; +export * from './turnAnyFieldFilterIntoRecordGqlFilter'; export * from './turnRecordFilterGroupIntoGqlOperationFilter'; export * from './turnRecordFilterIntoGqlOperationFilter'; export * from './utils/combineFilters'; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter.ts b/packages/twenty-shared/src/utils/filter/turnAnyFieldFilterIntoRecordGqlFilter.ts similarity index 70% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter.ts rename to packages/twenty-shared/src/utils/filter/turnAnyFieldFilterIntoRecordGqlFilter.ts index b9342b89524..f1e49a60fb6 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter.ts +++ b/packages/twenty-shared/src/utils/filter/turnAnyFieldFilterIntoRecordGqlFilter.ts @@ -1,41 +1,43 @@ -import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; -import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; -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 { CURRENCY_CODE_LABELS } from '@/constants'; +import { type CurrencyCode } from '@/constants/CurrencyCode'; +import { FieldMetadataType, ViewFilterOperand, type PartialFieldMetadataItem, type RecordGqlOperationFilter } from '@/types'; +import { filterSelectOptionsOfFieldMetadataItem, type RecordFilter } from '@/utils'; +import { isNonEmptyArray } from '@/utils/array/isNonEmptyArray'; +import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter'; +import { createAnyFieldRecordFilterBaseProperties } from '@/utils/filter/utils/createAnyFieldRecordFilterBaseProperties'; +import { isDefined } from '@/utils/validation'; import { isNonEmptyString } from '@sniptt/guards'; -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'; + +const currencies: { value: CurrencyCode; label: string }[] = Object.entries( + CURRENCY_CODE_LABELS, +).map(([key, { label }]) => ({ + value: key as CurrencyCode, + label: `${label} (${key})`, +})); export const turnAnyFieldFilterIntoRecordGqlFilter = ({ filterValue, - objectMetadataItem, + fields, }: { filterValue: string; - objectMetadataItem: ObjectMetadataItem; + fields: PartialFieldMetadataItem[]; }) => { - const fieldMetadataItems = objectMetadataItem.fields; const anyFieldRecordFilters: RecordFilter[] = []; const isFilterValueANumber = z.coerce.number().safeParse(filterValue).success; - for (const fieldMetadataItem of fieldMetadataItems) { - switch (fieldMetadataItem.type) { + for (const field of fields) { + switch (field.type) { case FieldMetadataType.TEXT: { anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'TEXT', } satisfies RecordFilter); break; @@ -44,9 +46,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'ADDRESS', } satisfies RecordFilter); break; @@ -55,9 +57,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'LINKS', } satisfies RecordFilter); break; @@ -66,9 +68,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'FULL_NAME', } satisfies RecordFilter); break; @@ -77,9 +79,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'ARRAY', } satisfies RecordFilter); break; @@ -88,9 +90,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'EMAILS', } satisfies RecordFilter); break; @@ -99,9 +101,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'PHONES', } satisfies RecordFilter); break; @@ -111,9 +113,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.IS, + operand: ViewFilterOperand.IS, type: 'NUMBER', } satisfies RecordFilter); } @@ -124,16 +126,14 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.IS, + operand: ViewFilterOperand.IS, type: 'CURRENCY', - subFieldName: 'amountMicros', } satisfies RecordFilter); } - if (isNonEmptyString(filterValue)) { - const foundCorrespondingCurrencies = CURRENCIES.filter( + const foundCorrespondingCurrencies = currencies.filter( (currency) => currency.label.includes(filterValue) || currency.value.includes(filterValue), @@ -147,9 +147,9 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ filterValue: arrayOfCurrenciesStringified, - fieldMetadataItem, + fieldMetadataItem: field, }), - operand: RecordFilterOperand.IS, + operand: ViewFilterOperand.IS, type: 'CURRENCY', subFieldName: 'currencyCode', } satisfies RecordFilter); @@ -161,7 +161,7 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ if (isNonEmptyString(filterValue)) { const { foundCorrespondingSelectOptions } = filterSelectOptionsOfFieldMetadataItem({ - fieldMetadataItem, + fieldMetadataItem: field, filterValue, }); @@ -174,10 +174,10 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ - fieldMetadataItem, + fieldMetadataItem: field, filterValue: arrayOfSelectValues, }), - operand: RecordFilterOperand.IS, + operand: ViewFilterOperand.IS, type: 'SELECT', } satisfies RecordFilter); } @@ -188,7 +188,7 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ if (isNonEmptyString(filterValue)) { const { foundCorrespondingSelectOptions } = filterSelectOptionsOfFieldMetadataItem({ - fieldMetadataItem, + fieldMetadataItem: field, filterValue, }); @@ -201,10 +201,10 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ anyFieldRecordFilters.push({ ...createAnyFieldRecordFilterBaseProperties({ - fieldMetadataItem, + fieldMetadataItem: field, filterValue: arrayOfSelectValues, }), - operand: RecordFilterOperand.CONTAINS, + operand: ViewFilterOperand.CONTAINS, type: 'MULTI_SELECT', } satisfies RecordFilter); } @@ -218,7 +218,7 @@ export const turnAnyFieldFilterIntoRecordGqlFilter = ({ .map((recordFilter) => turnRecordFilterIntoRecordGqlOperationFilter({ filterValueDependencies: {}, - fieldMetadataItems: objectMetadataItem.fields, + fieldMetadataItems: fields, recordFilter, }), ) diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnAnyFieldFilterIntoRecordGqlFilter.test.ts b/packages/twenty-shared/src/utils/filter/utils/__tests__/turnAnyFieldFilterIntoRecordGqlFilter.test.ts similarity index 78% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnAnyFieldFilterIntoRecordGqlFilter.test.ts rename to packages/twenty-shared/src/utils/filter/utils/__tests__/turnAnyFieldFilterIntoRecordGqlFilter.test.ts index a6368763fa3..38d79b63542 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/__tests__/turnAnyFieldFilterIntoRecordGqlFilter.test.ts +++ b/packages/twenty-shared/src/utils/filter/utils/__tests__/turnAnyFieldFilterIntoRecordGqlFilter.test.ts @@ -1,95 +1,90 @@ -import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; -import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { filterSelectOptionsOfFieldMetadataItem } from '@/object-record/record-filter/utils/filterSelectOptionsOfFieldMetadataItem'; -import { turnAnyFieldFilterIntoRecordGqlFilter } from '@/object-record/record-filter/utils/turnAnyFieldFilterIntoRecordGqlFilter'; -import { FieldMetadataType } from '~/generated-metadata/graphql'; +import { FieldMetadataType, type PartialFieldMetadataItem } from "@/types"; +import { turnAnyFieldFilterIntoRecordGqlFilter } from "@/utils/filter/turnAnyFieldFilterIntoRecordGqlFilter"; +import { filterSelectOptionsOfFieldMetadataItem } from "@/utils/filter/utils/filterSelectOptionsOfFieldMetadataItem"; -const baseFieldMetadataItem: FieldMetadataItem = { + +const baseFieldMetadataItem: PartialFieldMetadataItem = { id: 'base-field-metadata-item-id', - createdAt: new Date().toISOString(), label: 'Test', name: 'test', type: FieldMetadataType.TEXT, - updatedAt: new Date().toISOString(), }; -const textFieldMetadataItem: FieldMetadataItem = { +const textFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'text-field-id', name: 'textField', }; -const addressFieldMetadataItem: FieldMetadataItem = { +const addressFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'address-field-id', type: FieldMetadataType.ADDRESS, name: 'addressField', }; -const linksFieldMetadataItem: FieldMetadataItem = { +const linksFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'links-field-id', type: FieldMetadataType.LINKS, name: 'linksField', }; -const fullNameFieldMetadataItem: FieldMetadataItem = { +const fullNameFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'full-name-field-id', type: FieldMetadataType.FULL_NAME, name: 'fullNameField', }; -const arrayFieldMetadataItem: FieldMetadataItem = { +const arrayFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'array-field-id', type: FieldMetadataType.ARRAY, name: 'arrayField', }; -const emailsFieldMetadataItem: FieldMetadataItem = { +const emailsFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'emails-field-id', type: FieldMetadataType.EMAILS, name: 'emailsField', }; -const phonesFieldMetadataItem: FieldMetadataItem = { +const phonesFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'phones-field-id', type: FieldMetadataType.PHONES, name: 'phonesField', }; -const numberFieldMetadataItem: FieldMetadataItem = { +const numberFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'number-field-id', type: FieldMetadataType.NUMBER, name: 'numberField', }; -const currencyFieldMetadataItem: FieldMetadataItem = { +const currencyFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'currency-field-id', type: FieldMetadataType.CURRENCY, name: 'currencyField', }; -const selectFieldMetadataItem: FieldMetadataItem = { +const selectFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'select-field-id', type: FieldMetadataType.SELECT, name: 'selectField', options: [ { - color: 'blue', id: '1', label: 'blue', position: 1, value: 'BLUE', }, { - color: 'red', id: '2', label: 'red', position: 2, @@ -98,21 +93,19 @@ const selectFieldMetadataItem: FieldMetadataItem = { ], }; -const multiSelectFieldMetadataItem: FieldMetadataItem = { +const multiSelectFieldMetadataItem: PartialFieldMetadataItem = { ...baseFieldMetadataItem, id: 'multi-select-field-id', type: FieldMetadataType.MULTI_SELECT, name: 'multiSelect', options: [ { - color: 'blue', id: '1', label: 'blue', position: 1, value: 'BLUE', }, { - color: 'red', id: '2', label: 'red', position: 2, @@ -121,7 +114,7 @@ const multiSelectFieldMetadataItem: FieldMetadataItem = { ], }; -const mockObjectMetadataItem: ObjectMetadataItem = { +const mockObjectMetadataItem = { id: 'mock-object-metadata-item', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), @@ -143,7 +136,7 @@ const mockObjectMetadataItem: ObjectMetadataItem = { updatableFields: [], }; -const mockObjectMetadataItemWithAllFields: ObjectMetadataItem = { +const mockObjectMetadataItemWithAllFields = { ...mockObjectMetadataItem, fields: [ textFieldMetadataItem, @@ -167,10 +160,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [textFieldMetadataItem], - }, + fields: [textFieldMetadataItem], }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -187,10 +177,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [addressFieldMetadataItem], - }, + fields: [addressFieldMetadataItem], }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -248,10 +235,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [linksFieldMetadataItem], - }, + fields: [linksFieldMetadataItem], }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -288,10 +272,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [fullNameFieldMetadataItem], - }, + fields: [fullNameFieldMetadataItem], }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -321,10 +302,8 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [arrayFieldMetadataItem], - }, + fields: [arrayFieldMetadataItem], + }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -341,10 +320,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [emailsFieldMetadataItem], - }, + fields: [emailsFieldMetadataItem], }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -374,10 +350,8 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [phonesFieldMetadataItem], - }, + fields: [phonesFieldMetadataItem], + }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -414,10 +388,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, fields: [numberFieldMetadataItem], - }, }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -432,10 +403,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [numberFieldMetadataItem], - }, + fields: [numberFieldMetadataItem], }); expect(result.recordGqlOperationFilter).toEqual({}); @@ -448,10 +416,8 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [currencyFieldMetadataItem], - }, + fields: [currencyFieldMetadataItem], + }); expect(result.recordGqlOperationFilter.or).toContainEqual({ @@ -468,10 +434,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [currencyFieldMetadataItem], - }, + fields: [currencyFieldMetadataItem], }); expect( @@ -488,10 +451,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [selectFieldMetadataItem], - }, + fields: [selectFieldMetadataItem], }); const { foundCorrespondingSelectOptions: expectedOptions } = @@ -512,10 +472,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [selectFieldMetadataItem], - }, + fields: [selectFieldMetadataItem], }); expect(result.recordGqlOperationFilter).toEqual({}); @@ -528,10 +485,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [multiSelectFieldMetadataItem], - }, + fields: [multiSelectFieldMetadataItem], }); const { foundCorrespondingSelectOptions: expectedOptions } = @@ -552,10 +506,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: { - ...mockObjectMetadataItem, - fields: [multiSelectFieldMetadataItem], - }, + fields: [multiSelectFieldMetadataItem], }); expect(result.recordGqlOperationFilter).toEqual({}); @@ -568,7 +519,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: mockObjectMetadataItemWithAllFields, + fields: mockObjectMetadataItemWithAllFields.fields, }); expect(result.recordGqlOperationFilter).toHaveProperty('or'); @@ -583,7 +534,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue, - objectMetadataItem: mockObjectMetadataItemWithAllFields, + fields: mockObjectMetadataItemWithAllFields.fields, }); expect(result.recordGqlOperationFilter).toEqual({}); @@ -597,7 +548,7 @@ describe('turnAnyFieldFilterIntoRecordGqlFilter', () => { const result = turnAnyFieldFilterIntoRecordGqlFilter({ filterValue: 'test', - objectMetadataItem: emptyObjectMetadata, + fields: emptyObjectMetadata.fields, }); expect(result.recordGqlOperationFilter).toEqual({}); diff --git a/packages/twenty-shared/src/utils/filter/utils/createAnyFieldRecordFilterBaseProperties.ts b/packages/twenty-shared/src/utils/filter/utils/createAnyFieldRecordFilterBaseProperties.ts new file mode 100644 index 00000000000..41ed70a347d --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/utils/createAnyFieldRecordFilterBaseProperties.ts @@ -0,0 +1,20 @@ +import { type PartialFieldMetadataItem } from '@/types'; +import { type RecordFilter } from '@/utils/filter'; +import { v4 } from 'uuid'; + +export const createAnyFieldRecordFilterBaseProperties = ({ + filterValue, + fieldMetadataItem, +}: { + filterValue: string; + fieldMetadataItem: PartialFieldMetadataItem; +}): Pick< + RecordFilter, + 'id' | 'value' | 'fieldMetadataId' +> => { + return { + id: v4(), + value: filterValue, + fieldMetadataId: fieldMetadataItem.id, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/filterSelectOptionsOfFieldMetadataItem.ts b/packages/twenty-shared/src/utils/filter/utils/filterSelectOptionsOfFieldMetadataItem.ts similarity index 81% rename from packages/twenty-front/src/modules/object-record/record-filter/utils/filterSelectOptionsOfFieldMetadataItem.ts rename to packages/twenty-shared/src/utils/filter/utils/filterSelectOptionsOfFieldMetadataItem.ts index 331fedf2c10..a7d9f6fc7a8 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/filterSelectOptionsOfFieldMetadataItem.ts +++ b/packages/twenty-shared/src/utils/filter/utils/filterSelectOptionsOfFieldMetadataItem.ts @@ -1,10 +1,10 @@ -import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; +import { type PartialFieldMetadataItem } from "@/types"; export const filterSelectOptionsOfFieldMetadataItem = ({ fieldMetadataItem, filterValue, }: { - fieldMetadataItem: FieldMetadataItem; + fieldMetadataItem: PartialFieldMetadataItem; filterValue: string; }) => { const selectOptions = fieldMetadataItem.options; diff --git a/packages/twenty-shared/src/utils/index.ts b/packages/twenty-shared/src/utils/index.ts index 27f97d77b6a..0e5d49165fb 100644 --- a/packages/twenty-shared/src/utils/index.ts +++ b/packages/twenty-shared/src/utils/index.ts @@ -12,6 +12,7 @@ export { filterOutByProperty } from './array/filterOutByProperty'; export { findById } from './array/findById'; export { findByProperty } from './array/findByProperty'; export { findOrThrow } from './array/findOrThrow'; +export { isNonEmptyArray } from './array/isNonEmptyArray'; export { sumByProperty } from './array/sumByProperty'; export { assertUnreachable } from './assertUnreachable'; export { computeDiffBetweenObjects } from './compute-diff-between-objects'; @@ -27,6 +28,7 @@ export { computeEmptyGqlOperationFilterForEmails } from './filter/computeEmptyGq export { computeEmptyGqlOperationFilterForLinks } from './filter/computeEmptyGqlOperationFilterForLinks'; export { computeRecordGqlOperationFilter } from './filter/computeRecordGqlOperationFilter'; export { isEmptinessOperand } from './filter/isEmptinessOperand'; +export { turnAnyFieldFilterIntoRecordGqlFilter } from './filter/turnAnyFieldFilterIntoRecordGqlFilter'; export type { RecordFilter, RecordFilterGroup, @@ -35,11 +37,13 @@ export { turnRecordFilterGroupsIntoGqlOperationFilter } from './filter/turnRecor export { turnRecordFilterIntoRecordGqlOperationFilter } from './filter/turnRecordFilterIntoGqlOperationFilter'; export { combineFilters } from './filter/utils/combineFilters'; export { convertViewFilterValueToString } from './filter/utils/convertViewFilterValueToString'; +export { createAnyFieldRecordFilterBaseProperties } from './filter/utils/createAnyFieldRecordFilterBaseProperties'; export { convertGreaterThanOrEqualRatingToArrayOfRatingValues, convertLessThanOrEqualRatingToArrayOfRatingValues, convertRatingToRatingValue, } from './filter/utils/fieldRatingConvertors'; +export { filterSelectOptionsOfFieldMetadataItem } from './filter/utils/filterSelectOptionsOfFieldMetadataItem'; export { generateILikeFiltersForCompositeFields } from './filter/utils/generateILikeFiltersForCompositeFields'; export { getEmptyRecordGqlOperationFilter } from './filter/utils/getEmptyRecordGqlOperationFilter'; export { getFilterTypeFromFieldType } from './filter/utils/getFilterTypeFromFieldType';