breaking (soft) - Migrate viewGroup.fieldMetadataId -> view.mainGroupByFieldMetadataId (2/3) (#16277)
Should be merged once https://github.com/twentyhq/twenty/pull/16206 has been released + command run to prod In this PR - Remove usage of viewGroup.fieldMetadataId, both in BE and FE states. - But we still need to properly populate it until we fully remove viewGroup.fieldMetadataId from db and ORM entity (upcoming 3rd PR out of 3). fieldMetadataId was removed from CoreViewGroup type and CreateViewGroupInput and is determined BE-side based on the associated view's mainGroupByFieldMetadataId. **I expect this means a downtime on viewGroup creation, until both FE and BE are deployed and cache is flushed.** This seems acceptable to me as it only regards viewGroup creation. - this information is replaced by view.mainGroupByFieldMetadataID - Handle view group creation, update and deletion in the BE as a side-effect of a view creation, update or deletion. Optimistic effects are still used - Add validation at view creation or update regarding mainGroupByFieldMetadata Left to do in 3rd PR - Remove viewGroup.fieldMetadataId from db and ORM entity - Restore feature allowing to update an existing grouped view's group by field (already OK on BE side but need to rebuild FE optimistic)
This commit is contained in:
-1
@@ -99,7 +99,6 @@ export const createStandardFieldFlatMetadata = <
|
||||
morphId: null,
|
||||
viewFieldIds: [],
|
||||
viewFilterIds: [],
|
||||
viewGroupIds: [],
|
||||
kanbanAggregateOperationViewIds: [],
|
||||
calendarViewIds: [],
|
||||
mainGroupByFieldMetadataViewIds: [],
|
||||
|
||||
-1
@@ -108,7 +108,6 @@ export const createStandardRelationFieldFlatMetadata = <
|
||||
morphId: null,
|
||||
viewFieldIds: [],
|
||||
viewFilterIds: [],
|
||||
viewGroupIds: [],
|
||||
kanbanAggregateOperationViewIds: [],
|
||||
calendarViewIds: [],
|
||||
mainGroupByFieldMetadataViewIds: [],
|
||||
|
||||
-4
@@ -36,7 +36,6 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a crea
|
||||
"updatedAt": 2024-01-01T00:00:00.000Z,
|
||||
"viewFieldIds": [],
|
||||
"viewFilterIds": [],
|
||||
"viewGroupIds": [],
|
||||
"workspaceId": "workspace-id-1",
|
||||
},
|
||||
},
|
||||
@@ -101,7 +100,6 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a dele
|
||||
"updatedAt": 2024-01-01T00:00:00.000Z,
|
||||
"viewFieldIds": [],
|
||||
"viewFilterIds": [],
|
||||
"viewGroupIds": [],
|
||||
"workspaceId": "workspace-id-1",
|
||||
},
|
||||
},
|
||||
@@ -184,7 +182,6 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
|
||||
"updatedAt": 2024-01-01T00:00:00.000Z,
|
||||
"viewFieldIds": [],
|
||||
"viewFilterIds": [],
|
||||
"viewGroupIds": [],
|
||||
"workspaceId": "workspace-id-1",
|
||||
},
|
||||
},
|
||||
@@ -231,7 +228,6 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
|
||||
"updatedAt": 2024-01-01T00:00:00.000Z,
|
||||
"viewFieldIds": [],
|
||||
"viewFilterIds": [],
|
||||
"viewGroupIds": [],
|
||||
"workspaceId": "workspace-id-1",
|
||||
},
|
||||
},
|
||||
|
||||
+16
-30
@@ -20,7 +20,6 @@ export class FlatViewGroupValidatorService {
|
||||
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
|
||||
flatViewGroupMaps: optimisticFlatViewGroupMaps,
|
||||
flatViewMaps,
|
||||
flatFieldMetadataMaps,
|
||||
},
|
||||
}: FlatEntityUpdateValidationArgs<
|
||||
typeof ALL_METADATA_NAME.viewGroup
|
||||
@@ -53,10 +52,17 @@ export class FlatViewGroupValidatorService {
|
||||
}),
|
||||
};
|
||||
|
||||
if (!isDefined(updatedFlatViewGroup.fieldValue)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Field value is required`,
|
||||
userFriendlyMessage: msg`Field value is required`,
|
||||
});
|
||||
}
|
||||
|
||||
validationResult.flatEntityMinimalInformation = {
|
||||
id: updatedFlatViewGroup.id,
|
||||
viewId: updatedFlatViewGroup.viewId,
|
||||
fieldMetadataId: updatedFlatViewGroup.fieldMetadataId,
|
||||
};
|
||||
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
@@ -72,19 +78,6 @@ export class FlatViewGroupValidatorService {
|
||||
});
|
||||
}
|
||||
|
||||
const flatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: updatedFlatViewGroup.fieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatFieldMetadata)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View group to update parent field not found`,
|
||||
userFriendlyMessage: msg`View group to update parent field not found`,
|
||||
});
|
||||
}
|
||||
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
@@ -122,7 +115,6 @@ export class FlatViewGroupValidatorService {
|
||||
flatEntityToValidate: flatViewGroupToValidate,
|
||||
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
|
||||
flatViewGroupMaps: optimisticFlatViewGroupMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewMaps,
|
||||
},
|
||||
}: FlatEntityValidationArgs<
|
||||
@@ -134,7 +126,6 @@ export class FlatViewGroupValidatorService {
|
||||
flatEntityMinimalInformation: {
|
||||
id: flatViewGroupToValidate.id,
|
||||
viewId: flatViewGroupToValidate.viewId,
|
||||
fieldMetadataId: flatViewGroupToValidate.fieldMetadataId,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -151,19 +142,6 @@ export class FlatViewGroupValidatorService {
|
||||
});
|
||||
}
|
||||
|
||||
const flatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: flatViewGroupToValidate.fieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatFieldMetadata)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Field metadata not found`,
|
||||
userFriendlyMessage: msg`Field metadata not found`,
|
||||
});
|
||||
}
|
||||
|
||||
const flatView = flatViewMaps.byId[flatViewGroupToValidate.viewId];
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
@@ -176,6 +154,14 @@ export class FlatViewGroupValidatorService {
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
if (!isDefined(flatViewGroupToValidate.fieldValue)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Field value is required`,
|
||||
userFriendlyMessage: msg`Field value is required`,
|
||||
});
|
||||
}
|
||||
|
||||
return validationResult;
|
||||
}
|
||||
}
|
||||
|
||||
+111
@@ -1,14 +1,17 @@
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import { type ALL_METADATA_NAME } from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { ViewType } from 'src/engine/metadata-modules/view/enums/view-type.enum';
|
||||
import { ViewExceptionCode } from 'src/engine/metadata-modules/view/exceptions/view.exception';
|
||||
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration-v2/utils/find-flat-entity-property-update.util';
|
||||
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/types/failed-flat-entity-validation.type';
|
||||
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/flat-entity-update-validation-args.type';
|
||||
import { type FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/flat-entity-validation-args.type';
|
||||
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
|
||||
|
||||
export class FlatViewValidatorService {
|
||||
constructor() {}
|
||||
@@ -39,8 +42,19 @@ export class FlatViewValidatorService {
|
||||
message: t`View not found`,
|
||||
userFriendlyMessage: msg`View not found`,
|
||||
});
|
||||
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
const partialUpdates = fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
|
||||
updates: flatEntityUpdates,
|
||||
});
|
||||
|
||||
const updatedFlatView: FlatView = {
|
||||
...existingFlatView,
|
||||
...partialUpdates,
|
||||
};
|
||||
|
||||
const kanbanAggregateOperationFieldMetadataIdUpdate =
|
||||
findFlatEntityPropertyUpdate({
|
||||
property: 'kanbanAggregateOperationFieldMetadataId',
|
||||
@@ -64,6 +78,70 @@ export class FlatViewValidatorService {
|
||||
});
|
||||
}
|
||||
|
||||
const viewBecomesKanban =
|
||||
updatedFlatView.type === ViewType.KANBAN &&
|
||||
existingFlatView.type !== ViewType.KANBAN;
|
||||
|
||||
if (viewBecomesKanban) {
|
||||
if (!isDefined(updatedFlatView.mainGroupByFieldMetadataId)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban view must have a main group by field`,
|
||||
userFriendlyMessage: msg`Kanban view must have a main group by field`,
|
||||
});
|
||||
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
const mainGroupByFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: updatedFlatView.mainGroupByFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(mainGroupByFieldMetadata)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban main group by field metadata not found`,
|
||||
userFriendlyMessage: msg`Kanban main group by field metadata not found`,
|
||||
});
|
||||
} else if (mainGroupByFieldMetadata.type !== FieldMetadataType.SELECT) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban main group by field must be a SELECT field`,
|
||||
userFriendlyMessage: msg`Kanban main group by field must be a select field`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const updatedMainGroupByFieldMetadataId =
|
||||
updatedFlatView.mainGroupByFieldMetadataId;
|
||||
|
||||
const mainGroupByFieldMetadataIsAddedOrUpdated =
|
||||
isDefined(updatedMainGroupByFieldMetadataId) &&
|
||||
existingFlatView.mainGroupByFieldMetadataId !==
|
||||
updatedMainGroupByFieldMetadataId;
|
||||
|
||||
if (mainGroupByFieldMetadataIsAddedOrUpdated && !viewBecomesKanban) {
|
||||
const mainGroupByFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: updatedMainGroupByFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(mainGroupByFieldMetadata)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban main group by field metadata not found`,
|
||||
userFriendlyMessage: msg`Kanban main group by field metadata not found`,
|
||||
});
|
||||
} else if (mainGroupByFieldMetadata.type !== FieldMetadataType.SELECT) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban main group by field must be a SELECT field`,
|
||||
userFriendlyMessage: msg`Kanban main group by field must be a select field`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
@@ -150,6 +228,39 @@ export class FlatViewValidatorService {
|
||||
});
|
||||
}
|
||||
|
||||
const isKanban = flatViewToValidate.type === ViewType.KANBAN;
|
||||
|
||||
if (isKanban) {
|
||||
if (!isDefined(flatViewToValidate.mainGroupByFieldMetadataId)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban view must have a main group by field`,
|
||||
userFriendlyMessage: msg`Kanban view must have a main group by field`,
|
||||
});
|
||||
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
const mainGroupByFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: flatViewToValidate.mainGroupByFieldMetadataId,
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(mainGroupByFieldMetadata)) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban main group by field metadata not found`,
|
||||
userFriendlyMessage: msg`Kanban main group by field metadata not found`,
|
||||
});
|
||||
} else if (mainGroupByFieldMetadata.type !== FieldMetadataType.SELECT) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Kanban main group by field must be a SELECT field`,
|
||||
userFriendlyMessage: msg`Kanban main group by field must be a select field`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return validationResult;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user