Add default relation to standard object on custom object in manifest (#18033)

add default relation fields when creating an object from an application

---------

Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
martmull
2026-02-20 11:49:06 +01:00
committed by GitHub
co-authored by prastoin
parent d060c843d1
commit 3bc887e12e
48 changed files with 1812 additions and 554 deletions
@@ -1,23 +1,25 @@
import { Injectable, Logger } from '@nestjs/common';
import { type Manifest, type RoleManifest } from 'twenty-shared/application';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
import {
ApplicationException,
ApplicationExceptionCode,
} from 'src/engine/core-modules/application/application.exception';
import { APPLICATION_MANIFEST_METADATA_NAMES } from 'src/engine/core-modules/application/constants/application-manifest-metadata-names.constant';
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { buildFromToAllUniversalFlatEntityMaps } from 'src/engine/core-modules/application/utils/build-from-to-all-universal-flat-entity-maps.util';
import { computeApplicationManifestAllUniversalFlatEntityMaps } from 'src/engine/core-modules/application/utils/compute-application-manifest-all-universal-flat-entity-maps.util';
import { getSubApplicationFromToAllFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-sub-application-from-to-all-flat-entity-maps.util';
import { getApplicationSubAllFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-application-sub-all-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { FieldPermissionService } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.service';
import { ObjectPermissionService } from 'src/engine/metadata-modules/object-permission/object-permission.service';
import { PermissionFlagService } from 'src/engine/metadata-modules/permission-flag/permission-flag.service';
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 { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
import { WorkspaceMigration } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration.type';
@@ -48,32 +50,42 @@ export class ApplicationManifestMigrationService {
}): Promise<WorkspaceMigration> {
const now = new Date().toISOString();
const toAllUniversalFlatEntityMaps =
computeApplicationManifestAllUniversalFlatEntityMaps({
manifest,
applicationUniversalIdentifier:
ownerFlatApplication.universalIdentifier,
now,
});
const { twentyStandardFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{ workspaceId },
);
const cacheResult = await this.workspaceCacheService.getOrRecompute(
workspaceId,
[
...APPLICATION_MANIFEST_METADATA_NAMES.map(
getMetadataFlatEntityMapsKey,
),
...Object.values(ALL_METADATA_NAME).map(getMetadataFlatEntityMapsKey),
'featureFlagsMap',
],
);
const { featureFlagsMap, ...fromAllFlatEntityMaps } = cacheResult;
const { featureFlagsMap, ...existingAllFlatEntityMaps } = cacheResult;
const fromToAllFlatEntityMaps = getSubApplicationFromToAllFlatEntityMaps({
applicationId: ownerFlatApplication.id,
fromAllFlatEntityMaps,
toAllUniversalFlatEntityMaps,
const toAllUniversalFlatEntityMaps =
computeApplicationManifestAllUniversalFlatEntityMaps({
manifest,
ownerFlatApplication,
now,
});
const fromAllFlatEntityMaps = getApplicationSubAllFlatEntityMaps({
applicationIds: [ownerFlatApplication.id],
fromAllFlatEntityMaps: existingAllFlatEntityMaps,
});
const dependencyAllFlatEntityMaps =
ownerFlatApplication.universalIdentifier ===
TWENTY_STANDARD_APPLICATION.universalIdentifier
? undefined
: getApplicationSubAllFlatEntityMaps({
applicationIds: [twentyStandardFlatApplication.id],
fromAllFlatEntityMaps: existingAllFlatEntityMaps,
});
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigrationFromTo(
{
@@ -83,8 +95,12 @@ export class ApplicationManifestMigrationService {
applicationUniversalIdentifier:
ownerFlatApplication.universalIdentifier,
},
fromToAllFlatEntityMaps,
fromToAllFlatEntityMaps: buildFromToAllUniversalFlatEntityMaps({
fromAllFlatEntityMaps,
toAllUniversalFlatEntityMaps,
}),
workspaceId,
dependencyAllFlatEntityMaps,
additionalCacheDataMaps: { featureFlagsMap },
},
);
@@ -3,22 +3,23 @@ import { Injectable, Logger } from '@nestjs/common';
import { FileFolder } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { PackageJson } from 'type-fest';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import {
ApplicationException,
ApplicationExceptionCode,
} from 'src/engine/core-modules/application/application.exception';
import { APPLICATION_MANIFEST_METADATA_NAMES } from 'src/engine/core-modules/application/constants/application-manifest-metadata-names.constant';
import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input';
import { ApplicationManifestMigrationService } from 'src/engine/core-modules/application/services/application-manifest-migration.service';
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { buildFromToAllUniversalFlatEntityMaps } from 'src/engine/core-modules/application/utils/build-from-to-all-universal-flat-entity-maps.util';
import { getApplicationSubAllFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-application-sub-all-flat-entity-maps.util';
import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application/utils/get-default-application-package-fields.util';
import { getEmptyApplicationManifestAllUniversalFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-empty-application-manifest-all-universal-flat-entity-maps.util';
import { getSubApplicationFromToAllFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-sub-application-from-to-all-flat-entity-maps.util';
import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
@@ -152,7 +153,7 @@ export class ApplicationSyncService {
);
}
const flatEntityMapsCacheKeys = APPLICATION_MANIFEST_METADATA_NAMES.map(
const flatEntityMapsCacheKeys = Object.values(ALL_METADATA_NAME).map(
getMetadataFlatEntityMapsKey,
);
@@ -163,11 +164,16 @@ export class ApplicationSyncService {
const { featureFlagsMap, ...fromAllFlatEntityMaps } = cacheResult;
const fromToAllFlatEntityMaps = getSubApplicationFromToAllFlatEntityMaps({
applicationId: application.id,
fromAllFlatEntityMaps,
toAllUniversalFlatEntityMaps:
getEmptyApplicationManifestAllUniversalFlatEntityMaps(),
const applicationFromAllFlatEntityMaps = getApplicationSubAllFlatEntityMaps(
{
applicationIds: [application.id],
fromAllFlatEntityMaps,
},
);
const fromToAllFlatEntityMaps = buildFromToAllUniversalFlatEntityMaps({
fromAllFlatEntityMaps: applicationFromAllFlatEntityMaps,
toAllUniversalFlatEntityMaps: createEmptyAllFlatEntityMaps(),
});
const validateAndBuildResult =
@@ -0,0 +1,31 @@
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { type FromToAllUniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
export const buildFromToAllUniversalFlatEntityMaps = ({
fromAllFlatEntityMaps,
toAllUniversalFlatEntityMaps,
}: {
fromAllFlatEntityMaps: AllFlatEntityMaps;
toAllUniversalFlatEntityMaps: AllFlatEntityMaps;
}): FromToAllUniversalFlatEntityMaps => {
const fromToAllFlatEntityMaps: FromToAllUniversalFlatEntityMaps = {};
for (const metadataName of Object.values(ALL_METADATA_NAME)) {
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(metadataName);
const fromFlatEntityMaps = fromAllFlatEntityMaps[flatEntityMapsKey];
const toFlatEntityMaps = toAllUniversalFlatEntityMaps[flatEntityMapsKey];
const fromTo = {
from: fromFlatEntityMaps,
to: toFlatEntityMaps,
};
// @ts-expect-error Metadata flat entity maps cache key and metadataName colliding
fromToAllFlatEntityMaps[flatEntityMapsKey] = fromTo;
}
return fromToAllFlatEntityMaps;
};
@@ -1,6 +1,6 @@
import { type Manifest } from 'twenty-shared/application';
import { type ApplicationManifestMetadataName } from 'src/engine/core-modules/application/constants/application-manifest-metadata-names.constant';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { fromCommandMenuItemManifestToUniversalFlatCommandMenuItem } from 'src/engine/core-modules/application/utils/from-command-menu-item-manifest-to-universal-flat-command-menu-item.util';
import { fromFieldManifestToUniversalFlatFieldMetadata } from 'src/engine/core-modules/application/utils/from-field-manifest-to-universal-flat-field-metadata.util';
import { fromFrontComponentManifestToUniversalFlatFrontComponent } from 'src/engine/core-modules/application/utils/from-front-component-manifest-to-universal-flat-front-component.util';
@@ -18,140 +18,115 @@ import { fromViewFilterGroupManifestToUniversalFlatViewFilterGroup } from 'src/e
import { fromViewFilterManifestToUniversalFlatViewFilter } from 'src/engine/core-modules/application/utils/from-view-filter-manifest-to-universal-flat-view-filter.util';
import { fromViewGroupManifestToUniversalFlatViewGroup } from 'src/engine/core-modules/application/utils/from-view-group-manifest-to-universal-flat-view-group.util';
import { fromViewManifestToUniversalFlatView } from 'src/engine/core-modules/application/utils/from-view-manifest-to-universal-flat-view.util';
import { getEmptyApplicationManifestAllUniversalFlatEntityMaps } from 'src/engine/core-modules/application/utils/get-empty-application-manifest-all-universal-flat-entity-maps.util';
import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type MetadataToFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/types/metadata-to-flat-entity-maps-key';
import { type AllUniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/all-universal-flat-entity-maps.type';
import { addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/add-universal-flat-entity-to-universal-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
export type ApplicationManifestAllUniversalFlatEntityMaps = Pick<
AllUniversalFlatEntityMaps,
MetadataToFlatEntityMapsKey<ApplicationManifestMetadataName>
>;
export type ApplicationManifestAllFlatEntityMaps = Pick<
AllFlatEntityMaps,
MetadataToFlatEntityMapsKey<ApplicationManifestMetadataName>
>;
import { addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/add-universal-flat-entity-to-universal-flat-entity-maps-through-mutation-or-throw.util';
export const computeApplicationManifestAllUniversalFlatEntityMaps = ({
manifest,
applicationUniversalIdentifier,
ownerFlatApplication,
now,
}: {
manifest: Manifest;
applicationUniversalIdentifier: string;
ownerFlatApplication: FlatApplication;
now: string;
}): ApplicationManifestAllUniversalFlatEntityMaps => {
const allUniversalFlatEntityMaps =
getEmptyApplicationManifestAllUniversalFlatEntityMaps();
}): AllFlatEntityMaps => {
const allUniversalFlatEntityMaps = createEmptyAllFlatEntityMaps();
const { universalIdentifier: applicationUniversalIdentifier } =
ownerFlatApplication;
for (const objectManifest of manifest.objects) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'objectMetadata',
universalFlatEntity: fromObjectManifestToUniversalFlatObjectMetadata({
objectManifest,
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromObjectManifestToUniversalFlatObjectMetadata({
objectManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatObjectMetadataMaps,
});
for (const fieldManifest of objectManifest.fields) {
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: {
...fieldManifest,
objectUniversalIdentifier: objectManifest.universalIdentifier,
},
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
for (const fieldManifest of objectManifest.fields) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'fieldMetadata',
universalFlatEntity: fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: {
...fieldManifest,
objectUniversalIdentifier: objectManifest.universalIdentifier,
},
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatFieldMetadataMaps,
});
}
}
for (const fieldManifest of manifest.fields) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'fieldMetadata',
universalFlatEntity: fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: fieldManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: fieldManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatFieldMetadataMaps,
});
}
for (const logicFunctionManifest of manifest.logicFunctions) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'logicFunction',
universalFlatEntity:
fromLogicFunctionManifestToUniversalFlatLogicFunction({
logicFunctionManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromLogicFunctionManifestToUniversalFlatLogicFunction({
logicFunctionManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatLogicFunctionMaps,
});
}
for (const frontComponentManifest of manifest.frontComponents) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'frontComponent',
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromFrontComponentManifestToUniversalFlatFrontComponent({
frontComponentManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatFrontComponentMaps,
});
if (frontComponentManifest.command) {
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromFrontComponentManifestToUniversalFlatFrontComponent({
frontComponentManifest,
fromCommandMenuItemManifestToUniversalFlatCommandMenuItem({
commandMenuItemManifest: {
...frontComponentManifest.command,
frontComponentUniversalIdentifier:
frontComponentManifest.universalIdentifier,
},
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
if (frontComponentManifest.command) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'commandMenuItem',
universalFlatEntity:
fromCommandMenuItemManifestToUniversalFlatCommandMenuItem({
commandMenuItemManifest: {
...frontComponentManifest.command,
frontComponentUniversalIdentifier:
frontComponentManifest.universalIdentifier,
},
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatCommandMenuItemMaps,
});
}
}
for (const roleManifest of manifest.roles) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'role',
universalFlatEntity: fromRoleManifestToUniversalFlatRole({
roleManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromRoleManifestToUniversalFlatRole({
roleManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate: allUniversalFlatEntityMaps.flatRoleMaps,
});
}
for (const skillManifest of manifest.skills ?? []) {
@@ -169,157 +144,135 @@ export const computeApplicationManifestAllUniversalFlatEntityMaps = ({
}
for (const viewManifest of manifest.views ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'view',
universalFlatEntity: fromViewManifestToUniversalFlatView({
viewManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromViewManifestToUniversalFlatView({
viewManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate: allUniversalFlatEntityMaps.flatViewMaps,
});
for (const viewFieldGroupManifest of viewManifest.fieldGroups ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'viewFieldGroup',
universalFlatEntity:
fromViewFieldGroupManifestToUniversalFlatViewFieldGroup({
viewFieldGroupManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromViewFieldGroupManifestToUniversalFlatViewFieldGroup({
viewFieldGroupManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatViewFieldGroupMaps,
});
}
for (const viewFieldManifest of viewManifest.fields ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'viewField',
universalFlatEntity: fromViewFieldManifestToUniversalFlatViewField({
viewFieldManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromViewFieldManifestToUniversalFlatViewField({
viewFieldManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatViewFieldMaps,
});
}
for (const viewFilterGroupManifest of viewManifest.filterGroups ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'viewFilterGroup',
universalFlatEntity:
fromViewFilterGroupManifestToUniversalFlatViewFilterGroup({
viewFilterGroupManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromViewFilterGroupManifestToUniversalFlatViewFilterGroup({
viewFilterGroupManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatViewFilterGroupMaps,
});
}
for (const viewFilterManifest of viewManifest.filters ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'viewFilter',
universalFlatEntity: fromViewFilterManifestToUniversalFlatViewFilter({
viewFilterManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromViewFilterManifestToUniversalFlatViewFilter({
viewFilterManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatViewFilterMaps,
});
}
for (const viewGroupManifest of viewManifest.groups ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'viewGroup',
universalFlatEntity: fromViewGroupManifestToUniversalFlatViewGroup({
viewGroupManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromViewGroupManifestToUniversalFlatViewGroup({
viewGroupManifest,
viewUniversalIdentifier: viewManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatViewGroupMaps,
});
}
}
for (const navigationMenuItemManifest of manifest.navigationMenuItems ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'navigationMenuItem',
universalFlatEntity:
fromNavigationMenuItemManifestToUniversalFlatNavigationMenuItem({
navigationMenuItemManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
}
for (const pageLayoutManifest of manifest.pageLayouts ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'pageLayout',
universalFlatEntity: fromPageLayoutManifestToUniversalFlatPageLayout({
pageLayoutManifest,
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromNavigationMenuItemManifestToUniversalFlatNavigationMenuItem({
navigationMenuItemManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatNavigationMenuItemMaps,
});
}
for (const pageLayoutManifest of manifest.pageLayouts ?? []) {
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromPageLayoutManifestToUniversalFlatPageLayout({
pageLayoutManifest,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatPageLayoutMaps,
});
for (const pageLayoutTabManifest of pageLayoutManifest.tabs ?? []) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'pageLayoutTab',
universalFlatEntity:
fromPageLayoutTabManifestToUniversalFlatPageLayoutTab({
pageLayoutTabManifest,
pageLayoutUniversalIdentifier:
pageLayoutManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate: allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromPageLayoutTabManifestToUniversalFlatPageLayoutTab({
pageLayoutTabManifest,
pageLayoutUniversalIdentifier:
pageLayoutManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatPageLayoutTabMaps,
});
for (const pageLayoutWidgetManifest of pageLayoutTabManifest.widgets ??
[]) {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName: 'pageLayoutWidget',
universalFlatEntity:
fromPageLayoutWidgetManifestToUniversalFlatPageLayoutWidget({
pageLayoutWidgetManifest,
pageLayoutTabUniversalIdentifier:
pageLayoutTabManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityAndRelatedMapsToMutate:
allUniversalFlatEntityMaps,
},
);
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromPageLayoutWidgetManifestToUniversalFlatPageLayoutWidget({
pageLayoutWidgetManifest,
pageLayoutTabUniversalIdentifier:
pageLayoutTabManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatPageLayoutWidgetMaps,
});
}
}
}
@@ -1,8 +1,8 @@
import { type FieldManifest } from 'twenty-shared/application';
import {
type FieldManifest,
type RelationFieldManifest,
} from 'twenty-shared/application';
import { type FieldMetadataType } from 'twenty-shared/types';
FieldMetadataType,
type RelationAndMorphRelationFieldMetadataType,
} from 'twenty-shared/types';
import {
ApplicationException,
@@ -14,12 +14,12 @@ import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
const isRelationFieldManifest = (
fieldManifest: FieldManifest<FieldMetadataType>,
): fieldManifest is RelationFieldManifest =>
fieldManifest: FieldManifest,
): fieldManifest is FieldManifest<RelationAndMorphRelationFieldMetadataType> =>
isMorphOrRelationFieldMetadataType(fieldManifest.type);
const getRelationTargetUniversalIdentifiers = (
fieldManifest: FieldManifest<FieldMetadataType>,
fieldManifest: FieldManifest,
): {
relationTargetFieldMetadataUniversalIdentifier: string | null;
relationTargetObjectMetadataUniversalIdentifier: string | null;
@@ -54,7 +54,7 @@ export const fromFieldManifestToUniversalFlatFieldMetadata = ({
applicationUniversalIdentifier,
now,
}: {
fieldManifest: FieldManifest<FieldMetadataType> & {
fieldManifest: FieldManifest & {
objectUniversalIdentifier: string;
};
applicationUniversalIdentifier: string;
@@ -85,7 +85,10 @@ export const fromFieldManifestToUniversalFlatFieldMetadata = ({
isNullable: fieldManifest.isNullable ?? true,
isUnique: false,
isLabelSyncedWithName: false,
morphId: null,
morphId:
fieldManifest.type === FieldMetadataType.MORPH_RELATION
? (fieldManifest.morphId ?? null)
: null,
objectMetadataUniversalIdentifier: fieldManifest.objectUniversalIdentifier,
relationTargetFieldMetadataUniversalIdentifier,
relationTargetObjectMetadataUniversalIdentifier,
@@ -0,0 +1,35 @@
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { getSubFlatEntityMapsByApplicationIdsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-maps-by-application-ids-or-throw.util';
export const getApplicationSubAllFlatEntityMaps = ({
applicationIds,
fromAllFlatEntityMaps,
}: {
applicationIds: string[];
fromAllFlatEntityMaps: AllFlatEntityMaps;
}): AllFlatEntityMaps => {
const emptyAllFlatEntityMaps = createEmptyAllFlatEntityMaps();
for (const metadataName of Object.values(ALL_METADATA_NAME)) {
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(metadataName);
const fromFlatEntityMaps = fromAllFlatEntityMaps[flatEntityMapsKey];
const applicationSubFlatEntityMaps =
getSubFlatEntityMapsByApplicationIdsOrThrow<
MetadataFlatEntity<typeof metadataName>
>({
applicationIds,
flatEntityMaps: fromFlatEntityMaps,
});
// @ts-expect-error Metadata flat entity maps cache key and metadataName colliding
emptyAllFlatEntityMaps[flatEntityMapsKey] = applicationSubFlatEntityMaps;
}
return emptyAllFlatEntityMaps;
};
@@ -1,16 +0,0 @@
import { APPLICATION_MANIFEST_METADATA_NAMES } from 'src/engine/core-modules/application/constants/application-manifest-metadata-names.constant';
import { type ApplicationManifestAllUniversalFlatEntityMaps } from 'src/engine/core-modules/application/utils/compute-application-manifest-all-universal-flat-entity-maps.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
export const getEmptyApplicationManifestAllUniversalFlatEntityMaps =
(): ApplicationManifestAllUniversalFlatEntityMaps => {
const result = {} as ApplicationManifestAllUniversalFlatEntityMaps;
for (const metadataName of APPLICATION_MANIFEST_METADATA_NAMES) {
const key = getMetadataFlatEntityMapsKey(metadataName);
result[key] = { byUniversalIdentifier: {} };
}
return result;
};
@@ -1,51 +0,0 @@
import { type FromTo } from 'twenty-shared/types';
import { APPLICATION_MANIFEST_METADATA_NAMES } from 'src/engine/core-modules/application/constants/application-manifest-metadata-names.constant';
import {
type ApplicationManifestAllFlatEntityMaps,
type ApplicationManifestAllUniversalFlatEntityMaps,
} from 'src/engine/core-modules/application/utils/compute-application-manifest-all-universal-flat-entity-maps.util';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { getSubFlatEntityMapsByApplicationIdsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-maps-by-application-ids-or-throw.util';
import { type AllUniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/all-universal-flat-entity-maps.type';
export type FromToApplicationManifestAllUniversalFlatEntityMaps = {
[P in keyof ApplicationManifestAllFlatEntityMaps]?: FromTo<
AllUniversalFlatEntityMaps[P]
>;
};
export const getSubApplicationFromToAllFlatEntityMaps = ({
applicationId,
fromAllFlatEntityMaps,
toAllUniversalFlatEntityMaps,
}: {
applicationId: string;
fromAllFlatEntityMaps: ApplicationManifestAllFlatEntityMaps;
toAllUniversalFlatEntityMaps: ApplicationManifestAllUniversalFlatEntityMaps;
}): FromToApplicationManifestAllUniversalFlatEntityMaps => {
const fromToAllFlatEntityMaps: FromToApplicationManifestAllUniversalFlatEntityMaps =
{};
for (const metadataName of APPLICATION_MANIFEST_METADATA_NAMES) {
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(metadataName);
const fromFlatEntityMaps = fromAllFlatEntityMaps[flatEntityMapsKey];
const toFlatEntityMaps = toAllUniversalFlatEntityMaps[flatEntityMapsKey];
const fromTo = {
from: getSubFlatEntityMapsByApplicationIdsOrThrow<
MetadataFlatEntity<typeof metadataName>
>({
applicationIds: [applicationId],
flatEntityMaps: fromFlatEntityMaps,
}),
to: toFlatEntityMaps,
};
// @ts-expect-error Metadata flat entity maps cache key and metadataName colliding
fromToAllFlatEntityMaps[flatEntityMapsKey] = fromTo;
}
return fromToAllFlatEntityMaps;
};
@@ -12,6 +12,7 @@ import { type FlatApplication } from 'src/engine/core-modules/application/types/
import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-executor-tmpdir-folder';
import { ConsoleListener } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/intercept-console';
import { TemporaryDirManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager';
import { HANDLER_NAME_REGEX } from 'src/engine/metadata-modules/logic-function/constants/handler.contant';
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/application/utils/copy-yarn-engine-and-build-dependencies';
import type { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service';
@@ -215,9 +216,9 @@ export class LocalDriver implements LogicFunctionDriver {
builtFileAbsPath: string;
handlerName: string;
}) {
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(handlerName)) {
if (!HANDLER_NAME_REGEX.test(handlerName)) {
throw new Error(
`Invalid handlerName "${handlerName}": must be a valid JavaScript identifier`,
`Invalid handlerName "${handlerName}": must be a valid JavaScript identifier or dotted path`,
);
}