Support Full Name as Record Text Identifier (#11610)

closes #11296 


[recording.webm](https://github.com/user-attachments/assets/da0f2587-a435-4bee-a802-81eb9ca92733)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Gaurav
2025-05-20 03:33:30 +05:30
committed by GitHub
parent 477a10ba4a
commit 98e199c01d
6 changed files with 31 additions and 20 deletions

View File

@ -3,4 +3,5 @@ import { FieldMetadataType } from '~/generated-metadata/graphql';
export const LABEL_IDENTIFIER_FIELD_METADATA_TYPES = [
FieldMetadataType.NUMBER,
FieldMetadataType.TEXT,
FieldMetadataType.FULL_NAME,
];

View File

@ -9,16 +9,16 @@ export const getLabelIdentifierFieldValue = (
labelIdentifierFieldMetadataItem: FieldMetadataItem | undefined,
objectNameSingular: string,
): string => {
if (!isDefined(labelIdentifierFieldMetadataItem)) {
return record.id;
}
if (
objectNameSingular === CoreObjectNameSingular.WorkspaceMember ||
labelIdentifierFieldMetadataItem?.type === FieldMetadataType.FULL_NAME
labelIdentifierFieldMetadataItem.type === FieldMetadataType.FULL_NAME
) {
return `${record.name?.firstName ?? ''} ${record.name?.lastName ?? ''}`;
return `${record[labelIdentifierFieldMetadataItem.name]?.firstName ?? ''} ${record[labelIdentifierFieldMetadataItem.name]?.lastName ?? ''}`;
}
if (isDefined(labelIdentifierFieldMetadataItem?.name)) {
return record[labelIdentifierFieldMetadataItem.name] ?? '';
}
return '';
return record[labelIdentifierFieldMetadataItem.name] ?? '';
};

View File

@ -1,5 +1,4 @@
import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext';
import { generateDefaultRecordChipData } from '@/object-metadata/utils/generateDefaultRecordChipData';
import { RecordChipData } from '@/object-record/record-field/types/RecordChipData';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { useContext } from 'react';
@ -23,16 +22,13 @@ export const useRecordChipData = ({
const identifierChipGenerator =
identifierChipGeneratorPerObject[objectNameSingular];
if (isDefined(identifierChipGenerator)) {
return {
recordChipData: identifierChipGenerator(record),
};
if (!isDefined(identifierChipGenerator)) {
throw new Error(
`No identifier chip generator found for object name singular: ${objectNameSingular}`,
);
}
return {
recordChipData: generateDefaultRecordChipData({
objectNameSingular,
record,
}),
recordChipData: identifierChipGenerator(record),
};
};

View File

@ -11,8 +11,8 @@ import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifie
import { isFieldIdentifierDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldIdentifierDisplay';
import { RecordChipData } from '@/object-record/record-field/types/RecordChipData';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataType } from '~/generated-metadata/graphql';
export const getRecordChipGenerators = (
objectMetadataItems: ObjectMetadataItem[],

View File

@ -13,7 +13,8 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Select } from '@/ui/input/components/Select';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from '@lingui/core/macro';
import { IconCircleOff, useIcons } from 'twenty-ui/display';
import { useNavigate } from 'react-router-dom';
import { IconCircleOff, IconPlus, useIcons } from 'twenty-ui/display';
import { SelectOption } from 'twenty-ui/input';
export const settingsDataModelObjectIdentifiersFormSchema =
@ -100,6 +101,9 @@ export const SettingsDataModelObjectIdentifiersForm = ({
label: 'None',
value: null,
};
const navigate = useNavigate();
return (
<StyledContainer>
{[
@ -124,12 +128,23 @@ export const SettingsDataModelObjectIdentifiersForm = ({
render={({ field: { onChange, value } }) => (
<Select
label={label}
disabled={!objectMetadataItem.isCustom || !options.length}
fullWidth
dropdownId={`${fieldName}-select`}
emptyOption={emptyOption}
options={options}
value={value}
withSearchInput={label === t`Record label`}
callToActionButton={
label === t`Record label`
? {
text: 'Create Text Field',
Icon: IconPlus,
onClick: () => {
navigate('./new-field/select');
},
}
: undefined
}
onChange={(value) => {
onChange(value);
formConfig.handleSubmit(handleSave)();

View File

@ -50,7 +50,6 @@ const reservedKeywords = [
'links',
'currency',
'currencies',
'fullName',
'fullNames',
'address',
'addresses',