diff --git a/packages/twenty-front/src/modules/object-metadata/constants/LabelIdentifierFieldMetadataTypes.ts b/packages/twenty-front/src/modules/object-metadata/constants/LabelIdentifierFieldMetadataTypes.ts new file mode 100644 index 000000000..fe2531919 --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/constants/LabelIdentifierFieldMetadataTypes.ts @@ -0,0 +1,6 @@ +import { FieldMetadataType } from '~/generated-metadata/graphql'; + +export const LABEL_IDENTIFIER_FIELD_METADATA_TYPES = [ + FieldMetadataType.Number, + FieldMetadataType.Text, +]; diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getActiveFieldMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/utils/getActiveFieldMetadataItems.ts new file mode 100644 index 000000000..e174c2b00 --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/utils/getActiveFieldMetadataItems.ts @@ -0,0 +1,9 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +export const getActiveFieldMetadataItems = ( + objectMetadataItem: Pick, +) => + objectMetadataItem.fields.filter( + (fieldMetadataItem) => + fieldMetadataItem.isActive && !fieldMetadataItem.isSystem, + ); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getDisabledFieldMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/utils/getDisabledFieldMetadataItems.ts new file mode 100644 index 000000000..52f781ccc --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/utils/getDisabledFieldMetadataItems.ts @@ -0,0 +1,9 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +export const getDisabledFieldMetadataItems = ( + objectMetadataItem: Pick, +) => + objectMetadataItem.fields.filter( + (fieldMetadataItem) => + !fieldMetadataItem.isActive && !fieldMetadataItem.isSystem, + ); diff --git a/packages/twenty-front/src/modules/settings/data-model/components/SettingsDataModelCardTitle.tsx b/packages/twenty-front/src/modules/settings/data-model/components/SettingsDataModelCardTitle.tsx new file mode 100644 index 000000000..9fbc11715 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/components/SettingsDataModelCardTitle.tsx @@ -0,0 +1,11 @@ +import styled from '@emotion/styled'; + +const StyledTitle = styled.h3` + color: ${({ theme }) => theme.font.color.extraLight}; + font-size: ${({ theme }) => theme.font.size.sm}; + font-weight: ${({ theme }) => theme.font.weight.medium}; + margin: 0; + margin-bottom: ${({ theme }) => theme.spacing(4)}; +`; + +export { StyledTitle as SettingsDataModelCardTitle }; diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectIdentifiersForm.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectIdentifiersForm.tsx new file mode 100644 index 000000000..6762b5269 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectIdentifiersForm.tsx @@ -0,0 +1,101 @@ +import { useMemo } from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; +import styled from '@emotion/styled'; +import { z } from 'zod'; + +import { LABEL_IDENTIFIER_FIELD_METADATA_TYPES } from '@/object-metadata/constants/LabelIdentifierFieldMetadataTypes'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { getActiveFieldMetadataItems } from '@/object-metadata/utils/getActiveFieldMetadataItems'; +import { objectMetadataItemSchema } from '@/object-metadata/validation-schemas/objectMetadataItemSchema'; +import { IconCircleOff } from '@/ui/display/icon'; +import { useIcons } from '@/ui/display/icon/hooks/useIcons'; +import { Select, SelectOption } from '@/ui/input/components/Select'; + +export const settingsDataModelObjectIdentifiersFormSchema = + objectMetadataItemSchema.pick({ + labelIdentifierFieldMetadataId: true, + imageIdentifierFieldMetadataId: true, + }); + +export type SettingsDataModelObjectIdentifiersFormValues = z.infer< + typeof settingsDataModelObjectIdentifiersFormSchema +>; + +type SettingsDataModelObjectIdentifiersFormProps = { + objectMetadataItem: ObjectMetadataItem; +}; + +const StyledContainer = styled.div` + display: flex; + gap: ${({ theme }) => theme.spacing(4)}; +`; + +export const SettingsDataModelObjectIdentifiersForm = ({ + objectMetadataItem, +}: SettingsDataModelObjectIdentifiersFormProps) => { + const { control } = + useFormContext(); + const { getIcon } = useIcons(); + + const labelIdentifierFieldOptions = useMemo( + () => + getActiveFieldMetadataItems(objectMetadataItem) + .filter( + ({ id, type }) => + LABEL_IDENTIFIER_FIELD_METADATA_TYPES.includes(type) || + objectMetadataItem.labelIdentifierFieldMetadataId === id, + ) + .map>((fieldMetadataItem) => ({ + Icon: getIcon(fieldMetadataItem.icon), + label: fieldMetadataItem.label, + value: fieldMetadataItem.id, + })), + [getIcon, objectMetadataItem], + ); + const imageIdentifierFieldOptions: SelectOption[] = []; + + const emptyOption: SelectOption = { + Icon: IconCircleOff, + label: 'None', + value: null, + }; + + return ( + + {[ + { + label: 'Record label', + fieldName: 'labelIdentifierFieldMetadataId' as const, + options: labelIdentifierFieldOptions, + }, + { + label: 'Record image', + fieldName: 'imageIdentifierFieldMetadataId' as const, + options: imageIdentifierFieldOptions, + }, + ].map(({ fieldName, label, options }) => ( + { + return ( +