diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useExportProcessRecordsForCSV.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useExportProcessRecordsForCSV.ts
index 2eb9eb433..0bce87764 100644
--- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useExportProcessRecordsForCSV.ts
+++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useExportProcessRecordsForCSV.ts
@@ -1,9 +1,9 @@
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { FieldCurrencyValue } from '@/object-record/record-field/types/FieldMetadata';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
+import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { convertCurrencyMicrosToCurrencyAmount } from '~/utils/convertCurrencyToCurrencyMicros';
-import { isDefined } from 'twenty-shared/utils';
export const useExportProcessRecordsForCSV = (objectNameSingular: string) => {
const { objectMetadataItem } = useObjectMetadataItem({
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/CurrencyFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/CurrencyFieldDisplay.tsx
index bbf110d16..8ba76547e 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/CurrencyFieldDisplay.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/CurrencyFieldDisplay.tsx
@@ -2,7 +2,12 @@ import { useCurrencyFieldDisplay } from '@/object-record/record-field/meta-types
import { CurrencyDisplay } from '@/ui/field/display/components/CurrencyDisplay';
export const CurrencyFieldDisplay = () => {
- const { fieldValue } = useCurrencyFieldDisplay();
+ const { fieldValue, fieldDefinition } = useCurrencyFieldDisplay();
- return ;
+ return (
+
+ );
};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useCurrencyFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useCurrencyFieldDisplay.ts
index 7b78c9b11..7ba20a7d1 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useCurrencyFieldDisplay.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useCurrencyFieldDisplay.ts
@@ -2,12 +2,21 @@ import { useContext } from 'react';
import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
+import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
+import { isFieldCurrency } from '@/object-record/record-field/types/guards/isFieldCurrency';
+import { FieldMetadataType } from 'twenty-shared/types';
import { FieldContext } from '../../contexts/FieldContext';
import { FieldCurrencyValue } from '../../types/FieldMetadata';
export const useCurrencyFieldDisplay = () => {
const { recordId, fieldDefinition } = useContext(FieldContext);
+ assertFieldMetadata(
+ FieldMetadataType.CURRENCY,
+ isFieldCurrency,
+ fieldDefinition,
+ );
+
const fieldName = fieldDefinition.metadata.fieldName;
const fieldValue = useRecordFieldValue(
diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts b/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts
index 40689f517..632cbe916 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/types/FieldMetadata.ts
@@ -84,7 +84,9 @@ export type FieldLinksMetadata = BaseFieldMetadata & {
export type FieldCurrencyMetadata = BaseFieldMetadata & {
placeHolder: string;
isPositive?: boolean;
- settings?: null;
+ settings?: {
+ format: FieldCurrencyFormat | null;
+ };
};
export type FieldFullNameMetadata = BaseFieldMetadata & {
@@ -211,6 +213,9 @@ export type FieldLinksValue = {
primaryLinkUrl: string | null;
secondaryLinks?: { label: string | null; url: string | null }[] | null;
};
+
+export const fieldMetadataCurrencyFormat = ['short', 'full'] as const;
+export type FieldCurrencyFormat = (typeof fieldMetadataCurrencyFormat)[number];
export type FieldCurrencyValue = {
currencyCode: CurrencyCode;
amountMicros: number | null;
diff --git a/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/currencyFieldSettingsSchema.ts b/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/currencyFieldSettingsSchema.ts
new file mode 100644
index 000000000..473087f1b
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/validation-schemas/currencyFieldSettingsSchema.ts
@@ -0,0 +1,6 @@
+import { fieldMetadataCurrencyFormat } from '@/object-record/record-field/types/FieldMetadata';
+import { z } from 'zod';
+
+export const currencyFieldSettingsSchema = z.object({
+ format: z.enum(fieldMetadataCurrencyFormat),
+});
diff --git a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportProcessRecordsForCSV.ts b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportProcessRecordsForCSV.ts
index 8cd6b2aab..28fd0745d 100644
--- a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportProcessRecordsForCSV.ts
+++ b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportProcessRecordsForCSV.ts
@@ -1,9 +1,9 @@
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { FieldCurrencyValue } from '@/object-record/record-field/types/FieldMetadata';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
+import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { convertCurrencyMicrosToCurrencyAmount } from '~/utils/convertCurrencyToCurrencyMicros';
-import { isDefined } from 'twenty-shared/utils';
export const useExportProcessRecordsForCSV = (objectNameSingular: string) => {
const { objectMetadataItem } = useObjectMetadataItem({
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsObjectNewFieldSelector.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsObjectNewFieldSelector.tsx
index bb3f874f2..1fde22271 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsObjectNewFieldSelector.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsObjectNewFieldSelector.tsx
@@ -13,22 +13,22 @@ import { SettingsPath } from '@/types/SettingsPath';
import { TextInput } from '@/ui/input/components/TextInput';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import { t } from '@lingui/core/macro';
import { Section } from '@react-email/components';
import { useState } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
+import { H2Title, IconSearch } from 'twenty-ui/display';
+import { UndecoratedLink } from 'twenty-ui/navigation';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { SettingsDataModelFieldTypeFormValues } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldSelect';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
-import { t } from '@lingui/core/macro';
-import { H2Title, IconSearch } from 'twenty-ui/display';
-import { UndecoratedLink } from 'twenty-ui/navigation';
type SettingsObjectNewFieldSelectorProps = {
className?: string;
excludedFieldTypes?: FieldType[];
fieldMetadataItem?: Pick<
FieldMetadataItem,
- 'defaultValue' | 'options' | 'type'
+ 'defaultValue' | 'options' | 'type' | 'settings'
>;
objectNamePlural: string;
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm.tsx
index cab05076a..6e53d59ca 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm.tsx
@@ -2,17 +2,20 @@ import { Controller, useFormContext } from 'react-hook-form';
import { z } from 'zod';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
+import { FieldCurrencyFormat } from '@/object-record/record-field/types/FieldMetadata';
import { currencyFieldDefaultValueSchema } from '@/object-record/record-field/validation-schemas/currencyFieldDefaultValueSchema';
+import { currencyFieldSettingsSchema } from '@/object-record/record-field/validation-schemas/currencyFieldSettingsSchema';
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
import { Select } from '@/ui/input/components/Select';
import { useLingui } from '@lingui/react/macro';
-import { IconCurrencyDollar } from 'twenty-ui/display';
+import { IconCheckbox, IconCurrencyDollar } from 'twenty-ui/display';
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
export const settingsDataModelFieldCurrencyFormSchema = z.object({
defaultValue: currencyFieldDefaultValueSchema,
+ settings: currencyFieldSettingsSchema,
});
export type SettingsDataModelFieldCurrencyFormValues = z.infer<
@@ -21,7 +24,10 @@ export type SettingsDataModelFieldCurrencyFormValues = z.infer<
type SettingsDataModelFieldCurrencyFormProps = {
disabled?: boolean;
- fieldMetadataItem: Pick;
+ fieldMetadataItem: Pick<
+ FieldMetadataItem,
+ 'icon' | 'label' | 'type' | 'defaultValue' | 'settings'
+ >;
};
export const SettingsDataModelFieldCurrencyForm = ({
@@ -29,12 +35,16 @@ export const SettingsDataModelFieldCurrencyForm = ({
fieldMetadataItem,
}: SettingsDataModelFieldCurrencyFormProps) => {
const { t } = useLingui();
+ const {
+ initialAmountMicrosValue,
+ initialCurrencyCodeValue,
+ initialSettingsValue,
+ } = useCurrencySettingsFormInitialValues({
+ fieldMetadataItem,
+ });
const { control } =
useFormContext();
- const { initialAmountMicrosValue, initialCurrencyCodeValue } =
- useCurrencySettingsFormInitialValues({ fieldMetadataItem });
-
return (
<>
)}
/>
+ (
+
+
+ )}
+ />
>
);
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencySettingsFormCard.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencySettingsFormCard.tsx
index 3112b316c..708bdc16f 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencySettingsFormCard.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencySettingsFormCard.tsx
@@ -1,5 +1,5 @@
-import { useFormContext } from 'react-hook-form';
import styled from '@emotion/styled';
+import { useFormContext } from 'react-hook-form';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
@@ -17,7 +17,7 @@ type SettingsDataModelFieldCurrencySettingsFormCardProps = {
disabled?: boolean;
fieldMetadataItem: Pick<
FieldMetadataItem,
- 'icon' | 'label' | 'type' | 'defaultValue'
+ 'icon' | 'label' | 'type' | 'defaultValue' | 'settings'
>;
} & Pick;
@@ -31,9 +31,10 @@ export const SettingsDataModelFieldCurrencySettingsFormCard = ({
fieldMetadataItem,
objectMetadataItem,
}: SettingsDataModelFieldCurrencySettingsFormCardProps) => {
- const { initialDefaultValue } = useCurrencySettingsFormInitialValues({
- fieldMetadataItem,
- });
+ const { initialDefaultValue, initialSettingsValue } =
+ useCurrencySettingsFormInitialValues({
+ fieldMetadataItem,
+ });
const { watch: watchFormValue } =
useFormContext();
@@ -45,6 +46,7 @@ export const SettingsDataModelFieldCurrencySettingsFormCard = ({
fieldMetadataItem={{
...fieldMetadataItem,
defaultValue: watchFormValue('defaultValue', initialDefaultValue),
+ settings: watchFormValue('settings', initialSettingsValue),
}}
objectMetadataItem={objectMetadataItem}
/>
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 d9ca44541..cf5dc4ab2 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
@@ -5,31 +5,42 @@ import { CurrencyCode } from '@/object-record/record-field/types/CurrencyCode';
import { SettingsDataModelFieldCurrencyFormValues } from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm';
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
+type UseCurrencySettingsFormInitialValuesArgs = {
+ fieldMetadataItem?: Pick;
+};
export const useCurrencySettingsFormInitialValues = ({
fieldMetadataItem,
-}: {
- fieldMetadataItem?: Pick;
-}) => {
+}: UseCurrencySettingsFormInitialValuesArgs) => {
const initialAmountMicrosValue =
(fieldMetadataItem?.defaultValue?.amountMicros as number | null) ?? null;
const initialCurrencyCodeValue =
fieldMetadataItem?.defaultValue?.currencyCode ??
applySimpleQuotesToString(CurrencyCode.USD);
- const initialDefaultValue = {
- amountMicros: initialAmountMicrosValue,
- currencyCode: initialCurrencyCodeValue,
+ const initialFormValues: SettingsDataModelFieldCurrencyFormValues = {
+ settings: {
+ format: fieldMetadataItem?.settings?.format ?? 'short',
+ },
+ defaultValue: {
+ amountMicros: initialAmountMicrosValue,
+ currencyCode: initialCurrencyCodeValue,
+ },
};
const { resetField } =
useFormContext();
- const resetDefaultValueField = () =>
- resetField('defaultValue', { defaultValue: initialDefaultValue });
+ const resetDefaultValueField = () => {
+ resetField('defaultValue', {
+ defaultValue: initialFormValues.defaultValue,
+ });
+ resetField('settings', { defaultValue: initialFormValues.settings });
+ };
return {
initialAmountMicrosValue,
initialCurrencyCodeValue,
- initialDefaultValue,
+ initialSettingsValue: initialFormValues.settings,
+ initialDefaultValue: initialFormValues.defaultValue,
resetDefaultValueField,
};
};
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 1cc84e4eb..c8263c37d 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
@@ -11,7 +11,7 @@ export const getCurrencyFieldPreviewValue = ({
}: {
fieldMetadataItem: Pick<
FieldMetadataItem,
- 'defaultValue' | 'options' | 'type'
+ 'defaultValue' | 'options' | 'type' | 'settings'
>;
}): FieldCurrencyValue | null => {
if (fieldMetadataItem.type !== FieldMetadataType.CURRENCY) return null;
diff --git a/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx
index c21898b2a..92f102a8a 100644
--- a/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx
+++ b/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx
@@ -1,17 +1,26 @@
import { useTheme } from '@emotion/react';
-import { FieldCurrencyValue } from '@/object-record/record-field/types/FieldMetadata';
+import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
+import {
+ FieldCurrencyMetadata,
+ FieldCurrencyValue,
+} from '@/object-record/record-field/types/FieldMetadata';
import { SETTINGS_FIELD_CURRENCY_CODES } from '@/settings/data-model/constants/SettingsFieldCurrencyCodes';
import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
import { isDefined } from 'twenty-shared/utils';
import { formatAmount } from '~/utils/format/formatAmount';
+import { formatNumber } from '~/utils/format/number';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
type CurrencyDisplayProps = {
currencyValue: FieldCurrencyValue | null | undefined;
+ fieldDefinition: FieldDefinition;
};
-export const CurrencyDisplay = ({ currencyValue }: CurrencyDisplayProps) => {
+export const CurrencyDisplay = ({
+ currencyValue,
+ fieldDefinition,
+}: CurrencyDisplayProps) => {
const theme = useTheme();
const shouldDisplayCurrency = isDefined(currencyValue?.currencyCode);
@@ -24,6 +33,8 @@ export const CurrencyDisplay = ({ currencyValue }: CurrencyDisplayProps) => {
? null
: currencyValue?.amountMicros / 1000000;
+ const format = fieldDefinition.metadata.settings?.format;
+
if (!shouldDisplayCurrency) {
return {0};
}
@@ -39,7 +50,11 @@ export const CurrencyDisplay = ({ currencyValue }: CurrencyDisplayProps) => {
/>{' '}
>
)}
- {amountToDisplay !== null ? formatAmount(amountToDisplay) : ''}
+ {amountToDisplay !== null
+ ? !isDefined(format) || format === 'short'
+ ? formatAmount(amountToDisplay)
+ : formatNumber(amountToDisplay)
+ : null}
);
};
diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows.ts
index 9e0cb3380..58cc95af3 100644
--- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows.ts
+++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows.ts
@@ -1,5 +1,5 @@
-import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
+import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
const QUICK_LEAD_WORKFLOW_ID = '8b213cac-a68b-4ffe-817a-3ec994e9932d';
const QUICK_LEAD_WORKFLOW_VERSION_ID = 'ac67974f-c524-4288-9d88-af8515400b68';