Add field isLabelSyncedWithName (#8829)
## Context
The recent addition of object renaming introduced issues with enum
names. Enum names should follow the pattern
`${schemaName}.${tableName}_${columnName}_enum`. To address this, and to
allow users to customize the API name (which is included in the enum
name, columnName), this PR implements behavior similar to object
renaming by introducing a `isLabelSyncedWithName` boolean.
<img width="624" alt="Screenshot 2024-12-02 at 11 58 49"
src="https://github.com/user-attachments/assets/690fb71c-83f0-4922-80c0-946c92dacc30">
<img width="596" alt="Screenshot 2024-12-02 at 11 58 39"
src="https://github.com/user-attachments/assets/af9a0037-7cf5-40c3-9ed5-d51b340c8087">
This commit is contained in:
@ -2,7 +2,7 @@ import { useApolloClient } from '@apollo/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import omit from 'lodash.omit';
|
||||
import pick from 'lodash.pick';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import {
|
||||
@ -49,6 +49,7 @@ type SettingsDataModelFieldEditFormValues = z.infer<
|
||||
export const SettingsObjectFieldEdit = () => {
|
||||
const navigate = useNavigate();
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
const [isPersisting, setIsPersisting] = useState(false);
|
||||
|
||||
const { objectSlug = '', fieldSlug = '' } = useParams();
|
||||
const { findObjectMetadataItemBySlug } = useFilteredObjectMetadataItems();
|
||||
@ -87,14 +88,16 @@ export const SettingsObjectFieldEdit = () => {
|
||||
type: fieldMetadataItem?.type as SettingsFieldType,
|
||||
label: fieldMetadataItem?.label ?? '',
|
||||
description: fieldMetadataItem?.description,
|
||||
isLabelSyncedWithName: fieldMetadataItem?.isLabelSyncedWithName ?? true,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isPersisting) return;
|
||||
if (!objectMetadataItem || !fieldMetadataItem) {
|
||||
navigate(AppPath.NotFound);
|
||||
}
|
||||
}, [fieldMetadataItem, objectMetadataItem, navigate]);
|
||||
}, [navigate, objectMetadataItem, fieldMetadataItem, isPersisting]);
|
||||
|
||||
const { isDirty, isValid, isSubmitting } = formConfig.formState;
|
||||
const canSave = isDirty && isValid && !isSubmitting;
|
||||
@ -125,6 +128,8 @@ export const SettingsObjectFieldEdit = () => {
|
||||
}) ?? {};
|
||||
|
||||
if (isDefined(relationFieldMetadataItem)) {
|
||||
setIsPersisting(true);
|
||||
|
||||
await updateOneFieldMetadataItem({
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
fieldMetadataIdToUpdate: relationFieldMetadataItem.id,
|
||||
@ -141,6 +146,8 @@ export const SettingsObjectFieldEdit = () => {
|
||||
Object.keys(otherDirtyFields),
|
||||
);
|
||||
|
||||
setIsPersisting(true);
|
||||
|
||||
await updateOneFieldMetadataItem({
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
fieldMetadataIdToUpdate: fieldMetadataItem.id,
|
||||
@ -155,6 +162,8 @@ export const SettingsObjectFieldEdit = () => {
|
||||
enqueueSnackBar((error as Error).message, {
|
||||
variant: SnackBarVariant.Error,
|
||||
});
|
||||
} finally {
|
||||
setIsPersisting(false);
|
||||
}
|
||||
};
|
||||
|
||||
@ -210,6 +219,9 @@ export const SettingsObjectFieldEdit = () => {
|
||||
disabled={!fieldMetadataItem.isCustom}
|
||||
fieldMetadataItem={fieldMetadataItem}
|
||||
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
|
||||
canToggleSyncLabelWithName={
|
||||
fieldMetadataItem.type !== FieldMetadataType.Relation
|
||||
}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
|
||||
@ -29,6 +29,7 @@ import { H2Title, Section } from 'twenty-ui';
|
||||
import { z } from 'zod';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { DEFAULT_ICONS_BY_FIELD_TYPE } from '~/pages/settings/data-model/constants/DefaultIconsByFieldType';
|
||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
type SettingsDataModelNewFieldFormValues = z.infer<
|
||||
@ -67,6 +68,7 @@ export const SettingsObjectNewFieldConfigure = () => {
|
||||
DEFAULT_ICONS_BY_FIELD_TYPE[fieldType] ?? DEFAULT_ICON_FOR_NEW_FIELD,
|
||||
label: '',
|
||||
description: '',
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
|
||||
@ -134,12 +136,22 @@ export const SettingsObjectNewFieldConfigure = () => {
|
||||
|
||||
await createOneRelationMetadata({
|
||||
relationType: relationFormValues.type,
|
||||
field: pick(fieldFormValues, ['icon', 'label', 'description']),
|
||||
field: pick(fieldFormValues, [
|
||||
'icon',
|
||||
'label',
|
||||
'description',
|
||||
'name',
|
||||
'isLabelSyncedWithName',
|
||||
]),
|
||||
objectMetadataId: activeObjectMetadataItem.id,
|
||||
connect: {
|
||||
field: {
|
||||
icon: relationFormValues.field.icon,
|
||||
label: relationFormValues.field.label,
|
||||
name:
|
||||
(relationFormValues.field.isLabelSyncedWithName ?? true)
|
||||
? computeMetadataNameFromLabel(relationFormValues.field.label)
|
||||
: relationFormValues.field.name,
|
||||
},
|
||||
objectMetadataId: relationFormValues.objectMetadataId,
|
||||
},
|
||||
@ -204,6 +216,9 @@ export const SettingsObjectNewFieldConfigure = () => {
|
||||
/>
|
||||
<SettingsDataModelFieldIconLabelForm
|
||||
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
|
||||
canToggleSyncLabelWithName={
|
||||
fieldType !== FieldMetadataType.Relation
|
||||
}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
|
||||
Reference in New Issue
Block a user