Field deactivation side effect views calendar kanban viewFields (#15180)
# Introduction
Handling both:
- field deactivation side effect on view fields, view filters and views
- field deactivation side effect on view that targets it as
`kanbanAggregateFieldMetadataId`
- field deactivation side effect on view that targets it as
`calendarFieldMetadataId`
## Coverage
added coverage
```ts
PASS test/integration/metadata/suites/field-metadata/kanban-aggregate-field-deactivation-deletes-views.integration-spec.ts (13.132 s)
kanban-aggregate-field-deactivation-nullifies-kanban-properties
✓ should nullify kanban properties when field used as kanbanAggregateOperationFieldMetadataId is deactivated (3923 ms)
✓ should not modify views when field not used as kanbanAggregateOperationFieldMetadataId is deactivated (2958 ms)
✓ should nullify kanban properties on multiple views when they all use the same field as kanbanAggregateOperationFieldMetadataId (2542 ms)
✓ should nullify kanban properties when views have different aggregate operations on same field (3380 ms)
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 13.154 s
```
```ts
PASS test/integration/metadata/suites/field-metadata/view-group-field-deactivation-deletes-views.integration-spec.ts (12.639 s)
view-group-field-deactivation-deletes-views
✓ should delete view when field used in view group is deactivated (3469 ms)
✓ should not delete view when field not used in view group is deactivated (3109 ms)
✓ should delete multiple views when they all use the same field in view groups (2741 ms)
✓ should handle deactivation when view has multiple view groups with different fields (3008 ms)
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 12.664 s
```
```ts
PASS test/integration/metadata/suites/field-metadata/calendar-field-deactivation-deletes-views.integration-spec.ts (14.579 s)
calendar-field-deactivation-deletes-views
✓ should delete view when field used as calendarFieldMetadataId is deactivated (3388 ms)
✓ should not delete view when field not used as calendarFieldMetadataId is deactivated (2438 ms)
✓ should delete multiple views when they all use the same field as calendarFieldMetadataId (2635 ms)
✓ should handle deactivation when views have different calendar layouts on same field (3195 ms)
✓ should delete calendar view but not other view types when calendar field is deactivated (2682 ms)
Test Suites: 1 passed, 1 total
Tests: 5 passed, 5 total
Snapshots: 0 total
Time: 14.601 s, estimated 15 s
```
## View soft deletion
We decided to remove the soft deletion grain on all the views, in this
PR context we've only removed soft deleted validation requirement on any
view entities
## Conclusion
close https://github.com/twentyhq/core-team-issues/issues/1754
This commit is contained in:
+20
-30
@@ -3,64 +3,54 @@ import { type ExtractPropertiesThatEndsWithId } from 'twenty-shared/types';
|
||||
import { type AllMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-metadata-name.type';
|
||||
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
|
||||
|
||||
type PropertyNameToRelationName<T extends string> = T extends `${infer Name}Id`
|
||||
? Name
|
||||
: never;
|
||||
|
||||
type ExtractEntityRelations<TEntity extends MetadataEntity<AllMetadataName>> = {
|
||||
[K in ExtractPropertiesThatEndsWithId<
|
||||
TEntity,
|
||||
'id' | 'workspaceId'
|
||||
> as PropertyNameToRelationName<K>]: K;
|
||||
[K in ExtractPropertiesThatEndsWithId<TEntity, 'id' | 'workspaceId'>]: K;
|
||||
};
|
||||
|
||||
type MetadataRelatedMetadataNames<T extends AllMetadataName> = Extract<
|
||||
keyof ExtractEntityRelations<MetadataEntity<T>>,
|
||||
AllMetadataName
|
||||
>;
|
||||
type MetadataRelatedMetadataNames<T extends AllMetadataName> =
|
||||
keyof ExtractEntityRelations<MetadataEntity<T>>;
|
||||
|
||||
type MetadataNameAndRelations = {
|
||||
[T in AllMetadataName]: MetadataRelatedMetadataNames<T> extends never
|
||||
? Record<string, never>
|
||||
: Record<MetadataRelatedMetadataNames<T>, string> & {
|
||||
[K in Exclude<
|
||||
AllMetadataName,
|
||||
MetadataRelatedMetadataNames<T>
|
||||
>]?: string;
|
||||
: {
|
||||
[P in MetadataRelatedMetadataNames<T>]?: AllMetadataName;
|
||||
};
|
||||
};
|
||||
|
||||
export const ALL_METADATA_NAME_MANY_TO_ONE_RELATIONS = {
|
||||
export const ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY = {
|
||||
fieldMetadata: {
|
||||
objectMetadata: 'objectMetadataId',
|
||||
objectMetadataId: 'objectMetadata',
|
||||
},
|
||||
objectMetadata: {},
|
||||
view: {
|
||||
objectMetadata: 'objectMetadataId',
|
||||
kanbanAggregateOperationFieldMetadataId: 'fieldMetadata',
|
||||
calendarFieldMetadataId: 'fieldMetadata',
|
||||
objectMetadataId: 'objectMetadata',
|
||||
},
|
||||
viewField: {
|
||||
view: 'viewId',
|
||||
fieldMetadata: 'fieldMetadataId',
|
||||
viewId: 'view',
|
||||
fieldMetadataId: 'fieldMetadata',
|
||||
},
|
||||
viewGroup: {
|
||||
view: 'viewId',
|
||||
fieldMetadata: 'fieldMetadataId',
|
||||
viewId: 'view',
|
||||
fieldMetadataId: 'fieldMetadata',
|
||||
},
|
||||
index: {
|
||||
objectMetadata: 'objectMetadataId',
|
||||
objectMetadataId: 'objectMetadata',
|
||||
},
|
||||
serverlessFunction: {},
|
||||
cronTrigger: {
|
||||
serverlessFunction: 'serverlessFunctionId',
|
||||
serverlessFunctionId: 'serverlessFunction',
|
||||
},
|
||||
databaseEventTrigger: {
|
||||
serverlessFunction: 'serverlessFunctionId',
|
||||
serverlessFunctionId: 'serverlessFunction',
|
||||
},
|
||||
routeTrigger: {
|
||||
serverlessFunction: 'serverlessFunctionId',
|
||||
serverlessFunctionId: 'serverlessFunction',
|
||||
},
|
||||
viewFilter: {
|
||||
view: 'viewId',
|
||||
fieldMetadata: 'fieldMetadataId',
|
||||
viewId: 'view',
|
||||
fieldMetadataId: 'fieldMetadata',
|
||||
},
|
||||
} as const satisfies MetadataNameAndRelations;
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ export const ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION = {
|
||||
fieldMetadata: true,
|
||||
},
|
||||
view: {
|
||||
fieldMetadata: true,
|
||||
objectMetadata: true,
|
||||
},
|
||||
viewField: {
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { type ALL_METADATA_NAME_MANY_TO_ONE_RELATIONS } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-many-to-one-relations.constant';
|
||||
import { type ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-many-to-one-relations.constant';
|
||||
import { type AllMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-metadata-name.type';
|
||||
|
||||
export type MetadataManyToOneRelatedMetadataNames<T extends AllMetadataName> =
|
||||
Extract<
|
||||
keyof (typeof ALL_METADATA_NAME_MANY_TO_ONE_RELATIONS)[T],
|
||||
(typeof ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY)[T][keyof (typeof ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY)[T]],
|
||||
AllMetadataName
|
||||
>;
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
import { ALL_METADATA_NAME_MANY_TO_ONE_RELATIONS } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-many-to-one-relations.constant';
|
||||
import { ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-many-to-one-relations.constant';
|
||||
import {
|
||||
FlatEntityMapsException,
|
||||
FlatEntityMapsExceptionCode,
|
||||
@@ -32,8 +32,9 @@ export const addFlatEntityToFlatEntityAndRelatedEntityMapsOrThrow = <
|
||||
flatEntityMaps: initialFlatEntityAndRelatedMaps[flatEntityMapsKey],
|
||||
});
|
||||
|
||||
// TODO refactor
|
||||
const manyToOneRelatedMetadataName = Object.entries(
|
||||
ALL_METADATA_NAME_MANY_TO_ONE_RELATIONS[metadataName],
|
||||
ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY[metadataName],
|
||||
);
|
||||
|
||||
return manyToOneRelatedMetadataName.reduce(
|
||||
|
||||
Reference in New Issue
Block a user