[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
This commit is contained in:
Marie
2025-09-30 16:13:40 +00:00
committed by GitHub
parent 3927b36406
commit f33396e425
46 changed files with 805 additions and 549 deletions
@@ -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') {
@@ -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<
@@ -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,
@@ -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,
@@ -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 = {
@@ -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';
@@ -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';
@@ -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',
}
@@ -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;
@@ -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;
@@ -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({
@@ -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 = {
@@ -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 = {
@@ -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);
@@ -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';
@@ -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,
};
};
@@ -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,
});
@@ -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,
});
@@ -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,
});
@@ -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,
});
@@ -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();
@@ -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,
@@ -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 },
};
@@ -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';
@@ -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',
@@ -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';
@@ -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 =
@@ -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<keyof Role> = [
'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: {
@@ -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';
@@ -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,
});
@@ -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;
}
@@ -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] }),
]),
);
});
});
});
@@ -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',
}
@@ -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' },
};
@@ -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';
@@ -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;
}
@@ -0,0 +1,7 @@
export type PartialFieldMetadataItemOption = {
id: string;
label: string;
position: number;
value: string;
};
@@ -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 {
@@ -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', () => {
@@ -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';
@@ -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,
}),
)
@@ -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({});
@@ -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,
};
};
@@ -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;
@@ -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';