[BREAKING_CHANGE_VIEW_SORT] Refactor view sort to v2 (#17609)

Fixes https://github.com/twentyhq/core-team-issues/issues/2187

---------

Co-authored-by: prastoin <paul@twenty.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
BOHEUS
2026-03-04 12:48:58 +00:00
committed by GitHub
parent 906a0aed38
commit c97d872b9f
135 changed files with 3262 additions and 815 deletions
@@ -166,6 +166,7 @@ export const enrichCreateWorkspaceMigrationActionsWithIds = ({
case 'commandMenuItem':
case 'navigationMenuItem':
case 'frontComponent':
case 'viewSort':
case 'webhook': {
if (!isDefined(idByUniversalIdentifier)) {
return action;
@@ -36,6 +36,7 @@ import { WorkspaceMigrationViewFilterActionsBuilderService } from 'src/engine/wo
import { WorkspaceMigrationViewGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-group/workspace-migration-view-group-actions-builder.service';
import { WorkspaceMigrationViewActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view/workspace-migration-view-actions-builder.service';
import { WorkspaceMigrationWebhookActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/webhook/workspace-migration-webhook-actions-builder.service';
import { WorkspaceMigrationViewSortActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-sort/workspace-migration-view-sort-actions.builder.service';
@Injectable()
export class WorkspaceMigrationBuildOrchestratorService {
@@ -48,6 +49,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
private readonly workspaceMigrationViewFilterGroupActionsBuilderService: WorkspaceMigrationViewFilterGroupActionsBuilderService,
private readonly workspaceMigrationViewGroupActionsBuilderService: WorkspaceMigrationViewGroupActionsBuilderService,
private readonly workspaceMigrationViewFieldGroupActionsBuilderService: WorkspaceMigrationViewFieldGroupActionsBuilderService,
private readonly workspaceMigrationViewSortActionsBuilderService: WorkspaceMigrationViewSortActionsBuilderService,
private readonly workspaceMigrationLogicFunctionActionsBuilderService: WorkspaceMigrationLogicFunctionActionsBuilderService,
private readonly workspaceMigrationRoleTargetActionsBuilderService: WorkspaceMigrationRoleTargetActionsBuilderService,
private readonly workspaceMigrationFieldActionsBuilderService: WorkspaceMigrationFieldActionsBuilderService,
@@ -134,6 +136,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatViewFilterGroupMaps,
flatViewGroupMaps,
flatViewFieldGroupMaps,
flatViewSortMaps,
flatRowLevelPermissionPredicateMaps,
flatRowLevelPermissionPredicateGroupMaps,
flatRoleMaps,
@@ -355,6 +358,28 @@ export class WorkspaceMigrationBuildOrchestratorService {
}
}
if (isDefined(flatViewSortMaps)) {
const { from: fromFlatViewSortMaps, to: toFlatViewSortMaps } =
flatViewSortMaps;
const viewSortResult =
await this.workspaceMigrationViewSortActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatViewSortMaps,
to: toFlatViewSortMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
if (viewSortResult.status === 'fail') {
orchestratorFailureReport.viewSort.push(...viewSortResult.errors);
} else {
orchestratorActionsReport.viewSort = viewSortResult.actions;
}
}
if (isDefined(flatRowLevelPermissionPredicateGroupMaps)) {
const {
from: fromFlatRowLevelPermissionPredicateGroupMaps,
@@ -763,6 +788,9 @@ export class WorkspaceMigrationBuildOrchestratorService {
...aggregatedOrchestratorActionsReport.viewGroup.delete,
...aggregatedOrchestratorActionsReport.viewGroup.create,
...aggregatedOrchestratorActionsReport.viewGroup.update,
...aggregatedOrchestratorActionsReport.viewSort.create,
...aggregatedOrchestratorActionsReport.viewSort.update,
...aggregatedOrchestratorActionsReport.viewSort.delete,
///
// Logic functions
@@ -5,6 +5,7 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_FOREIGN_KEY_AGGREGATOR_PROPERTIES should matc
"agent": [],
"commandMenuItem": [],
"fieldMetadata": [
"viewSortUniversalIdentifiers",
"viewFieldUniversalIdentifiers",
"viewFilterUniversalIdentifiers",
"kanbanAggregateOperationViewUniversalIdentifiers",
@@ -56,6 +57,7 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_FOREIGN_KEY_AGGREGATOR_PROPERTIES should matc
"viewFilterUniversalIdentifiers",
],
"viewGroup": [],
"viewSort": [],
"webhook": [],
}
`;
@@ -18,6 +18,7 @@ export const ALL_JSONB_PROPERTIES_WITH_SERIALIZED_RELATION_BY_METADATA_NAME = {
viewFieldGroup: {},
viewFilter: {},
viewFilterGroup: {},
viewSort: {},
index: {},
role: {},
roleTarget: {},
@@ -0,0 +1,7 @@
import { type ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
import { type UniversalFlatEntityFrom } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
export type UniversalFlatViewSort = UniversalFlatEntityFrom<
ViewSortEntity,
'viewSort'
>;
@@ -1,8 +1,4 @@
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
import { type UniversalFlatEntityFrom } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
// TODO remove once viewSorts has been migrated to v2
export type UniversalFlatView = UniversalFlatEntityFrom<
Omit<ViewEntity, 'viewSorts'>,
'view'
>;
export type UniversalFlatView = UniversalFlatEntityFrom<ViewEntity, 'view'>;
@@ -45,6 +45,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a crea
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"viewSortIds": [],
"viewSortUniversalIdentifiers": [],
"workspaceId": "workspace-id-1",
},
},
@@ -106,6 +108,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a dele
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"viewSortIds": [],
"viewSortUniversalIdentifiers": [],
"workspaceId": "workspace-id-1",
},
},
@@ -181,6 +185,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"viewSortIds": [],
"viewSortUniversalIdentifiers": [],
"workspaceId": "workspace-id-1",
},
},
@@ -228,6 +234,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"viewSortIds": [],
"viewSortUniversalIdentifiers": [],
"workspaceId": "workspace-id-1",
},
},
@@ -0,0 +1,24 @@
import { type BaseFlatCreateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-create-workspace-migration-action.type';
import { type BaseFlatUpdateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-update-workspace-migration-action.type';
import { type BaseFlatDeleteWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-delete-workspace-migration-action.type';
import { type BaseUniversalCreateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-universal-create-workspace-migration-action.type';
import { type BaseUniversalUpdateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-universal-update-workspace-migration-action.type';
import { type BaseUniversalDeleteWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-universal-delete-workspace-migration-action.type';
export type FlatCreateViewSortAction =
BaseFlatCreateWorkspaceMigrationAction<'viewSort'>;
export type FlatUpdateViewSortAction =
BaseFlatUpdateWorkspaceMigrationAction<'viewSort'>;
export type FlatDeleteViewSortAction =
BaseFlatDeleteWorkspaceMigrationAction<'viewSort'>;
export type UniversalCreateViewSortAction =
BaseUniversalCreateWorkspaceMigrationAction<'viewSort'>;
export type UniversalUpdateViewSortAction =
BaseUniversalUpdateWorkspaceMigrationAction<'viewSort'>;
export type UniversalDeleteViewSortAction =
BaseUniversalDeleteWorkspaceMigrationAction<'viewSort'>;
@@ -0,0 +1,108 @@
import { Injectable } from '@nestjs/common';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { WorkspaceEntityMigrationBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/services/workspace-entity-migration-builder.service';
import { UniversalUpdateViewSortAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-sort/types/workspace-migration-view-sort-action.type';
import { FlatViewSortValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-view-sort-validator.service';
import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type';
import { UniversalFlatEntityValidationReturnType } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-result.type';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type';
@Injectable()
export class WorkspaceMigrationViewSortActionsBuilderService extends WorkspaceEntityMigrationBuilderService<
typeof ALL_METADATA_NAME.viewSort
> {
constructor(
private readonly flatViewSortValidatorService: FlatViewSortValidatorService,
) {
super(ALL_METADATA_NAME.viewSort);
}
protected validateFlatEntityCreation(
args: UniversalFlatEntityValidationArgs<typeof ALL_METADATA_NAME.viewSort>,
): UniversalFlatEntityValidationReturnType<
typeof ALL_METADATA_NAME.viewSort,
'create'
> {
const validationResult =
this.flatViewSortValidatorService.validateFlatViewSortCreation(args);
if (validationResult.errors.length > 0) {
return {
status: 'fail',
...validationResult,
};
}
const { flatEntityToValidate: flatViewSortToValidate } = args;
return {
status: 'success',
action: {
type: 'create',
metadataName: 'viewSort',
flatEntity: flatViewSortToValidate,
},
};
}
protected validateFlatEntityDeletion(
args: UniversalFlatEntityValidationArgs<typeof ALL_METADATA_NAME.viewSort>,
): UniversalFlatEntityValidationReturnType<
typeof ALL_METADATA_NAME.viewSort,
'delete'
> {
const validationResult =
this.flatViewSortValidatorService.validateFlatViewSortDeletion(args);
if (validationResult.errors.length > 0) {
return {
status: 'fail',
...validationResult,
};
}
const { flatEntityToValidate: flatViewSortToValidate } = args;
return {
status: 'success',
action: {
type: 'delete',
metadataName: 'viewSort',
universalIdentifier: flatViewSortToValidate.universalIdentifier,
},
};
}
protected validateFlatEntityUpdate(
args: FlatEntityUpdateValidationArgs<typeof ALL_METADATA_NAME.viewSort>,
): UniversalFlatEntityValidationReturnType<
typeof ALL_METADATA_NAME.viewSort,
'update'
> {
const validationResult =
this.flatViewSortValidatorService.validateFlatViewSortUpdate(args);
if (validationResult.errors.length > 0) {
return {
status: 'fail',
...validationResult,
};
}
const { universalIdentifier, flatEntityUpdate } = args;
const updateViewSortAction: UniversalUpdateViewSortAction = {
type: 'update',
metadataName: 'viewSort',
universalIdentifier,
update: flatEntityUpdate,
};
return {
status: 'success',
action: updateViewSortAction,
};
}
}
@@ -0,0 +1,229 @@
import { Injectable } from '@nestjs/common';
import { msg, t } from '@lingui/core/macro';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { ViewSortExceptionCode } from 'src/engine/metadata-modules/view-sort/exceptions/view-sort.exception';
import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type';
import { ViewSortDirection } from 'src/engine/metadata-modules/view-sort/enums/view-sort-direction';
import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type';
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';
@Injectable()
export class FlatViewSortValidatorService {
constructor() {}
validateFlatViewSortCreation({
flatEntityToValidate: flatViewSortToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewSortMaps: optimisticFlatViewSortMaps,
flatViewMaps,
flatFieldMetadataMaps,
},
}: UniversalFlatEntityValidationArgs<
typeof ALL_METADATA_NAME.viewSort
>): FailedFlatEntityValidation<'viewSort', 'create'> {
const validationResult = getEmptyFlatEntityValidationError({
flatEntityMinimalInformation: {
universalIdentifier: flatViewSortToValidate.universalIdentifier,
viewUniversalIdentifier: flatViewSortToValidate.viewUniversalIdentifier,
},
metadataName: 'viewSort',
type: 'create',
});
const existingFlatViewSort = findFlatEntityByUniversalIdentifier({
universalIdentifier: flatViewSortToValidate.universalIdentifier,
flatEntityMaps: optimisticFlatViewSortMaps,
});
if (isDefined(existingFlatViewSort)) {
const flatViewSortId = flatViewSortToValidate.universalIdentifier;
validationResult.errors.push({
code: ViewSortExceptionCode.INVALID_VIEW_SORT_DATA,
message: t`View sort with id ${flatViewSortId} already exists`,
userFriendlyMessage: msg`View sort already exists`,
});
}
const flatFieldMetadata = findFlatEntityByUniversalIdentifier({
universalIdentifier:
flatViewSortToValidate.fieldMetadataUniversalIdentifier,
flatEntityMaps: flatFieldMetadataMaps,
});
if (!isDefined(flatFieldMetadata)) {
validationResult.errors.push({
code: ViewSortExceptionCode.INVALID_VIEW_SORT_DATA,
message: t`Field metadata not found`,
userFriendlyMessage: msg`Field metadata not found`,
});
}
const flatView = findFlatEntityByUniversalIdentifier({
universalIdentifier: flatViewSortToValidate.viewUniversalIdentifier,
flatEntityMaps: flatViewMaps,
});
if (!isDefined(flatView)) {
validationResult.errors.push({
code: ViewSortExceptionCode.VIEW_NOT_FOUND,
message: t`View not found`,
userFriendlyMessage: msg`View not found`,
});
return validationResult;
}
const otherFlatViewSorts =
findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow({
universalIdentifiers: flatView.viewSortUniversalIdentifiers,
flatEntityMaps: optimisticFlatViewSortMaps,
});
const equivalentExistingFlatViewSortExists = otherFlatViewSorts.some(
(flatViewSort) =>
flatViewSort.universalIdentifier ===
flatViewSortToValidate.universalIdentifier &&
flatViewSort.fieldMetadataUniversalIdentifier ===
flatViewSortToValidate.fieldMetadataUniversalIdentifier,
);
if (equivalentExistingFlatViewSortExists) {
validationResult.errors.push({
code: ViewSortExceptionCode.INVALID_VIEW_SORT_DATA,
message: t`View sort with same fieldMetadataId and viewId already exists`,
userFriendlyMessage: msg`View sort already exists`,
});
}
if (
!isDefined(flatViewSortToValidate.direction) ||
!Object.values(ViewSortDirection).includes(
flatViewSortToValidate.direction,
)
) {
validationResult.errors.push({
code: ViewSortExceptionCode.INVALID_VIEW_SORT_DATA,
message: t`View sort with invalid direction`,
userFriendlyMessage: msg`View sort with invalid direction, should be ASC or DESC`,
});
}
return validationResult;
}
public validateFlatViewSortUpdate({
universalIdentifier,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewSortMaps: optimisticFlatViewSortMaps,
flatViewMaps,
},
}: FlatEntityUpdateValidationArgs<
typeof ALL_METADATA_NAME.viewSort
>): FailedFlatEntityValidation<'viewSort', 'update'> {
const existingFlatViewSort = findFlatEntityByUniversalIdentifier({
universalIdentifier,
flatEntityMaps: optimisticFlatViewSortMaps,
});
const validationResult = getEmptyFlatEntityValidationError({
flatEntityMinimalInformation: {
universalIdentifier,
},
metadataName: 'viewSort',
type: 'update',
});
if (!isDefined(existingFlatViewSort)) {
validationResult.errors.push({
code: ViewSortExceptionCode.VIEW_SORT_NOT_FOUND,
message: t`View sort to update not found`,
userFriendlyMessage: msg`View sort to update not found`,
});
return validationResult;
}
const updatedFlatViewSort = {
...existingFlatViewSort,
...flatEntityUpdate,
};
if (
!isDefined(updatedFlatViewSort?.direction) ||
!(
updatedFlatViewSort.direction === ViewSortDirection.DESC ||
updatedFlatViewSort.direction === ViewSortDirection.ASC
)
) {
validationResult.errors.push({
code: ViewSortExceptionCode.INVALID_VIEW_SORT_DATA,
message: t`Correct direction is required`,
userFriendlyMessage: msg`Correct direction is required`,
});
}
validationResult.flatEntityMinimalInformation = {
...validationResult.flatEntityMinimalInformation,
viewUniversalIdentifier: updatedFlatViewSort.viewUniversalIdentifier,
};
const flatView = findFlatEntityByUniversalIdentifier({
universalIdentifier: updatedFlatViewSort.viewUniversalIdentifier,
flatEntityMaps: flatViewMaps,
});
if (!isDefined(flatView)) {
validationResult.errors.push({
code: ViewSortExceptionCode.VIEW_NOT_FOUND,
message: t`View sort to update parent view not found`,
userFriendlyMessage: msg`View sort to update parent view not found`,
});
return validationResult;
}
return validationResult;
}
public validateFlatViewSortDeletion({
flatEntityToValidate: { universalIdentifier },
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewSortMaps: optimisticFlatViewSortMaps,
},
}: UniversalFlatEntityValidationArgs<
typeof ALL_METADATA_NAME.viewSort
>): FailedFlatEntityValidation<'viewSort', 'delete'> {
const validationResult = getEmptyFlatEntityValidationError({
flatEntityMinimalInformation: {
universalIdentifier,
},
metadataName: 'viewSort',
type: 'delete',
});
const existingFlatViewSort = findFlatEntityByUniversalIdentifier({
universalIdentifier,
flatEntityMaps: optimisticFlatViewSortMaps,
});
if (!isDefined(existingFlatViewSort)) {
validationResult.errors.push({
code: ViewSortExceptionCode.VIEW_SORT_NOT_FOUND,
message: t`View sort to delete not found`,
userFriendlyMessage: msg`View sort to delete not found`,
});
return validationResult;
}
return validationResult;
}
}
@@ -26,6 +26,7 @@ import { FlatViewFilterValidatorService } from 'src/engine/workspace-manager/wor
import { FlatViewGroupValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-view-group-validator.service';
import { FlatViewValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-view-validator.service';
import { FlatWebhookValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-webhook-validator.service';
import { FlatViewSortValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-view-sort-validator.service';
@Module({
imports: [FeatureFlagModule],
@@ -36,6 +37,7 @@ import { FlatWebhookValidatorService } from 'src/engine/workspace-manager/worksp
FlatViewFilterGroupValidatorService,
FlatViewGroupValidatorService,
FlatViewFieldGroupValidatorService,
FlatViewSortValidatorService,
FlatIndexValidatorService,
FlatFieldMetadataValidatorService,
FlatObjectMetadataValidatorService,
@@ -63,6 +65,7 @@ import { FlatWebhookValidatorService } from 'src/engine/workspace-manager/worksp
FlatViewFilterGroupValidatorService,
FlatViewGroupValidatorService,
FlatViewFieldGroupValidatorService,
FlatViewSortValidatorService,
FlatIndexValidatorService,
FlatFieldMetadataValidatorService,
FlatObjectMetadataValidatorService,
@@ -26,6 +26,7 @@ import { WorkspaceMigrationViewFilterActionsBuilderService } from 'src/engine/wo
import { WorkspaceMigrationViewGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-group/workspace-migration-view-group-actions-builder.service';
import { WorkspaceMigrationViewActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view/workspace-migration-view-actions-builder.service';
import { WorkspaceMigrationBuilderValidatorsModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/workspace-migration-builder-validators.module';
import { WorkspaceMigrationViewSortActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-sort/workspace-migration-view-sort-actions.builder.service';
@Module({
imports: [FeatureFlagModule, WorkspaceMigrationBuilderValidatorsModule],
@@ -38,6 +39,7 @@ import { WorkspaceMigrationBuilderValidatorsModule } from 'src/engine/workspace-
WorkspaceMigrationViewFilterGroupActionsBuilderService,
WorkspaceMigrationViewGroupActionsBuilderService,
WorkspaceMigrationViewFieldGroupActionsBuilderService,
WorkspaceMigrationViewSortActionsBuilderService,
WorkspaceMigrationIndexActionsBuilderService,
WorkspaceMigrationLogicFunctionActionsBuilderService,
WorkspaceMigrationFieldActionsBuilderService,
@@ -64,6 +66,7 @@ import { WorkspaceMigrationBuilderValidatorsModule } from 'src/engine/workspace-
WorkspaceMigrationViewFilterGroupActionsBuilderService,
WorkspaceMigrationViewGroupActionsBuilderService,
WorkspaceMigrationViewFieldGroupActionsBuilderService,
WorkspaceMigrationViewSortActionsBuilderService,
WorkspaceMigrationFieldActionsBuilderService,
WorkspaceMigrationLogicFunctionActionsBuilderService,
WorkspaceMigrationRoleActionsBuilderService,
@@ -133,6 +133,7 @@ export const fromUniversalFlatFieldMetadataToFlatFieldMetadata = ({
calendarViewIds: [],
mainGroupByFieldMetadataViewIds: [],
kanbanAggregateOperationViewIds: [],
viewSortIds: [],
...emptyUniversalForeignKeyAggregators,
};
};
@@ -0,0 +1,65 @@
import { Injectable } from '@nestjs/common';
import { v4 } from 'uuid';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
FlatCreateViewSortAction,
UniversalCreateViewSortAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-sort/types/workspace-migration-view-sort-action.type';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { resolveUniversalRelationIdentifiersToIds } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-universal-relation-identifiers-to-ids.util';
@Injectable()
export class CreateViewSortActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'create',
'viewSort',
) {
override async transpileUniversalActionToFlatAction({
action,
allFlatEntityMaps,
flatApplication,
workspaceId,
}: WorkspaceMigrationActionRunnerArgs<UniversalCreateViewSortAction>): Promise<FlatCreateViewSortAction> {
const { fieldMetadataId, viewId } =
resolveUniversalRelationIdentifiersToIds({
flatEntityMaps: allFlatEntityMaps,
metadataName: action.metadataName,
universalForeignKeyValues: action.flatEntity,
});
return {
...action,
flatEntity: {
...action.flatEntity,
fieldMetadataId,
viewId,
id: action.id ?? v4(),
applicationId: flatApplication.id,
workspaceId,
},
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatCreateViewSortAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { flatEntity } = flatAction;
await this.insertFlatEntitiesInRepository({
queryRunner,
flatEntities: [flatEntity],
});
}
async executeForWorkspaceSchema(
_context: WorkspaceMigrationActionRunnerContext<FlatCreateViewSortAction>,
): Promise<void> {
return;
}
}
@@ -0,0 +1,49 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
import {
FlatDeleteViewSortAction,
UniversalDeleteViewSortAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-sort/types/workspace-migration-view-sort-action.type';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
@Injectable()
export class DeleteViewSortActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'delete',
'viewSort',
) {
constructor() {
super();
}
override async transpileUniversalActionToFlatAction(
context: WorkspaceMigrationActionRunnerArgs<UniversalDeleteViewSortAction>,
): Promise<FlatDeleteViewSortAction> {
return this.transpileUniversalDeleteActionToFlatDeleteAction(context);
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatDeleteViewSortAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const viewSortRepository =
queryRunner.manager.getRepository<ViewSortEntity>(ViewSortEntity);
await viewSortRepository.delete({
id: flatAction.entityId,
workspaceId,
});
}
async executeForWorkspaceSchema(
_context: WorkspaceMigrationActionRunnerContext<FlatDeleteViewSortAction>,
): Promise<void> {
return;
}
}
@@ -0,0 +1,67 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity';
import {
FlatUpdateViewSortAction,
UniversalUpdateViewSortAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-sort/types/workspace-migration-view-sort-action.type';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { resolveUniversalUpdateRelationIdentifiersToIds } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-universal-update-relation-identifiers-to-ids.util';
@Injectable()
export class UpdateViewSortActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'update',
'viewSort',
) {
constructor() {
super();
}
override async transpileUniversalActionToFlatAction(
context: WorkspaceMigrationActionRunnerArgs<UniversalUpdateViewSortAction>,
): Promise<FlatUpdateViewSortAction> {
const { action, allFlatEntityMaps } = context;
const flatViewSort = findFlatEntityByUniversalIdentifierOrThrow({
flatEntityMaps: allFlatEntityMaps.flatViewSortMaps,
universalIdentifier: action.universalIdentifier,
});
const update = resolveUniversalUpdateRelationIdentifiersToIds({
metadataName: 'viewSort',
universalUpdate: action.update,
allFlatEntityMaps,
});
return {
type: 'update',
metadataName: 'viewSort',
entityId: flatViewSort.id,
update,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateViewSortAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const viewSortRepository =
queryRunner.manager.getRepository<ViewSortEntity>(ViewSortEntity);
await viewSortRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
_context: WorkspaceMigrationActionRunnerContext<FlatUpdateViewSortAction>,
): Promise<void> {
return;
}
}
@@ -62,6 +62,7 @@ export class CreateViewActionHandlerService extends WorkspaceMigrationRunnerActi
viewGroupIds: [],
viewFilterIds: [],
viewFilterGroupIds: [],
viewSortIds: [],
...emptyUniversalForeignKeyAggregators,
},
};
@@ -72,6 +72,9 @@ import { UpdateViewGroupActionHandlerService } from 'src/engine/workspace-manage
import { CreateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view/services/create-view-action-handler.service';
import { DeleteViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view/services/delete-view-action-handler.service';
import { UpdateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view/services/update-view-action-handler.service';
import { CreateViewSortActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view-sort/services/create-view-sort-action-handler.service';
import { UpdateViewSortActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view-sort/services/update-view-sort-action-handler.service';
import { DeleteViewSortActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view-sort/services/delete-view-sort-action-handler.service';
@Module({
imports: [
@@ -107,6 +110,10 @@ import { UpdateViewActionHandlerService } from 'src/engine/workspace-manager/wor
UpdateViewFilterGroupActionHandlerService,
DeleteViewFilterGroupActionHandlerService,
CreateViewSortActionHandlerService,
UpdateViewSortActionHandlerService,
DeleteViewSortActionHandlerService,
CreateViewGroupActionHandlerService,
UpdateViewGroupActionHandlerService,
DeleteViewGroupActionHandlerService,
@@ -23,6 +23,6 @@ export const METADATA_EVENTS_TO_EMIT = {
rowLevelPermissionPredicateGroup: true,
index: true,
logicFunction: true,
viewSort: true,
webhook: false,
} as const satisfies { [P in AllMetadataName]: boolean };
@@ -89,6 +89,7 @@ const deriveAllMetadataEventsFromCreateAction = (
case 'commandMenuItem':
case 'frontComponent':
case 'navigationMenuItem':
case 'viewSort':
case 'webhook': {
return [
{
@@ -53,6 +53,7 @@ const deriveAllMetadataEventsFromDeleteAction = ({
case 'commandMenuItem':
case 'frontComponent':
case 'navigationMenuItem':
case 'viewSort':
case 'webhook': {
const flatEntityToDelete = findFlatEntityByIdInFlatEntityMapsOrThrow<
MetadataFlatEntity<typeof flatAction.metadataName>
@@ -131,6 +131,7 @@ const deriveAllMetadataEventsFromUpdateAction = ({
case 'commandMenuItem':
case 'frontComponent':
case 'navigationMenuItem':
case 'viewSort':
case 'webhook': {
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(
flatAction.metadataName,
@@ -51,6 +51,7 @@ export const optimisticallyApplyCreateActionOnAllFlatEntityMaps = ({
case 'viewField':
case 'viewGroup':
case 'viewFieldGroup':
case 'viewSort':
case 'rowLevelPermissionPredicate':
case 'rowLevelPermissionPredicateGroup':
case 'viewFilterGroup':
@@ -23,6 +23,7 @@ export const optimisticallyApplyDeleteActionOnAllFlatEntityMaps = ({
case 'viewField':
case 'viewGroup':
case 'viewFieldGroup':
case 'viewSort':
case 'rowLevelPermissionPredicate':
case 'rowLevelPermissionPredicateGroup':
case 'viewFilterGroup':
@@ -45,6 +45,7 @@ export const optimisticallyApplyUpdateActionOnAllFlatEntityMaps = ({
case 'viewField':
case 'viewGroup':
case 'viewFieldGroup':
case 'viewSort':
case 'rowLevelPermissionPredicate':
case 'rowLevelPermissionPredicateGroup':
case 'viewFilterGroup':