Migrate field widgets to backend (#18808)
- Renamed FieldConfiguration's layout field to fieldDisplayMode as it caused issues with the layout field of BarChartConfiguration - Create relation Field widgets for standard objects --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
d90d2e3151
commit
be89ef30cd
+39
-1
@@ -2,9 +2,9 @@ import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { FeatureFlagKey } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type FindOneOptions, type Repository } from 'typeorm';
|
||||
import { FeatureFlagKey } from 'twenty-shared/types';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { fromCreateFieldInputToFlatFieldMetadatasToCreate } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-create-field-input-to-flat-field-metadatas-to-create.util';
|
||||
@@ -26,6 +27,7 @@ import { fromDeleteFieldInputToFlatFieldMetadatasToDelete } from 'src/engine/met
|
||||
import { fromUpdateFieldInputToFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-update-field-input-to-flat-field-metadata.util';
|
||||
import { throwOnFieldInputTranspilationsError } from 'src/engine/metadata-modules/flat-field-metadata/utils/throw-on-field-input-transpilations-error.util';
|
||||
import { computeFlatViewFieldsFromFieldsWidgets } from 'src/engine/metadata-modules/flat-view-field/utils/compute-flat-view-fields-from-fields-widgets.util';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { EMPTY_ORCHESTRATOR_FAILURE_REPORT } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-failure-report.constant';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
@@ -93,6 +95,7 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatIndexMaps: existingFlatIndexMaps,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
@@ -100,6 +103,7 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
'flatObjectMetadataMaps',
|
||||
'flatIndexMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatPageLayoutWidgetMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
@@ -122,6 +126,31 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
},
|
||||
);
|
||||
|
||||
const deletedFieldIds = new Set(
|
||||
flatFieldMetadatasToDelete
|
||||
.map((f) => {
|
||||
const resolved = findFlatEntityByUniversalIdentifier({
|
||||
universalIdentifier: f.universalIdentifier,
|
||||
flatEntityMaps: existingFlatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
return resolved?.id;
|
||||
})
|
||||
.filter(isDefined),
|
||||
);
|
||||
|
||||
const flatPageLayoutWidgetsToDelete = Object.values(
|
||||
existingFlatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(widget) =>
|
||||
!isDefined(widget.deletedAt) &&
|
||||
widget.configuration?.configurationType ===
|
||||
WidgetConfigurationType.FIELD &&
|
||||
deletedFieldIds.has(widget.configuration.fieldMetadataId),
|
||||
);
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
@@ -136,6 +165,15 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
flatEntityToDelete: flatIndexesToDelete,
|
||||
flatEntityToUpdate: flatIndexesToUpdate,
|
||||
},
|
||||
...(flatPageLayoutWidgetsToDelete.length > 0
|
||||
? {
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: flatPageLayoutWidgetsToDelete,
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild,
|
||||
|
||||
+4
-8
@@ -51,10 +51,8 @@ export class FlatPageLayoutWidgetTypeValidatorService {
|
||||
msg`Widget type VIEW is not supported yet.`,
|
||||
),
|
||||
IFRAME: validateIframeFlatPageLayoutWidgetForCreation,
|
||||
FIELD: rejectWidgetType(
|
||||
WidgetType.FIELD,
|
||||
'Widget type FIELD is not supported yet.',
|
||||
msg`Widget type FIELD is not supported yet.`,
|
||||
FIELD: validateSimpleRecordPageWidgetForCreation(
|
||||
WidgetConfigurationType.FIELD,
|
||||
),
|
||||
FIELDS: validateFieldsFlatPageLayoutWidgetForCreation,
|
||||
GRAPH: validateGraphFlatPageLayoutWidgetForCreation,
|
||||
@@ -101,10 +99,8 @@ export class FlatPageLayoutWidgetTypeValidatorService {
|
||||
msg`Widget type VIEW is not supported yet.`,
|
||||
),
|
||||
IFRAME: validateIframeFlatPageLayoutWidgetForUpdate,
|
||||
FIELD: rejectWidgetType(
|
||||
WidgetType.FIELD,
|
||||
'Widget type FIELD is not supported yet.',
|
||||
msg`Widget type FIELD is not supported yet.`,
|
||||
FIELD: validateSimpleRecordPageWidgetForUpdate(
|
||||
WidgetConfigurationType.FIELD,
|
||||
),
|
||||
FIELDS: () => [],
|
||||
GRAPH: validateGraphFlatPageLayoutWidgetForUpdate,
|
||||
|
||||
+18
-1
@@ -321,8 +321,25 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
|
||||
};
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.FIELD: {
|
||||
const { fieldMetadataId, fieldDisplayMode, configurationType } =
|
||||
configuration;
|
||||
|
||||
const fieldMetadataUniversalIdentifier =
|
||||
getFieldMetadataUniversalIdentifier({
|
||||
fieldMetadataId,
|
||||
fieldMetadataUniversalIdentifierById,
|
||||
shouldThrowOnMissingIdentifier,
|
||||
});
|
||||
|
||||
return {
|
||||
configurationType,
|
||||
fieldMetadataId: fieldMetadataUniversalIdentifier ?? fieldMetadataId,
|
||||
fieldDisplayMode,
|
||||
};
|
||||
}
|
||||
|
||||
case WidgetConfigurationType.VIEW:
|
||||
case WidgetConfigurationType.FIELD:
|
||||
case WidgetConfigurationType.TIMELINE:
|
||||
case WidgetConfigurationType.TASKS:
|
||||
case WidgetConfigurationType.NOTES:
|
||||
|
||||
+13
-1
@@ -1,8 +1,10 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsIn, IsNotEmpty } from 'class-validator';
|
||||
import { IsEnum, IsIn, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
import { type FieldConfiguration } from 'twenty-shared/types';
|
||||
|
||||
import { FieldDisplayMode } from 'src/engine/metadata-modules/page-layout-widget/enums/field-display-mode.enum';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
|
||||
@ObjectType('FieldConfiguration')
|
||||
@@ -11,4 +13,14 @@ export class FieldConfigurationDTO implements FieldConfiguration {
|
||||
@IsIn([WidgetConfigurationType.FIELD])
|
||||
@IsNotEmpty()
|
||||
configurationType: WidgetConfigurationType.FIELD;
|
||||
|
||||
@Field(() => String)
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
fieldMetadataId: string;
|
||||
|
||||
@Field(() => FieldDisplayMode)
|
||||
@IsEnum(FieldDisplayMode)
|
||||
@IsNotEmpty()
|
||||
fieldDisplayMode: FieldDisplayMode;
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { registerEnumType } from '@nestjs/graphql';
|
||||
|
||||
export enum FieldDisplayMode {
|
||||
CARD = 'CARD',
|
||||
FIELD = 'FIELD',
|
||||
VIEW = 'VIEW',
|
||||
}
|
||||
|
||||
registerEnumType(FieldDisplayMode, {
|
||||
name: 'FieldDisplayMode',
|
||||
description: 'Display mode for field configuration widgets',
|
||||
});
|
||||
Reference in New Issue
Block a user