Metadata api create entity in workspace custom app (#15911)
# Introduction Cleaner and fewer scope version of https://github.com/twentyhq/twenty/pull/15745 ( removed sync-metadata hack through, too ambitious migration and upgrade ) Please note that this PR won't have any interaction with the existing sync-metadata Which mean that the sync metadata does not update the standard entities applicationId and universalIdentifier, and it won't we will deprecate it on favor of a workspace migration aka twenty-standard app installation ## API Metadata Any operation going through the api metadata nows automatically scope the related entity to the workspace custom application instance. ( optionally passing an applicationId to allow current hacky implem of app sync service ) We need to either ignore the tests or remove the cli status check from the blocking status badges for a PR to be merged ## New workspace Already handled in previous https://github.com/twentyhq/twenty/pull/15625, when a workspace is created it gets created a twenty standard and custom workspace instance All his views and permissions will be prefilled to the its twenty standard app instance with a specific universalIdentifier ## New universalIdentifier At the contrary as before with standardIds, universalIdentifier are unique for a given workspace This means that createdAt field of both object company and opportunity will have a unique universalIdentifier whereas they share the same standardId ## FlatApplication Introduced the flatApplication and cache. Will migrate existing `MetadataName` to be `SyncableMetadataName` in a following PR ## What's next Next we will describe a twenty standard app configuration as json that will be used to generate a workspace migration that will be run instead of the sync metadata, in a nutshell we aim to deprecated the sync metadata So we can standardize any entity to have a non nullable applicationId and universalIdentifier ## Upgrade command Introduced an upgrade command that will create a custom workspace instance for any workspace that do not have one in order to align with the new behavior when creating a new workspace
This commit is contained in:
+6
-6
@@ -104,7 +104,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"result": {
|
||||
"flatFieldMetadatas": [
|
||||
{
|
||||
"applicationId": null,
|
||||
"applicationId": Any<String>,
|
||||
"calendarViewIds": [],
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
@@ -140,7 +140,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"applicationId": Any<String>,
|
||||
"calendarViewIds": [],
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
@@ -178,7 +178,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"applicationId": Any<String>,
|
||||
"calendarViewIds": [],
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
@@ -214,7 +214,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"applicationId": Any<String>,
|
||||
"calendarViewIds": [],
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
@@ -254,7 +254,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
],
|
||||
"indexMetadatas": [
|
||||
{
|
||||
"applicationId": null,
|
||||
"applicationId": Any<String>,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"flatIndexFieldMetadatas": [
|
||||
{
|
||||
@@ -278,7 +278,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"applicationId": Any<String>,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"flatIndexFieldMetadatas": [
|
||||
{
|
||||
|
||||
+14
@@ -42,6 +42,8 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should create morph relation field metadata with valid input on rocket object to pet object',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -100,6 +102,8 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
title: 'should fail when morphRelationsCreationPayload is missing',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -118,6 +122,8 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
title: 'should fail when morphRelationsCreationPayload is empty array',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -137,6 +143,8 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should fail when morphRelationsCreationPayload has different relation types',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -169,6 +177,8 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should fail when morphRelationsCreationPayload has several references to same object metadata',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -201,6 +211,8 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should fail when morphRelationsCreationPayload has invalid relation payload',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -225,6 +237,8 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
title: 'should fail when target object metadata is not found',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
|
||||
+5
@@ -25,12 +25,14 @@ import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-m
|
||||
export type FromCreateFieldInputToFlatObjectMetadataArgs = {
|
||||
createFieldInput: Omit<CreateFieldInput, 'workspaceId'>;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps'>;
|
||||
|
||||
export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
createFieldInput: rawCreateFieldInput,
|
||||
workspaceId,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
}: FromCreateFieldInputToFlatObjectMetadataArgs): Promise<
|
||||
FieldInputTranspilationResult<{
|
||||
flatFieldMetadatas: FlatFieldMetadata[];
|
||||
@@ -71,6 +73,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
createFieldInput,
|
||||
workspaceId,
|
||||
fieldMetadataId,
|
||||
workspaceCustomApplicationId,
|
||||
});
|
||||
|
||||
switch (createFieldInput.type) {
|
||||
@@ -83,6 +86,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceFlatObjectMetadata: parentFlatObjectMetadata,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
});
|
||||
}
|
||||
case FieldMetadataType.RELATION: {
|
||||
@@ -94,6 +98,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
type: createFieldInput.type,
|
||||
},
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
});
|
||||
}
|
||||
case FieldMetadataType.RATING: {
|
||||
|
||||
+3
@@ -21,12 +21,14 @@ type FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs = {
|
||||
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
sourceFlatObjectMetadata: FlatObjectMetadata;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
};
|
||||
export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
createFieldInput,
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceFlatObjectMetadata,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
}: FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs): Promise<
|
||||
FieldInputTranspilationResult<{
|
||||
flatFieldMetadatas: FlatFieldMetadata[];
|
||||
@@ -90,6 +92,7 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
targetFlatObjectMetadata,
|
||||
workspaceId,
|
||||
morphId,
|
||||
workspaceCustomApplicationId,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
+3
@@ -21,12 +21,14 @@ type FromRelationCreateFieldInputToFlatFieldMetadataArgs = {
|
||||
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
sourceFlatObjectMetadata: FlatObjectMetadata;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
};
|
||||
export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceFlatObjectMetadata,
|
||||
createFieldInput,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
}: FromRelationCreateFieldInputToFlatFieldMetadataArgs): Promise<
|
||||
FieldInputTranspilationResult<SourceTargetMorphOrRelationFlatFieldAndFlatIndex>
|
||||
> => {
|
||||
@@ -67,6 +69,7 @@ export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ export const generateIndexForFlatFieldMetadata = ({
|
||||
universalIdentifier: indexId,
|
||||
updatedAt: createdAt,
|
||||
workspaceId,
|
||||
applicationId: null,
|
||||
applicationId: flatFieldMetadata.applicationId,
|
||||
},
|
||||
flatObjectMetadata,
|
||||
},
|
||||
|
||||
+5
-1
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
FieldMetadataType,
|
||||
RelationType,
|
||||
RelationOnDeleteAction,
|
||||
RelationType,
|
||||
} from 'twenty-shared/types';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
@@ -46,6 +46,7 @@ type GenerateMorphOrRelationFlatFieldMetadataPairArgs = {
|
||||
> & { type: MorphOrRelationFieldMetadataType };
|
||||
workspaceId: string;
|
||||
morphId?: string | null;
|
||||
workspaceCustomApplicationId: string;
|
||||
};
|
||||
|
||||
export type SourceTargetMorphOrRelationFlatFieldAndFlatIndex = {
|
||||
@@ -58,6 +59,7 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
sourceFlatObjectMetadata,
|
||||
targetFlatObjectMetadata,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
sourceFlatObjectMetadataJoinColumnName,
|
||||
morphId = null,
|
||||
}: GenerateMorphOrRelationFlatFieldMetadataPairArgs): SourceTargetMorphOrRelationFlatFieldAndFlatIndex => {
|
||||
@@ -78,6 +80,7 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
createFieldInput,
|
||||
workspaceId,
|
||||
fieldMetadataId: sourceRelationTargetFieldMetadataId,
|
||||
workspaceCustomApplicationId,
|
||||
}),
|
||||
morphId,
|
||||
objectMetadataId: sourceFlatObjectMetadata.id,
|
||||
@@ -116,6 +119,7 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
createFieldInput: targetCreateFieldInput,
|
||||
workspaceId,
|
||||
fieldMetadataId: targetRelationTargetFieldMetadataId,
|
||||
workspaceCustomApplicationId,
|
||||
}),
|
||||
type: FieldMetadataType.RELATION,
|
||||
defaultValue: null,
|
||||
|
||||
+3
-1
@@ -9,11 +9,13 @@ type GetDefaultFlatFieldMetadataArgs = {
|
||||
fieldMetadataId: string;
|
||||
createFieldInput: Omit<CreateFieldInput, 'workspaceId'>;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
};
|
||||
export const getDefaultFlatFieldMetadata = ({
|
||||
createFieldInput,
|
||||
fieldMetadataId,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
}: GetDefaultFlatFieldMetadataArgs) => {
|
||||
const { defaultValue, settings } = extractAndSanitizeObjectStringFields(
|
||||
createFieldInput,
|
||||
@@ -56,7 +58,7 @@ export const getDefaultFlatFieldMetadata = ({
|
||||
updatedAt: createdAt,
|
||||
isUIReadOnly: createFieldInput.isUIReadOnly ?? false,
|
||||
morphId: null,
|
||||
applicationId: createFieldInput.applicationId ?? null,
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
viewFilterIds: [],
|
||||
viewGroupIds: [],
|
||||
kanbanAggregateOperationViewIds: [],
|
||||
|
||||
Reference in New Issue
Block a user