refactor: reset field default value on type change in Settings (#5534)

Related issue: #5412

See https://github.com/twentyhq/twenty/pull/5436#discussion_r1609470484
for context.
This commit is contained in:
Thaïs
2024-05-24 12:15:17 +02:00
committed by GitHub
parent 18fafbdeb5
commit 7f7ea59b51
23 changed files with 326 additions and 131 deletions

View File

@ -1,7 +1,7 @@
import { z } from 'zod'; import { z } from 'zod';
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/utils/getOptionValueFromLabel'; import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
import { themeColorSchema } from '@/ui/theme/utils/themeColorSchema'; import { themeColorSchema } from '@/ui/theme/utils/themeColorSchema';
import { computeOptionValueFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils'; import { computeOptionValueFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';

View File

@ -1,10 +1,10 @@
import { useEffect } from 'react';
import { Controller, useFormContext } from 'react-hook-form'; import { Controller, useFormContext } from 'react-hook-form';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { IconCheck, IconX } from 'twenty-ui'; import { IconCheck, IconX } from 'twenty-ui';
import { z } from 'zod'; import { z } from 'zod';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/fields/forms/boolean/hooks/useBooleanSettingsFormInitialValues';
import { Select } from '@/ui/input/components/Select'; import { Select } from '@/ui/input/components/Select';
import { CardContent } from '@/ui/layout/card/components/CardContent'; import { CardContent } from '@/ui/layout/card/components/CardContent';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
@ -13,13 +13,13 @@ export const settingsDataModelFieldBooleanFormSchema = z.object({
defaultValue: z.boolean(), defaultValue: z.boolean(),
}); });
type SettingsDataModelFieldBooleanFormValues = z.infer< export type SettingsDataModelFieldBooleanFormValues = z.infer<
typeof settingsDataModelFieldBooleanFormSchema typeof settingsDataModelFieldBooleanFormSchema
>; >;
type SettingsDataModelFieldBooleanFormProps = { type SettingsDataModelFieldBooleanFormProps = {
className?: string; className?: string;
fieldMetadataItem?: Pick<FieldMetadataItem, 'defaultValue'>; fieldMetadataItem: Pick<FieldMetadataItem, 'defaultValue'>;
}; };
const StyledContainer = styled(CardContent)` const StyledContainer = styled(CardContent)`
@ -38,16 +38,12 @@ export const SettingsDataModelFieldBooleanForm = ({
className, className,
fieldMetadataItem, fieldMetadataItem,
}: SettingsDataModelFieldBooleanFormProps) => { }: SettingsDataModelFieldBooleanFormProps) => {
const { control, resetField } = const { control } = useFormContext<SettingsDataModelFieldBooleanFormValues>();
useFormContext<SettingsDataModelFieldBooleanFormValues>();
const isEditMode = isDefined(fieldMetadataItem?.defaultValue); const isEditMode = isDefined(fieldMetadataItem?.defaultValue);
const initialValue = fieldMetadataItem?.defaultValue ?? true; const { initialDefaultValue } = useBooleanSettingsFormInitialValues({
fieldMetadataItem,
// Reset defaultValue on mount, so it doesn't conflict with other field types. });
useEffect(() => {
resetField('defaultValue', { defaultValue: initialValue });
}, [initialValue, resetField]);
return ( return (
<StyledContainer> <StyledContainer>
@ -55,7 +51,7 @@ export const SettingsDataModelFieldBooleanForm = ({
<Controller <Controller
name="defaultValue" name="defaultValue"
control={control} control={control}
defaultValue={initialValue} defaultValue={initialDefaultValue}
render={({ field: { onChange, value } }) => ( render={({ field: { onChange, value } }) => (
<Select <Select
className={className} className={className}

View File

@ -0,0 +1,57 @@
import { useFormContext } from 'react-hook-form';
import styled from '@emotion/styled';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
import {
SettingsDataModelFieldBooleanForm,
SettingsDataModelFieldBooleanFormValues,
} from '@/settings/data-model/fields/forms/boolean/components/SettingsDataModelFieldBooleanForm';
import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/fields/forms/boolean/hooks/useBooleanSettingsFormInitialValues';
import {
SettingsDataModelFieldPreviewCard,
SettingsDataModelFieldPreviewCardProps,
} from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard';
type SettingsDataModelFieldBooleanSettingsFormCardProps = {
fieldMetadataItem: Pick<
FieldMetadataItem,
'icon' | 'label' | 'type' | 'defaultValue'
>;
} & Pick<SettingsDataModelFieldPreviewCardProps, 'objectMetadataItem'>;
const StyledFieldPreviewCard = styled(SettingsDataModelFieldPreviewCard)`
display: grid;
flex: 1 1 100%;
`;
export const SettingsDataModelFieldBooleanSettingsFormCard = ({
fieldMetadataItem,
objectMetadataItem,
}: SettingsDataModelFieldBooleanSettingsFormCardProps) => {
const { initialDefaultValue } = useBooleanSettingsFormInitialValues({
fieldMetadataItem,
});
const { watch: watchFormValue } =
useFormContext<SettingsDataModelFieldBooleanFormValues>();
return (
<SettingsDataModelPreviewFormCard
preview={
<StyledFieldPreviewCard
fieldMetadataItem={{
...fieldMetadataItem,
defaultValue: watchFormValue('defaultValue', initialDefaultValue),
}}
objectMetadataItem={objectMetadataItem}
/>
}
form={
<SettingsDataModelFieldBooleanForm
fieldMetadataItem={fieldMetadataItem}
/>
}
/>
);
};

View File

@ -0,0 +1,26 @@
import { useFormContext } from 'react-hook-form';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsDataModelFieldBooleanFormValues } from '@/settings/data-model/fields/forms/boolean/components/SettingsDataModelFieldBooleanForm';
export const useBooleanSettingsFormInitialValues = ({
fieldMetadataItem,
}: {
fieldMetadataItem?: Pick<FieldMetadataItem, 'defaultValue'>;
}) => {
const initialDefaultValue =
(fieldMetadataItem?.defaultValue as SettingsDataModelFieldBooleanFormValues['defaultValue']) ??
true;
const { resetField } =
useFormContext<SettingsDataModelFieldBooleanFormValues>();
const resetDefaultValueField = () => {
resetField('defaultValue', { defaultValue: initialDefaultValue });
};
return {
initialDefaultValue,
resetDefaultValueField,
};
};

View File

@ -5,21 +5,17 @@ import { z } from 'zod';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard'; import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsFieldTypeConfigs'; import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
import { import { settingsDataModelFieldBooleanFormSchema } from '@/settings/data-model/fields/forms/boolean/components/SettingsDataModelFieldBooleanForm';
SettingsDataModelFieldBooleanForm, import { SettingsDataModelFieldBooleanSettingsFormCard } from '@/settings/data-model/fields/forms/boolean/components/SettingsDataModelFieldBooleanSettingsFormCard';
settingsDataModelFieldBooleanFormSchema, import { settingsDataModelFieldCurrencyFormSchema } from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm';
} from '@/settings/data-model/fields/forms/components/boolean/SettingsDataModelFieldBooleanForm'; import { SettingsDataModelFieldCurrencySettingsFormCard } from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencySettingsFormCard';
import { import { settingsDataModelFieldRelationFormSchema } from '@/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm';
SettingsDataModelFieldCurrencyForm, import { SettingsDataModelFieldRelationSettingsFormCard } from '@/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationSettingsFormCard';
settingsDataModelFieldCurrencyFormSchema,
} from '@/settings/data-model/fields/forms/components/currency/SettingsDataModelFieldCurrencyForm';
import { settingsDataModelFieldRelationFormSchema } from '@/settings/data-model/fields/forms/components/relation/SettingsDataModelFieldRelationForm';
import { SettingsDataModelFieldRelationSettingsFormCard } from '@/settings/data-model/fields/forms/components/relation/SettingsDataModelFieldRelationSettingsFormCard';
import { import {
settingsDataModelFieldMultiSelectFormSchema, settingsDataModelFieldMultiSelectFormSchema,
settingsDataModelFieldSelectFormSchema, settingsDataModelFieldSelectFormSchema,
} from '@/settings/data-model/fields/forms/components/select/SettingsDataModelFieldSelectForm'; } from '@/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm';
import { SettingsDataModelFieldSelectSettingsFormCard } from '@/settings/data-model/fields/forms/components/select/SettingsDataModelFieldSelectSettingsFormCard'; import { SettingsDataModelFieldSelectSettingsFormCard } from '@/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectSettingsFormCard';
import { import {
SettingsDataModelFieldPreviewCard, SettingsDataModelFieldPreviewCard,
SettingsDataModelFieldPreviewCardProps, SettingsDataModelFieldPreviewCardProps,
@ -108,6 +104,25 @@ export const SettingsDataModelFieldSettingsFormCard = ({
}: SettingsDataModelFieldSettingsFormCardProps) => { }: SettingsDataModelFieldSettingsFormCardProps) => {
if (!previewableTypes.includes(fieldMetadataItem.type)) return null; if (!previewableTypes.includes(fieldMetadataItem.type)) return null;
if (fieldMetadataItem.type === FieldMetadataType.Boolean) {
return (
<SettingsDataModelFieldBooleanSettingsFormCard
fieldMetadataItem={fieldMetadataItem}
objectMetadataItem={objectMetadataItem}
/>
);
}
if (fieldMetadataItem.type === FieldMetadataType.Currency) {
return (
<SettingsDataModelFieldCurrencySettingsFormCard
disabled={disableCurrencyForm}
fieldMetadataItem={fieldMetadataItem}
objectMetadataItem={objectMetadataItem}
/>
);
}
if (fieldMetadataItem.type === FieldMetadataType.Relation) { if (fieldMetadataItem.type === FieldMetadataType.Relation) {
return ( return (
<SettingsDataModelFieldRelationSettingsFormCard <SettingsDataModelFieldRelationSettingsFormCard
@ -137,18 +152,6 @@ export const SettingsDataModelFieldSettingsFormCard = ({
objectMetadataItem={objectMetadataItem} objectMetadataItem={objectMetadataItem}
/> />
} }
form={
fieldMetadataItem.type === FieldMetadataType.Boolean ? (
<SettingsDataModelFieldBooleanForm
fieldMetadataItem={fieldMetadataItem}
/>
) : fieldMetadataItem.type === FieldMetadataType.Currency ? (
<SettingsDataModelFieldCurrencyForm
disabled={disableCurrencyForm}
fieldMetadataItem={fieldMetadataItem}
/>
) : undefined
}
/> />
); );
}; };

View File

@ -7,6 +7,9 @@ import {
SETTINGS_FIELD_TYPE_CONFIGS, SETTINGS_FIELD_TYPE_CONFIGS,
SettingsFieldTypeConfig, SettingsFieldTypeConfig,
} from '@/settings/data-model/constants/SettingsFieldTypeConfigs'; } from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/fields/forms/boolean/hooks/useBooleanSettingsFormInitialValues';
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues';
import { SettingsSupportedFieldType } from '@/settings/data-model/types/SettingsSupportedFieldType'; import { SettingsSupportedFieldType } from '@/settings/data-model/types/SettingsSupportedFieldType';
import { Select, SelectOption } from '@/ui/input/components/Select'; import { Select, SelectOption } from '@/ui/input/components/Select';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
@ -28,7 +31,10 @@ type SettingsDataModelFieldTypeSelectProps = {
className?: string; className?: string;
disabled?: boolean; disabled?: boolean;
excludedFieldTypes?: SettingsSupportedFieldType[]; excludedFieldTypes?: SettingsSupportedFieldType[];
fieldMetadataItem?: FieldMetadataItem; fieldMetadataItem?: Pick<
FieldMetadataItem,
'defaultValue' | 'options' | 'type'
>;
}; };
export const SettingsDataModelFieldTypeSelect = ({ export const SettingsDataModelFieldTypeSelect = ({
@ -51,6 +57,34 @@ export const SettingsDataModelFieldTypeSelect = ({
value: key as SettingsSupportedFieldType, value: key as SettingsSupportedFieldType,
})); }));
const { resetDefaultValueField: resetBooleanDefaultValueField } =
useBooleanSettingsFormInitialValues({ fieldMetadataItem });
const { resetDefaultValueField: resetCurrencyDefaultValueField } =
useCurrencySettingsFormInitialValues({ fieldMetadataItem });
const { resetDefaultValueField: resetSelectDefaultValueField } =
useSelectSettingsFormInitialValues({ fieldMetadataItem });
// Reset defaultValue on type change with a valid value for the selected type
// so the form does not become invalid.
const resetDefaultValueField = (nextValue: SettingsSupportedFieldType) => {
switch (nextValue) {
case FieldMetadataType.Boolean:
resetBooleanDefaultValueField();
break;
case FieldMetadataType.Currency:
resetCurrencyDefaultValueField();
break;
case FieldMetadataType.Select:
case FieldMetadataType.MultiSelect:
resetSelectDefaultValueField();
break;
default:
break;
}
};
return ( return (
<Controller <Controller
name="type" name="type"
@ -67,7 +101,10 @@ export const SettingsDataModelFieldTypeSelect = ({
disabled={disabled} disabled={disabled}
dropdownId="object-field-type-select" dropdownId="object-field-type-select"
value={value} value={value}
onChange={onChange} onChange={(nextValue) => {
onChange(nextValue);
resetDefaultValueField(nextValue);
}}
options={fieldTypeOptions} options={fieldTypeOptions}
/> />
)} )}

View File

@ -1,11 +1,10 @@
import { useEffect } from 'react';
import { Controller, useFormContext } from 'react-hook-form'; import { Controller, useFormContext } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { CurrencyCode } from '@/object-record/record-field/types/CurrencyCode';
import { currencyCodeSchema } from '@/object-record/record-field/validation-schemas/currencyCodeSchema'; import { currencyCodeSchema } from '@/object-record/record-field/validation-schemas/currencyCodeSchema';
import { SETTINGS_FIELD_CURRENCY_CODES } from '@/settings/data-model/constants/SettingsFieldCurrencyCodes'; import { SETTINGS_FIELD_CURRENCY_CODES } from '@/settings/data-model/constants/SettingsFieldCurrencyCodes';
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
import { Select } from '@/ui/input/components/Select'; import { Select } from '@/ui/input/components/Select';
import { CardContent } from '@/ui/layout/card/components/CardContent'; import { CardContent } from '@/ui/layout/card/components/CardContent';
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString'; import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
@ -14,7 +13,7 @@ import { simpleQuotesStringSchema } from '~/utils/validation-schemas/simpleQuote
export const settingsDataModelFieldCurrencyFormSchema = z.object({ export const settingsDataModelFieldCurrencyFormSchema = z.object({
defaultValue: z.object({ defaultValue: z.object({
amountMicros: z.null(), amountMicros: z.number().nullable(),
currencyCode: simpleQuotesStringSchema.refine( currencyCode: simpleQuotesStringSchema.refine(
(value) => (value) =>
currencyCodeSchema.safeParse(stripSimpleQuotesFromString(value)) currencyCodeSchema.safeParse(stripSimpleQuotesFromString(value))
@ -24,13 +23,13 @@ export const settingsDataModelFieldCurrencyFormSchema = z.object({
}), }),
}); });
type SettingsDataModelFieldCurrencyFormValues = z.infer< export type SettingsDataModelFieldCurrencyFormValues = z.infer<
typeof settingsDataModelFieldCurrencyFormSchema typeof settingsDataModelFieldCurrencyFormSchema
>; >;
type SettingsDataModelFieldCurrencyFormProps = { type SettingsDataModelFieldCurrencyFormProps = {
disabled?: boolean; disabled?: boolean;
fieldMetadataItem?: Pick<FieldMetadataItem, 'defaultValue'>; fieldMetadataItem: Pick<FieldMetadataItem, 'defaultValue'>;
}; };
const OPTIONS = Object.entries(SETTINGS_FIELD_CURRENCY_CODES).map( const OPTIONS = Object.entries(SETTINGS_FIELD_CURRENCY_CODES).map(
@ -45,25 +44,11 @@ export const SettingsDataModelFieldCurrencyForm = ({
disabled, disabled,
fieldMetadataItem, fieldMetadataItem,
}: SettingsDataModelFieldCurrencyFormProps) => { }: SettingsDataModelFieldCurrencyFormProps) => {
const { control, resetField } = const { control } =
useFormContext<SettingsDataModelFieldCurrencyFormValues>(); useFormContext<SettingsDataModelFieldCurrencyFormValues>();
const initialAmountMicrosValue = null; const { initialAmountMicrosValue, initialCurrencyCodeValue } =
const initialCurrencyCode = useCurrencySettingsFormInitialValues({ fieldMetadataItem });
(fieldMetadataItem?.defaultValue?.currencyCode as CurrencyCode) ??
CurrencyCode.USD;
const initialCurrencyCodeValue =
applySimpleQuotesToString(initialCurrencyCode);
// Reset defaultValue on mount, so it doesn't conflict with other field types.
useEffect(() => {
resetField('defaultValue', {
defaultValue: {
amountMicros: initialAmountMicrosValue,
currencyCode: initialCurrencyCodeValue,
},
});
}, [initialCurrencyCodeValue, resetField]);
return ( return (
<CardContent> <CardContent>

View File

@ -0,0 +1,60 @@
import { useFormContext } from 'react-hook-form';
import styled from '@emotion/styled';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
import {
SettingsDataModelFieldCurrencyForm,
SettingsDataModelFieldCurrencyFormValues,
} from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm';
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
import {
SettingsDataModelFieldPreviewCard,
SettingsDataModelFieldPreviewCardProps,
} from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard';
type SettingsDataModelFieldCurrencySettingsFormCardProps = {
disabled?: boolean;
fieldMetadataItem: Pick<
FieldMetadataItem,
'icon' | 'label' | 'type' | 'defaultValue'
>;
} & Pick<SettingsDataModelFieldPreviewCardProps, 'objectMetadataItem'>;
const StyledFieldPreviewCard = styled(SettingsDataModelFieldPreviewCard)`
display: grid;
flex: 1 1 100%;
`;
export const SettingsDataModelFieldCurrencySettingsFormCard = ({
disabled,
fieldMetadataItem,
objectMetadataItem,
}: SettingsDataModelFieldCurrencySettingsFormCardProps) => {
const { initialDefaultValue } = useCurrencySettingsFormInitialValues({
fieldMetadataItem,
});
const { watch: watchFormValue } =
useFormContext<SettingsDataModelFieldCurrencyFormValues>();
return (
<SettingsDataModelPreviewFormCard
preview={
<StyledFieldPreviewCard
fieldMetadataItem={{
...fieldMetadataItem,
defaultValue: watchFormValue('defaultValue', initialDefaultValue),
}}
objectMetadataItem={objectMetadataItem}
/>
}
form={
<SettingsDataModelFieldCurrencyForm
disabled={disabled}
fieldMetadataItem={fieldMetadataItem}
/>
}
/>
);
};

View File

@ -0,0 +1,37 @@
import { useFormContext } from 'react-hook-form';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
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';
export const useCurrencySettingsFormInitialValues = ({
fieldMetadataItem,
}: {
fieldMetadataItem?: Pick<FieldMetadataItem, 'defaultValue'>;
}) => {
const initialAmountMicrosValue =
(fieldMetadataItem?.defaultValue?.amountMicros as number | null) ?? null;
const initialCurrencyCode =
(fieldMetadataItem?.defaultValue?.currencyCode as CurrencyCode) ??
CurrencyCode.USD;
const initialCurrencyCodeValue =
applySimpleQuotesToString(initialCurrencyCode);
const initialDefaultValue = {
amountMicros: initialAmountMicrosValue,
currencyCode: initialCurrencyCodeValue,
};
const { resetField } =
useFormContext<SettingsDataModelFieldCurrencyFormValues>();
const resetDefaultValueField = () =>
resetField('defaultValue', { defaultValue: initialDefaultValue });
return {
initialAmountMicrosValue,
initialCurrencyCodeValue,
initialDefaultValue,
resetDefaultValueField,
};
};

View File

@ -1,38 +0,0 @@
import { useMemo } from 'react';
import { v4 } from 'uuid';
import {
FieldMetadataItem,
FieldMetadataItemOption,
} from '@/object-metadata/types/FieldMetadataItem';
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/utils/getOptionValueFromLabel';
const DEFAULT_OPTION: FieldMetadataItemOption = {
color: 'green',
id: v4(),
label: 'Option 1',
position: 0,
value: getOptionValueFromLabel('Option 1'),
};
export const useSelectSettingsFormInitialValues = ({
fieldMetadataItem,
}: {
fieldMetadataItem: Pick<FieldMetadataItem, 'defaultValue' | 'options'>;
}) => {
const initialDefaultValue = fieldMetadataItem.defaultValue ?? null;
const initialOptions = useMemo(
() =>
fieldMetadataItem.options?.length
? [...fieldMetadataItem.options].sort(
(optionA, optionB) => optionA.position - optionB.position,
)
: [DEFAULT_OPTION],
[fieldMetadataItem.options],
);
return {
initialDefaultValue,
initialOptions,
};
};

View File

@ -8,7 +8,7 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation'; import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation';
import { fieldMetadataItemSchema } from '@/object-metadata/validation-schemas/fieldMetadataItemSchema'; import { fieldMetadataItemSchema } from '@/object-metadata/validation-schemas/fieldMetadataItemSchema';
import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes'; import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes';
import { useRelationSettingsFormInitialValues } from '@/settings/data-model/fields/forms/hooks/useRelationSettingsFormInitialValues'; import { useRelationSettingsFormInitialValues } from '@/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues';
import { RelationType } from '@/settings/data-model/types/RelationType'; import { RelationType } from '@/settings/data-model/types/RelationType';
import { IconPicker } from '@/ui/input/components/IconPicker'; import { IconPicker } from '@/ui/input/components/IconPicker';
import { Select } from '@/ui/input/components/Select'; import { Select } from '@/ui/input/components/Select';
@ -32,7 +32,7 @@ export type SettingsDataModelFieldRelationFormValues = z.infer<
>; >;
type SettingsDataModelFieldRelationFormProps = { type SettingsDataModelFieldRelationFormProps = {
fieldMetadataItem?: Pick< fieldMetadataItem: Pick<
FieldMetadataItem, FieldMetadataItem,
'fromRelationMetadata' | 'toRelationMetadata' | 'type' 'fromRelationMetadata' | 'toRelationMetadata' | 'type'
>; >;

View File

@ -8,8 +8,8 @@ import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes';
import { import {
SettingsDataModelFieldRelationForm, SettingsDataModelFieldRelationForm,
SettingsDataModelFieldRelationFormValues, SettingsDataModelFieldRelationFormValues,
} from '@/settings/data-model/fields/forms/components/relation/SettingsDataModelFieldRelationForm'; } from '@/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm';
import { useRelationSettingsFormInitialValues } from '@/settings/data-model/fields/forms/hooks/useRelationSettingsFormInitialValues'; import { useRelationSettingsFormInitialValues } from '@/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues';
import { import {
SettingsDataModelFieldPreviewCard, SettingsDataModelFieldPreviewCard,
SettingsDataModelFieldPreviewCardProps, SettingsDataModelFieldPreviewCardProps,

View File

@ -1,4 +1,3 @@
import { useEffect } from 'react';
import { Controller, useFormContext } from 'react-hook-form'; import { Controller, useFormContext } from 'react-hook-form';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { DropResult } from '@hello-pangea/dnd'; import { DropResult } from '@hello-pangea/dnd';
@ -10,8 +9,8 @@ import {
FieldMetadataItemOption, FieldMetadataItemOption,
} from '@/object-metadata/types/FieldMetadataItem'; } from '@/object-metadata/types/FieldMetadataItem';
import { selectOptionsSchema } from '@/object-metadata/validation-schemas/selectOptionsSchema'; import { selectOptionsSchema } from '@/object-metadata/validation-schemas/selectOptionsSchema';
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/hooks/useSelectSettingsFormInitialValues'; import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues';
import { generateNewSelectOption } from '@/settings/data-model/fields/forms/utils/generateNewSelectOption'; import { generateNewSelectOption } from '@/settings/data-model/fields/forms/select/utils/generateNewSelectOption';
import { isSelectOptionDefaultValue } from '@/settings/data-model/utils/isSelectOptionDefaultValue'; import { isSelectOptionDefaultValue } from '@/settings/data-model/utils/isSelectOptionDefaultValue';
import { LightButton } from '@/ui/input/button/components/LightButton'; import { LightButton } from '@/ui/input/button/components/LightButton';
import { CardContent } from '@/ui/layout/card/components/CardContent'; import { CardContent } from '@/ui/layout/card/components/CardContent';
@ -86,7 +85,6 @@ export const SettingsDataModelFieldSelectForm = ({
setValue: setFormValue, setValue: setFormValue,
watch: watchFormValue, watch: watchFormValue,
getValues, getValues,
resetField,
} = useFormContext<SettingsDataModelFieldSelectFormValues>(); } = useFormContext<SettingsDataModelFieldSelectFormValues>();
const handleDragEnd = ( const handleDragEnd = (
@ -168,11 +166,6 @@ export const SettingsDataModelFieldSelectForm = ({
} }
}; };
// Reset defaultValue on mount or on field type change, so it doesn't conflict with other field types.
useEffect(() => {
resetField('defaultValue', { defaultValue: initialDefaultValue });
}, [initialDefaultValue, initialOptions, resetField, fieldMetadataItem.type]);
return ( return (
<> <>
<Controller <Controller

View File

@ -12,7 +12,7 @@ import {
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/utils/getOptionValueFromLabel'; import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { TextInput } from '@/ui/input/components/TextInput'; import { TextInput } from '@/ui/input/components/TextInput';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';

View File

@ -8,8 +8,8 @@ import {
settingsDataModelFieldMultiSelectFormSchema, settingsDataModelFieldMultiSelectFormSchema,
SettingsDataModelFieldSelectForm, SettingsDataModelFieldSelectForm,
settingsDataModelFieldSelectFormSchema, settingsDataModelFieldSelectFormSchema,
} from '@/settings/data-model/fields/forms/components/select/SettingsDataModelFieldSelectForm'; } from '@/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm';
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/hooks/useSelectSettingsFormInitialValues'; import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues';
import { import {
SettingsDataModelFieldPreviewCard, SettingsDataModelFieldPreviewCard,
SettingsDataModelFieldPreviewCardProps, SettingsDataModelFieldPreviewCardProps,
@ -20,7 +20,7 @@ const selectOrMultiSelectFormSchema = z.union([
settingsDataModelFieldMultiSelectFormSchema, settingsDataModelFieldMultiSelectFormSchema,
]); ]);
type SettingsDataModelFieldSettingsFormValues = z.infer< type SettingsDataModelFieldSelectOrMultiSelectFormValues = z.infer<
typeof selectOrMultiSelectFormSchema typeof selectOrMultiSelectFormSchema
>; >;
@ -46,7 +46,7 @@ export const SettingsDataModelFieldSelectSettingsFormCard = ({
}); });
const { watch: watchFormValue } = const { watch: watchFormValue } =
useFormContext<SettingsDataModelFieldSettingsFormValues>(); useFormContext<SettingsDataModelFieldSelectOrMultiSelectFormValues>();
return ( return (
<SettingsDataModelPreviewFormCard <SettingsDataModelPreviewFormCard

View File

@ -0,0 +1,49 @@
import { useMemo } from 'react';
import { useFormContext } from 'react-hook-form';
import { v4 } from 'uuid';
import {
FieldMetadataItem,
FieldMetadataItemOption,
} from '@/object-metadata/types/FieldMetadataItem';
import { SettingsDataModelFieldSelectFormValues } from '@/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm';
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
const DEFAULT_OPTION: FieldMetadataItemOption = {
color: 'green',
id: v4(),
label: 'Option 1',
position: 0,
value: getOptionValueFromLabel('Option 1'),
};
export const useSelectSettingsFormInitialValues = ({
fieldMetadataItem,
}: {
fieldMetadataItem?: Pick<FieldMetadataItem, 'defaultValue' | 'options'>;
}) => {
const initialDefaultValue =
(fieldMetadataItem?.defaultValue as SettingsDataModelFieldSelectFormValues['defaultValue']) ??
null;
const initialOptions = useMemo(
() =>
fieldMetadataItem?.options?.length
? [...fieldMetadataItem.options].sort(
(optionA, optionB) => optionA.position - optionB.position,
)
: [DEFAULT_OPTION],
[fieldMetadataItem?.options],
);
const { resetField } =
useFormContext<SettingsDataModelFieldSelectFormValues>();
const resetDefaultValueField = () =>
resetField('defaultValue', { defaultValue: initialDefaultValue });
return {
initialDefaultValue,
initialOptions,
resetDefaultValueField,
};
};

View File

@ -1,4 +1,4 @@
import { generateNewSelectOptionLabel } from '@/settings/data-model/fields/forms/utils/generateNewSelectOptionLabel'; import { generateNewSelectOptionLabel } from '../generateNewSelectOptionLabel';
describe('generateNewSelectOptionLabel', () => { describe('generateNewSelectOptionLabel', () => {
it('generates a new select option label', () => { it('generates a new select option label', () => {

View File

@ -1,4 +1,4 @@
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/utils/getOptionValueFromLabel'; import { getOptionValueFromLabel } from '../getOptionValueFromLabel';
describe('getOptionValueFromLabel', () => { describe('getOptionValueFromLabel', () => {
it('should return the option value from the label', () => { it('should return the option value from the label', () => {

View File

@ -2,8 +2,8 @@ import { getNextThemeColor } from 'twenty-ui';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
import { generateNewSelectOptionLabel } from '@/settings/data-model/fields/forms/utils/generateNewSelectOptionLabel'; import { generateNewSelectOptionLabel } from '@/settings/data-model/fields/forms/select/utils/generateNewSelectOptionLabel';
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/utils/getOptionValueFromLabel'; import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
export const generateNewSelectOption = ( export const generateNewSelectOption = (
options: FieldMetadataItemOption[], options: FieldMetadataItemOption[],

View File

@ -215,16 +215,6 @@ export const SettingsObjectNewFieldStep2 = () => {
} else { } else {
const createdMetadataField = await createMetadataField({ const createdMetadataField = await createMetadataField({
...formValues, ...formValues,
defaultValue:
formValues.type === FieldMetadataType.Currency &&
'defaultValue' in formValues
? {
...formValues.defaultValue,
amountMicros: null,
}
: 'defaultValue' in formValues
? formValues.defaultValue
: undefined,
objectMetadataId: activeObjectMetadataItem.id, objectMetadataId: activeObjectMetadataItem.id,
}); });