Move view in metadata-modules/ and create atomic folder + module for each view entity (#14990)

# Introduction
Preparing view-filter and view-group introduction in v2 core engine
Moving view from `core-modules` to `metadata-modules`

## What happened

### Created dedicated modules for each view entity:
- ViewFieldModule
- ViewFilterModule
- ViewFilterGroupModule
- ViewGroupModule
- ViewSortModule

### Each module is now completely independent with its own:
- Controller
- Resolver
- Service
- Entity

### Created dedicated abstraction metadata module folder for:
- flat-view-field
- flat-view

### Dependencies 
- Eleminated circular dep on ViewModule to all others ones
- Granular import not importing the whole viewModule anymore everywhere


close https://github.com/twentyhq/core-team-issues/issues/1703
This commit is contained in:
Paul Rastoin
2025-10-09 15:18:15 +02:00
committed by GitHub
parent c9a1a110e1
commit 59fbe35a8c
198 changed files with 877 additions and 765 deletions
@@ -0,0 +1,124 @@
import { assertUnreachable } from 'twenty-shared/utils';
import {
NotFoundError,
UserInputError,
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
import {
ViewFieldException,
ViewFieldExceptionCode,
} from 'src/engine/metadata-modules/view-field/exceptions/view-field.exception';
import {
ViewFilterGroupException,
ViewFilterGroupExceptionCode,
} from 'src/engine/metadata-modules/view-filter-group/exceptions/view-filter-group.exception';
import {
ViewFilterException,
ViewFilterExceptionCode,
} from 'src/engine/metadata-modules/view-filter/exceptions/view-filter.exception';
import {
ViewGroupException,
ViewGroupExceptionCode,
} from 'src/engine/metadata-modules/view-group/exceptions/view-group.exception';
import {
ViewSortException,
ViewSortExceptionCode,
} from 'src/engine/metadata-modules/view-sort/exceptions/view-sort.exception';
import {
ViewException,
ViewExceptionCode,
} from 'src/engine/metadata-modules/view/exceptions/view.exception';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { workspaceMigrationBuilderExceptionV2Formatter } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/workspace-migration-builder-exception-v2-formatter';
export const viewGraphqlApiExceptionHandler = (error: Error) => {
if (error instanceof WorkspaceMigrationBuilderExceptionV2) {
return workspaceMigrationBuilderExceptionV2Formatter(error);
}
if (error instanceof ViewException) {
switch (error.code) {
case ViewExceptionCode.VIEW_NOT_FOUND:
throw new NotFoundError(error.message);
case ViewExceptionCode.INVALID_VIEW_DATA:
throw new UserInputError(error.message, {
userFriendlyMessage: error.userFriendlyMessage,
});
default: {
return assertUnreachable(error.code);
}
}
}
if (error instanceof ViewFieldException) {
switch (error.code) {
case ViewFieldExceptionCode.VIEW_FIELD_NOT_FOUND:
throw new NotFoundError(error.message);
case ViewFieldExceptionCode.INVALID_VIEW_FIELD_DATA:
throw new UserInputError(error.message, {
userFriendlyMessage: error.userFriendlyMessage,
});
default: {
return assertUnreachable(error.code);
}
}
}
if (error instanceof ViewFilterException) {
switch (error.code) {
case ViewFilterExceptionCode.VIEW_FILTER_NOT_FOUND:
throw new NotFoundError(error.message);
case ViewFilterExceptionCode.INVALID_VIEW_FILTER_DATA:
throw new UserInputError(error.message, {
userFriendlyMessage: error.userFriendlyMessage,
});
default: {
return assertUnreachable(error.code);
}
}
}
if (error instanceof ViewFilterGroupException) {
switch (error.code) {
case ViewFilterGroupExceptionCode.VIEW_FILTER_GROUP_NOT_FOUND:
throw new NotFoundError(error.message);
case ViewFilterGroupExceptionCode.INVALID_VIEW_FILTER_GROUP_DATA:
throw new UserInputError(error.message, {
userFriendlyMessage: error.userFriendlyMessage,
});
default: {
return assertUnreachable(error.code);
}
}
}
if (error instanceof ViewGroupException) {
switch (error.code) {
case ViewGroupExceptionCode.VIEW_GROUP_NOT_FOUND:
throw new NotFoundError(error.message);
case ViewGroupExceptionCode.INVALID_VIEW_GROUP_DATA:
throw new UserInputError(error.message, {
userFriendlyMessage: error.userFriendlyMessage,
});
default: {
return assertUnreachable(error.code);
}
}
}
if (error instanceof ViewSortException) {
switch (error.code) {
case ViewSortExceptionCode.VIEW_SORT_NOT_FOUND:
throw new NotFoundError(error.message);
case ViewSortExceptionCode.INVALID_VIEW_SORT_DATA:
throw new UserInputError(error.message, {
userFriendlyMessage: error.userFriendlyMessage,
});
default: {
return assertUnreachable(error.code);
}
}
}
throw error;
};
@@ -0,0 +1,34 @@
import { Catch, type ExceptionFilter } from '@nestjs/common';
import { ViewFieldException } from 'src/engine/metadata-modules/view-field/exceptions/view-field.exception';
import { ViewFilterGroupException } from 'src/engine/metadata-modules/view-filter-group/exceptions/view-filter-group.exception';
import { ViewFilterException } from 'src/engine/metadata-modules/view-filter/exceptions/view-filter.exception';
import { ViewGroupException } from 'src/engine/metadata-modules/view-group/exceptions/view-group.exception';
import { ViewSortException } from 'src/engine/metadata-modules/view-sort/exceptions/view-sort.exception';
import { ViewException } from 'src/engine/metadata-modules/view/exceptions/view.exception';
import { viewGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/view/utils/view-graphql-api-exception-handler.util';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
@Catch(
ViewException,
ViewFieldException,
ViewFilterException,
ViewFilterGroupException,
ViewGroupException,
ViewSortException,
WorkspaceMigrationBuilderExceptionV2,
)
export class ViewGraphqlApiExceptionFilter implements ExceptionFilter {
catch(
exception:
| ViewException
| ViewFieldException
| ViewFilterException
| ViewFilterGroupException
| ViewGroupException
| ViewSortException
| WorkspaceMigrationBuilderExceptionV2,
) {
return viewGraphqlApiExceptionHandler(exception);
}
}