Fix cross app installation (#18151)

# Introduction
- Fixing app dependencyFlatEntityMaps load ( to load current app +
dependent app )
- Fix empty flat entity maps and undefined optimistic override
- Refactor the optimistic rendering to be mutation oriented at
orchestrator level
This commit is contained in:
Paul Rastoin
2026-02-23 19:58:06 +01:00
committed by GitHub
parent 0d4fe4575b
commit af0af0a237
24 changed files with 481 additions and 571 deletions
@@ -1,10 +1,8 @@
import { Injectable } from '@nestjs/common';
import { type AllMetadataName } from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant';
import { type MetadataUniversalFlatEntityAndRelatedUniversalFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-types.type';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-actions-report.constant';
import { EMPTY_ORCHESTRATOR_FAILURE_REPORT } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-failure-report.constant';
import {
@@ -74,6 +72,12 @@ export class WorkspaceMigrationBuildOrchestratorService {
WorkspaceMigrationOrchestratorBuildArgs,
'fromToAllFlatEntityMaps' | 'dependencyAllFlatEntityMaps'
>): AllUniversalFlatEntityMaps {
if (isDefined(dependencyAllFlatEntityMaps)) {
return {
...createEmptyAllFlatEntityMaps(),
...dependencyAllFlatEntityMaps,
};
}
const allFromToFlatEntityMapsKeys = Object.keys(
fromToAllFlatEntityMaps,
) as (keyof AllUniversalFlatEntityMaps)[];
@@ -82,10 +86,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
(allFlatEntityMaps, currFlatMaps) => {
const fromToOccurence = fromToAllFlatEntityMaps[currFlatMaps];
if (
!isDefined(fromToOccurence) ||
isDefined(allFlatEntityMaps[currFlatMaps])
) {
if (!isDefined(fromToOccurence)) {
return allFlatEntityMaps;
}
@@ -96,31 +97,10 @@ export class WorkspaceMigrationBuildOrchestratorService {
},
{
...createEmptyAllFlatEntityMaps(),
...dependencyAllFlatEntityMaps,
},
);
}
private mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation<
T extends AllMetadataName,
>({
allFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps,
}: {
flatEntityMapsAndRelatedFlatEntityMaps: MetadataUniversalFlatEntityAndRelatedUniversalFlatEntityMaps<T>;
allFlatEntityMaps: AllUniversalFlatEntityMaps;
}) {
const flatEntityMapsKeys = Object.keys(
flatEntityMapsAndRelatedFlatEntityMaps,
) as (keyof MetadataUniversalFlatEntityAndRelatedUniversalFlatEntityMaps<T>)[];
for (const flatEntityMapsKey of flatEntityMapsKeys) {
// @ts-expect-error TODO improve
allFlatEntityMaps[flatEntityMapsKey] =
flatEntityMapsAndRelatedFlatEntityMaps[flatEntityMapsKey];
}
}
public async buildWorkspaceMigration({
workspaceId,
buildOptions,
@@ -142,6 +122,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
fromToAllFlatEntityMaps,
dependencyAllFlatEntityMaps,
});
const {
flatObjectMetadataMaps,
flatViewFieldMaps,
@@ -177,32 +158,13 @@ export class WorkspaceMigrationBuildOrchestratorService {
{
additionalCacheDataMaps,
buildOptions,
// Note: That's a hacky way to allow validating object against field metadatas, not optimal
dependencyOptimisticFlatEntityMaps: {
flatFieldMetadataMaps: {
byUniversalIdentifier: {
...dependencyAllFlatEntityMaps?.flatFieldMetadataMaps
?.byUniversalIdentifier,
...flatFieldMetadataMaps?.from.byUniversalIdentifier,
...flatFieldMetadataMaps?.to.byUniversalIdentifier,
},
},
},
///
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
from: fromFlatObjectMetadataMaps,
to: toFlatObjectMetadataMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
objectResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (objectResult.status === 'fail') {
orchestratorFailureReport.objectMetadata.push(...objectResult.errors);
} else {
@@ -220,22 +182,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatFieldMetadataMaps,
to: toFlatFieldMetadataMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
fieldResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (fieldResult.status === 'fail') {
orchestratorFailureReport.fieldMetadata.push(...fieldResult.errors);
} else {
@@ -252,24 +203,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatIndexMaps,
to: toFlatIndexMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatFieldMetadataMaps:
optimisticAllFlatEntityMaps.flatFieldMetadataMaps,
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
indexResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (indexResult.status === 'fail') {
orchestratorFailureReport.index.push(...indexResult.errors);
} else {
@@ -283,12 +221,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
await this.workspaceMigrationViewActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
dependencyOptimisticFlatEntityMaps: {
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
flatFieldMetadataMaps:
optimisticAllFlatEntityMaps.flatFieldMetadataMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
from: fromFlatViewMaps,
to: toFlatViewMaps,
buildOptions,
@@ -296,14 +229,6 @@ export class WorkspaceMigrationBuildOrchestratorService {
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
viewResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (viewResult.status === 'fail') {
orchestratorFailureReport.view.push(...viewResult.errors);
} else {
@@ -322,21 +247,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatViewFieldGroupMaps,
to: toFlatViewFieldGroupMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatViewMaps: optimisticAllFlatEntityMaps.flatViewMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
viewFieldGroupResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (viewFieldGroupResult.status === 'fail') {
orchestratorFailureReport.viewFieldGroup.push(
...viewFieldGroupResult.errors,
@@ -356,27 +271,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatViewFieldMaps,
to: toFlatViewFieldMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
flatFieldMetadataMaps:
optimisticAllFlatEntityMaps.flatFieldMetadataMaps,
flatViewMaps: optimisticAllFlatEntityMaps.flatViewMaps,
flatViewFieldGroupMaps:
optimisticAllFlatEntityMaps.flatViewFieldGroupMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
viewFieldResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (viewFieldResult.status === 'fail') {
orchestratorFailureReport.viewField.push(...viewFieldResult.errors);
} else {
@@ -397,21 +296,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatViewFilterGroupMaps,
to: toFlatViewFilterGroupMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatViewMaps: optimisticAllFlatEntityMaps.flatViewMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
viewFilterGroupResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (viewFilterGroupResult.status === 'fail') {
orchestratorFailureReport.viewFilterGroup.push(
...viewFilterGroupResult.errors,
@@ -432,25 +321,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatViewFilterMaps,
to: toFlatViewFilterMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatFieldMetadataMaps:
optimisticAllFlatEntityMaps.flatFieldMetadataMaps,
flatViewMaps: optimisticAllFlatEntityMaps.flatViewMaps,
flatViewFilterGroupMaps:
optimisticAllFlatEntityMaps.flatViewFilterGroupMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
viewFilterResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (viewFilterResult.status === 'fail') {
orchestratorFailureReport.viewFilter.push(...viewFilterResult.errors);
} else {
@@ -468,23 +343,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatViewGroupMaps,
to: toFlatViewGroupMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatFieldMetadataMaps:
optimisticAllFlatEntityMaps.flatFieldMetadataMaps,
flatViewMaps: optimisticAllFlatEntityMaps.flatViewMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
viewGroupResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (viewGroupResult.status === 'fail') {
orchestratorFailureReport.viewGroup.push(...viewGroupResult.errors);
} else {
@@ -504,23 +367,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatRowLevelPermissionPredicateGroupMaps,
to: toFlatRowLevelPermissionPredicateGroupMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatRoleMaps: optimisticAllFlatEntityMaps.flatRoleMaps,
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
rowLevelPermissionPredicateGroupResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (rowLevelPermissionPredicateGroupResult.status === 'fail') {
orchestratorFailureReport.rowLevelPermissionPredicateGroup.push(
...rowLevelPermissionPredicateGroupResult.errors,
@@ -543,27 +394,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatRowLevelPermissionPredicateMaps,
to: toFlatRowLevelPermissionPredicateMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatFieldMetadataMaps:
optimisticAllFlatEntityMaps.flatFieldMetadataMaps,
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
flatRowLevelPermissionPredicateGroupMaps:
optimisticAllFlatEntityMaps.flatRowLevelPermissionPredicateGroupMaps,
flatRoleMaps: optimisticAllFlatEntityMaps.flatRoleMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
rowLevelPermissionPredicateResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (rowLevelPermissionPredicateResult.status === 'fail') {
orchestratorFailureReport.rowLevelPermissionPredicate.push(
...rowLevelPermissionPredicateResult.errors,
@@ -585,19 +420,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatLogicFunctionMaps,
to: toFlatLogicFunctionMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: undefined,
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
logicFunctionResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (logicFunctionResult.status === 'fail') {
orchestratorFailureReport.logicFunction.push(
...logicFunctionResult.errors,
@@ -617,19 +444,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatRoleMaps,
to: toFlatRoleMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: undefined,
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
roleResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (roleResult.status === 'fail') {
orchestratorFailureReport.role.push(...roleResult.errors);
} else {
@@ -648,22 +467,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatRoleTargetMaps,
to: toFlatRoleTargetMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatAgentMaps: optimisticAllFlatEntityMaps.flatAgentMaps,
flatRoleMaps: optimisticAllFlatEntityMaps.flatRoleMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
roleTargetResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (roleTargetResult.status === 'fail') {
orchestratorFailureReport.roleTarget.push(...roleTargetResult.errors);
} else {
@@ -681,21 +489,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatAgentMaps,
to: toFlatAgentMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatRoleMaps: optimisticAllFlatEntityMaps.flatRoleMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
agentResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (agentResult.status === 'fail') {
orchestratorFailureReport.agent.push(...agentResult.errors);
} else {
@@ -713,19 +511,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatSkillMaps,
to: toFlatSkillMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: undefined,
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
skillResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (skillResult.status === 'fail') {
orchestratorFailureReport.skill.push(...skillResult.errors);
} else {
@@ -746,24 +536,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatCommandMenuItemMaps,
to: toFlatCommandMenuItemMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
flatFrontComponentMaps:
optimisticAllFlatEntityMaps.flatFrontComponentMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
commandMenuItemResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (commandMenuItemResult.status === 'fail') {
orchestratorFailureReport.commandMenuItem.push(
...commandMenuItemResult.errors,
@@ -787,23 +564,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatNavigationMenuItemMaps,
to: toFlatNavigationMenuItemMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
flatViewMaps: optimisticAllFlatEntityMaps.flatViewMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
navigationMenuItemResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (navigationMenuItemResult.status === 'fail') {
orchestratorFailureReport.navigationMenuItem.push(
...navigationMenuItemResult.errors,
@@ -825,24 +590,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatPageLayoutMaps,
to: toFlatPageLayoutMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
flatPageLayoutTabMaps:
optimisticAllFlatEntityMaps.flatPageLayoutTabMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
pageLayoutResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (pageLayoutResult.status === 'fail') {
orchestratorFailureReport.pageLayout.push(...pageLayoutResult.errors);
} else {
@@ -850,9 +602,6 @@ export class WorkspaceMigrationBuildOrchestratorService {
}
}
// Page layout tabs must be processed before page layout widgets because
// widgets reference tabs, and the optimistic cache needs to contain the
// newly created tabs before widget validation runs
if (isDefined(flatPageLayoutTabMaps)) {
const { from: fromFlatPageLayoutTabMaps, to: toFlatPageLayoutTabMaps } =
flatPageLayoutTabMaps;
@@ -864,22 +613,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatPageLayoutTabMaps,
to: toFlatPageLayoutTabMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatPageLayoutMaps:
optimisticAllFlatEntityMaps.flatPageLayoutMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
pageLayoutTabResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (pageLayoutTabResult.status === 'fail') {
orchestratorFailureReport.pageLayoutTab.push(
...pageLayoutTabResult.errors,
@@ -902,24 +640,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatPageLayoutWidgetMaps,
to: toFlatPageLayoutWidgetMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatObjectMetadataMaps:
optimisticAllFlatEntityMaps.flatObjectMetadataMaps,
flatPageLayoutTabMaps:
optimisticAllFlatEntityMaps.flatPageLayoutTabMaps,
},
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
pageLayoutWidgetResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (pageLayoutWidgetResult.status === 'fail') {
orchestratorFailureReport.pageLayoutWidget.push(
...pageLayoutWidgetResult.errors,
@@ -941,19 +666,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatFrontComponentMaps,
to: toFlatFrontComponentMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: undefined,
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
frontComponentResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (frontComponentResult.status === 'fail') {
orchestratorFailureReport.frontComponent.push(
...frontComponentResult.errors,
@@ -974,19 +691,11 @@ export class WorkspaceMigrationBuildOrchestratorService {
from: fromFlatWebhookMaps,
to: toFlatWebhookMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: undefined,
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
webhookResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (webhookResult.status === 'fail') {
orchestratorFailureReport.webhook.push(...webhookResult.errors);
} else {
@@ -8,13 +8,20 @@ import { isDefined } from 'twenty-shared/utils';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { MetadataEventEmitter } from 'src/engine/metadata-event-emitter/metadata-event-emitter';
import { ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-required-metadata-for-validation.constant';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { FlatEntityToCreateDeleteUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-to-create-delete-update.type';
import { MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { MetadataUniversalFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-universal-flat-entity.type';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { getMetadataRelatedMetadataNamesForValidation } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names-for-validation.util';
import { getSubFlatEntityMapsByApplicationIdsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-maps-by-application-ids-or-throw.util';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
import { WorkspaceMigrationV2Exception } from 'src/engine/workspace-manager/workspace-migration.exception';
import { WORKSPACE_MIGRATION_ADDITIONAL_CACHE_DATA_MAPS_KEY } from 'src/engine/workspace-manager/workspace-migration/constant/workspace-migration-additional-cache-data-maps-key.constant';
import {
@@ -29,7 +36,7 @@ import {
WorkspaceMigrationOrchestratorFailedResult,
WorkspaceMigrationOrchestratorSuccessfulResult,
} from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { computeUniversalFlatEntityMapsFromTo } from 'src/engine/workspace-manager/workspace-migration/utils/compute-universal-flat-entity-maps-from-to.util';
import { computeUniversalFlatEntityMapsFromToThroughMutation } from 'src/engine/workspace-manager/workspace-migration/utils/compute-universal-flat-entity-maps-from-to-through-mutation.util';
import { InferDeletionFromMissingEntities } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/infer-deletion-from-missing-entities.type';
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/services/workspace-migration-runner.service';
@@ -39,8 +46,6 @@ type ValidateBuildAndRunWorkspaceMigrationFromMatriceArgs = {
[P in AllMetadataName]?: FlatEntityToCreateDeleteUpdate<P>;
};
isSystemBuild?: boolean;
// TODO remove once application synchronization do not consume services atomically anymore
// Should always be the universal workspace custom app id
applicationUniversalIdentifier: string;
};
@@ -66,29 +71,30 @@ export class WorkspaceMigrationValidateBuildAndRunService {
private async computeAllRelatedFlatEntityMaps({
allFlatEntityOperationByMetadataName,
workspaceId,
applicationUniversalIdentifier,
}: ValidateBuildAndRunWorkspaceMigrationFromMatriceArgs) {
const allMetadataNameToCompare = Object.keys(
allFlatEntityOperationByMetadataName,
) as AllMetadataName[];
const allDependencyMetadataName = allMetadataNameToCompare.flatMap(
(metadataName) =>
Object.keys(
ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION[metadataName],
) as AllMetadataName[],
);
const allMetadataNameCacheToCompute = [
...new Set([...allMetadataNameToCompare, ...allDependencyMetadataName]),
...new Set([
...allMetadataNameToCompare,
...allMetadataNameToCompare.flatMap(
getMetadataRelatedMetadataNamesForValidation,
),
]),
];
const allFlatEntityMapsCacheKeysToCompute =
allMetadataNameCacheToCompute.map(getMetadataFlatEntityMapsKey);
const allRelatedFlatEntityMaps =
const { flatApplicationMaps, ...allRelatedFlatEntityMaps } =
await this.workspaceCacheService.getOrRecompute(workspaceId, [
...allFlatEntityMapsCacheKeysToCompute,
...WORKSPACE_MIGRATION_ADDITIONAL_CACHE_DATA_MAPS_KEY,
'flatApplicationMaps',
]);
const initialAccumulator = allDependencyMetadataName.reduce<
const initialAccumulator = allMetadataNameCacheToCompute.reduce<
Partial<AllFlatEntityMaps>
>(
(allFlatEntityMaps, metadataName) => ({
@@ -98,7 +104,29 @@ export class WorkspaceMigrationValidateBuildAndRunService {
}),
{},
);
const dependencyAllFlatEntityMaps = allDependencyMetadataName.reduce(
const twentyStandardApplicationId =
flatApplicationMaps.idByUniversalIdentifier[
TWENTY_STANDARD_APPLICATION.universalIdentifier
];
const applicationId =
flatApplicationMaps.idByUniversalIdentifier[
applicationUniversalIdentifier
];
if (!isDefined(twentyStandardApplicationId) || !isDefined(applicationId)) {
throw new FlatEntityMapsException(
'Application to build and its dependent application not found',
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const isBuildingTwentyStandardApplication =
applicationUniversalIdentifier ===
TWENTY_STANDARD_APPLICATION.universalIdentifier;
const dependencyAllFlatEntityMaps = allMetadataNameCacheToCompute.reduce(
(allFlatEntityMaps, metadataName) => {
const metadataFlatEntityMapsKey =
getMetadataFlatEntityMapsKey(metadataName);
@@ -106,7 +134,15 @@ export class WorkspaceMigrationValidateBuildAndRunService {
return {
...allFlatEntityMaps,
[metadataFlatEntityMapsKey]:
allRelatedFlatEntityMaps[metadataFlatEntityMapsKey],
getSubFlatEntityMapsByApplicationIdsOrThrow<
MetadataFlatEntity<typeof metadataName>
>({
applicationIds: isBuildingTwentyStandardApplication
? [applicationId]
: [applicationId, twentyStandardApplicationId],
flatEntityMaps:
allRelatedFlatEntityMaps[metadataFlatEntityMapsKey],
}),
};
},
initialAccumulator,
@@ -153,10 +189,10 @@ export class WorkspaceMigrationValidateBuildAndRunService {
});
const fromToAllFlatEntityMaps: FromToAllUniversalFlatEntityMaps = {};
const inferDeletionFromMissingEntities: InferDeletionFromMissingEntities =
{};
const idByUniversalIdentifierByMetadataName: IdByUniversalIdentifierByMetadataName =
{};
const inferDeletionFromMissingEntities: InferDeletionFromMissingEntities =
{};
const allMetadataNameToCompare = Object.keys(
allFlatEntityOperationByMetadataName,
) as AllMetadataName[];
@@ -166,7 +202,10 @@ export class WorkspaceMigrationValidateBuildAndRunService {
allFlatEntityOperationByMetadataName[metadataName];
if (!isDefined(flatEntityOperations)) {
throw new Error('Should never occurs');
throw new FlatEntityMapsException(
`Could not load flat entity maps to compare for ${metadataName}, should never occur`,
FlatEntityMapsExceptionCode.INTERNAL_SERVER_ERROR,
);
}
const { flatEntityToCreate, flatEntityToDelete, flatEntityToUpdate } =
flatEntityOperations;
@@ -193,8 +232,8 @@ export class WorkspaceMigrationValidateBuildAndRunService {
// @ts-expect-error Metadata flat entity maps cache key and metadataName colliding
fromToAllFlatEntityMaps[flatEntityMapsKey] =
computeUniversalFlatEntityMapsFromTo({
flatEntityMaps,
computeUniversalFlatEntityMapsFromToThroughMutation({
flatEntityMaps: structuredClone(flatEntityMaps),
flatEntityToCreate,
flatEntityToDelete,
flatEntityToUpdate,