Morph many to one picker (#14155)
This PR follows the multiSelect PR merged previously. It will enable morph relation Many to One to be handled from the table, using a singleSelect picker Main point : I decided to change the singleSelect API to take an array of **objectMetadataName** instead of only one to deal with both our usecases. --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
+81
@@ -0,0 +1,81 @@
|
||||
import { FieldMetadataType, RelationType } from 'twenty-shared/types';
|
||||
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
|
||||
|
||||
describe('getMorphNameFromMorphFieldMetadataName', () => {
|
||||
const createMorphRelationFlatFieldMetadataMock = (
|
||||
name: string,
|
||||
relationType: RelationType,
|
||||
) =>
|
||||
({
|
||||
name,
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
label: name,
|
||||
settings: { relationType },
|
||||
}) as unknown as FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
|
||||
|
||||
it('should extract base morph field name for MANY_TO_ONE (removes singular suffix)', () => {
|
||||
const morphRelationFlatFieldMetadata =
|
||||
createMorphRelationFlatFieldMetadataMock(
|
||||
'contactDeal',
|
||||
RelationType.MANY_TO_ONE,
|
||||
);
|
||||
|
||||
const result = getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata,
|
||||
nameSingular: 'Deal',
|
||||
namePlural: 'Deals',
|
||||
});
|
||||
|
||||
expect(result).toBe('contact');
|
||||
});
|
||||
|
||||
it('should also work extract base morph field name for MANY_TO_ONE if casing is not correct', () => {
|
||||
const morphRelationFlatFieldMetadata =
|
||||
createMorphRelationFlatFieldMetadataMock(
|
||||
'contactDeal',
|
||||
RelationType.MANY_TO_ONE,
|
||||
);
|
||||
|
||||
const result = getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata,
|
||||
nameSingular: 'deal',
|
||||
namePlural: 'deals',
|
||||
});
|
||||
|
||||
expect(result).toBe('contact');
|
||||
});
|
||||
|
||||
it('should extract base morph field name for ONE_TO_MANY (removes plural suffix)', () => {
|
||||
const morphRelationFlatFieldMetadata =
|
||||
createMorphRelationFlatFieldMetadataMock(
|
||||
'contactDeals',
|
||||
RelationType.ONE_TO_MANY,
|
||||
);
|
||||
|
||||
const result = getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata,
|
||||
nameSingular: 'Deal',
|
||||
namePlural: 'Deals',
|
||||
});
|
||||
|
||||
expect(result).toBe('contact');
|
||||
});
|
||||
|
||||
it('should return the original name when suffix does not match', () => {
|
||||
const morphRelationFlatFieldMetadata =
|
||||
createMorphRelationFlatFieldMetadataMock(
|
||||
'randomName',
|
||||
RelationType.MANY_TO_ONE,
|
||||
);
|
||||
|
||||
const result = getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata,
|
||||
nameSingular: 'account',
|
||||
namePlural: 'accounts',
|
||||
});
|
||||
|
||||
expect(result).toBe('randomName');
|
||||
});
|
||||
});
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import { type FieldMetadataType, RelationType } from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { searchAndReplaceLast } from 'src/engine/metadata-modules/flat-object-metadata/utils/search-and-replace-last.util';
|
||||
|
||||
export const getMorphNameFromMorphFieldMetadataName = ({
|
||||
morphRelationFlatFieldMetadata,
|
||||
nameSingular,
|
||||
namePlural,
|
||||
}: {
|
||||
morphRelationFlatFieldMetadata: Pick<
|
||||
FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>,
|
||||
'name' | 'settings'
|
||||
>;
|
||||
nameSingular: string;
|
||||
namePlural: string;
|
||||
}): string => {
|
||||
const isManyToOneRelationType =
|
||||
morphRelationFlatFieldMetadata.settings.relationType ===
|
||||
RelationType.MANY_TO_ONE;
|
||||
|
||||
return searchAndReplaceLast({
|
||||
source: morphRelationFlatFieldMetadata.name,
|
||||
replace: '',
|
||||
search: isManyToOneRelationType
|
||||
? capitalize(nameSingular)
|
||||
: capitalize(namePlural),
|
||||
});
|
||||
};
|
||||
+11
-29
@@ -3,34 +3,15 @@ import {
|
||||
type FieldMetadataType,
|
||||
type FromTo,
|
||||
} from 'twenty-shared/types';
|
||||
import { computeMorphRelationFieldName } from 'twenty-shared/utils';
|
||||
|
||||
import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { computeMorphRelationFieldName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-relation-field-name.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { findObjectFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-object-fields-in-flat-field-metadata-maps-or-throw.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { getFlatObjectMetadataTargetMorphRelationFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-flat-object-metadata-many-to-one-target-morph-relation-flat-field-metadatas-or-throw.util';
|
||||
|
||||
const searchAndReplaceLast = ({
|
||||
replace,
|
||||
search,
|
||||
source,
|
||||
}: {
|
||||
source: string;
|
||||
search: string;
|
||||
replace: string;
|
||||
}) => {
|
||||
const lastIndex = source.lastIndexOf(search);
|
||||
|
||||
if (lastIndex === -1) return source;
|
||||
|
||||
return (
|
||||
source.slice(0, lastIndex) +
|
||||
replace +
|
||||
source.slice(lastIndex + search.length)
|
||||
);
|
||||
};
|
||||
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
|
||||
|
||||
type RenameRelatedMorphFieldOnObjectNamesUpdateArgs = FromTo<
|
||||
FlatObjectMetadata,
|
||||
@@ -59,17 +40,18 @@ export const renameRelatedMorphFieldOnObjectNamesUpdate = ({
|
||||
const isManyToOneRelationType =
|
||||
morphRelationFlatFieldMetadata.settings.relationType ===
|
||||
RelationType.MANY_TO_ONE;
|
||||
const initialMorphRelationFieldName = searchAndReplaceLast({
|
||||
source: morphRelationFlatFieldMetadata.name,
|
||||
replace: '',
|
||||
search: isManyToOneRelationType
|
||||
? fromFlatObjectMetadata.nameSingular
|
||||
: fromFlatObjectMetadata.namePlural,
|
||||
});
|
||||
const initialMorphRelationFieldName =
|
||||
getMorphNameFromMorphFieldMetadataName({
|
||||
morphRelationFlatFieldMetadata,
|
||||
nameSingular: fromFlatObjectMetadata.nameSingular,
|
||||
namePlural: fromFlatObjectMetadata.namePlural,
|
||||
});
|
||||
|
||||
const newMorphFieldName = computeMorphRelationFieldName({
|
||||
fieldName: initialMorphRelationFieldName,
|
||||
relationType: morphRelationFlatFieldMetadata.settings.relationType,
|
||||
targetObjectMetadata: toFlatObjectMetadata,
|
||||
targetObjectMetadataNameSingular: toFlatObjectMetadata.nameSingular,
|
||||
targetObjectMetadataNamePlural: toFlatObjectMetadata.namePlural,
|
||||
});
|
||||
const newJoinColumnName = isManyToOneRelationType
|
||||
? computeMorphOrRelationFieldJoinColumnName({
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
export const searchAndReplaceLast = ({
|
||||
replace,
|
||||
search,
|
||||
source,
|
||||
}: {
|
||||
source: string;
|
||||
search: string;
|
||||
replace: string;
|
||||
}) => {
|
||||
const lastIndex = source.lastIndexOf(search);
|
||||
|
||||
if (lastIndex === -1) return source;
|
||||
|
||||
return (
|
||||
source.slice(0, lastIndex) +
|
||||
replace +
|
||||
source.slice(lastIndex + search.length)
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user