Introducing view field group syncable entity (#17867)
## Context Introduces a new viewFieldGroup entity that allows grouping view fields into sections (e.g. "General", "Additional", "Other") within a view. The page layout fields widget needs a way to organize fields into sections. Today, views have no concept of field grouping. This PR introduces the viewFieldGroup entity which sits between a view and its viewFields, enabling section-based organization. <img width="401" height="724" alt="Layout - V2 (customize visibility)" src="https://github.com/user-attachments/assets/6376e2ab-44db-42bf-9d2c-758f56f6b548" /> --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
+11
-1
@@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY should match snapshot 1`] = `
|
||||
{
|
||||
@@ -246,6 +246,16 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY should ma
|
||||
"size",
|
||||
"position",
|
||||
"aggregateOperation",
|
||||
"viewFieldGroupUniversalIdentifier",
|
||||
"deletedAt",
|
||||
],
|
||||
"propertiesToStringify": [],
|
||||
},
|
||||
"viewFieldGroup": {
|
||||
"propertiesToCompare": [
|
||||
"name",
|
||||
"position",
|
||||
"isVisible",
|
||||
"deletedAt",
|
||||
],
|
||||
"propertiesToStringify": [],
|
||||
|
||||
+10
@@ -112,6 +112,16 @@ export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
|
||||
size: { toStringify: false, universalProperty: undefined },
|
||||
position: { toStringify: false, universalProperty: undefined },
|
||||
aggregateOperation: { toStringify: false, universalProperty: undefined },
|
||||
viewFieldGroupId: {
|
||||
toStringify: false,
|
||||
universalProperty: 'viewFieldGroupUniversalIdentifier',
|
||||
},
|
||||
deletedAt: { toStringify: false, universalProperty: undefined },
|
||||
},
|
||||
viewFieldGroup: {
|
||||
name: { toStringify: false, universalProperty: undefined },
|
||||
position: { toStringify: false, universalProperty: undefined },
|
||||
isVisible: { toStringify: false, universalProperty: undefined },
|
||||
deletedAt: { toStringify: false, universalProperty: undefined },
|
||||
},
|
||||
viewGroup: {
|
||||
|
||||
+2
@@ -18,6 +18,7 @@ import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modu
|
||||
import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity';
|
||||
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { SkillEntity } from 'src/engine/metadata-modules/skill/entities/skill.entity';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
@@ -26,6 +27,7 @@ import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entit
|
||||
|
||||
export const ALL_METADATA_ENTITY_BY_METADATA_NAME = {
|
||||
viewField: ViewFieldEntity,
|
||||
viewFieldGroup: ViewFieldGroupEntity,
|
||||
viewFilter: ViewFilterEntity,
|
||||
viewGroup: ViewGroupEntity,
|
||||
viewFilterGroup: ViewFilterGroupEntity,
|
||||
|
||||
+22
@@ -221,6 +221,7 @@ export const ALL_METADATA_RELATIONS = {
|
||||
metadataName: 'viewFilterGroup',
|
||||
},
|
||||
viewGroups: { metadataName: 'viewGroup' },
|
||||
viewFieldGroups: { metadataName: 'viewFieldGroup' },
|
||||
// @ts-expect-error TODO migrate viewSort to v2
|
||||
viewSorts: null,
|
||||
},
|
||||
@@ -239,11 +240,32 @@ export const ALL_METADATA_RELATIONS = {
|
||||
foreignKey: 'viewId',
|
||||
isNullable: false,
|
||||
},
|
||||
viewFieldGroup: {
|
||||
metadataName: 'viewFieldGroup',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldIds',
|
||||
foreignKey: 'viewFieldGroupId',
|
||||
isNullable: true,
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
viewFieldGroup: {
|
||||
manyToOne: {
|
||||
view: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldGroupIds',
|
||||
foreignKey: 'viewId',
|
||||
isNullable: false,
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {
|
||||
viewFields: { metadataName: 'viewField' },
|
||||
},
|
||||
},
|
||||
viewFilter: {
|
||||
manyToOne: {
|
||||
fieldMetadata: {
|
||||
|
||||
+4
@@ -27,6 +27,10 @@ export const ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION = {
|
||||
view: true,
|
||||
fieldMetadata: true,
|
||||
objectMetadata: true,
|
||||
viewFieldGroup: true,
|
||||
},
|
||||
viewFieldGroup: {
|
||||
view: true,
|
||||
},
|
||||
index: {
|
||||
objectMetadata: true,
|
||||
|
||||
+5
@@ -12,6 +12,7 @@ import { WorkspaceFlatPageLayoutWidgetMapCacheService } from 'src/engine/metadat
|
||||
import { WorkspaceFlatPageLayoutMapCacheService } from 'src/engine/metadata-modules/flat-page-layout/services/workspace-flat-page-layout-map-cache.service';
|
||||
import { WorkspaceFlatRowLevelPermissionPredicateGroupMapCacheService } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-group-map-cache.service';
|
||||
import { WorkspaceFlatRowLevelPermissionPredicateMapCacheService } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-map-cache.service';
|
||||
import { WorkspaceFlatViewFieldGroupMapCacheService } from 'src/engine/metadata-modules/flat-view-field-group/services/workspace-flat-view-field-group-map-cache.service';
|
||||
import { WorkspaceFlatViewFieldMapCacheService } from 'src/engine/metadata-modules/flat-view-field/services/workspace-flat-view-field-map-cache.service';
|
||||
import { WorkspaceFlatViewFilterGroupMapCacheService } from 'src/engine/metadata-modules/flat-view-filter-group/services/workspace-flat-view-filter-group-map-cache.service';
|
||||
import { WorkspaceFlatViewFilterMapCacheService } from 'src/engine/metadata-modules/flat-view-filter/services/workspace-flat-view-filter-map-cache.service';
|
||||
@@ -26,6 +27,7 @@ import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entiti
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity';
|
||||
import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
@@ -39,6 +41,7 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
|
||||
TypeOrmModule.forFeature([
|
||||
ViewEntity,
|
||||
ViewFieldEntity,
|
||||
ViewFieldGroupEntity,
|
||||
ViewFilterEntity,
|
||||
ViewFilterGroupEntity,
|
||||
ViewGroupEntity,
|
||||
@@ -60,6 +63,7 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
|
||||
WorkspaceFlatObjectMetadataMapCacheService,
|
||||
WorkspaceFlatViewMapCacheService,
|
||||
WorkspaceFlatViewFieldMapCacheService,
|
||||
WorkspaceFlatViewFieldGroupMapCacheService,
|
||||
WorkspaceFlatViewFilterMapCacheService,
|
||||
WorkspaceFlatViewFilterGroupMapCacheService,
|
||||
WorkspaceFlatIndexMapCacheService,
|
||||
@@ -76,6 +80,7 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
|
||||
WorkspaceFlatObjectMetadataMapCacheService,
|
||||
WorkspaceFlatViewMapCacheService,
|
||||
WorkspaceFlatViewFieldMapCacheService,
|
||||
WorkspaceFlatViewFieldGroupMapCacheService,
|
||||
WorkspaceFlatViewFilterMapCacheService,
|
||||
WorkspaceFlatViewFilterGroupMapCacheService,
|
||||
WorkspaceFlatIndexMapCacheService,
|
||||
|
||||
+27
@@ -23,6 +23,8 @@ import { type FlatRoleTarget } from 'src/engine/metadata-modules/flat-role-targe
|
||||
import { type FlatRole } from 'src/engine/metadata-modules/flat-role/types/flat-role.type';
|
||||
import { type FlatSkillMaps } from 'src/engine/metadata-modules/flat-skill/types/flat-skill-maps.type';
|
||||
import { type FlatSkill } from 'src/engine/metadata-modules/flat-skill/types/flat-skill.type';
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type';
|
||||
import { type FlatViewFieldMaps } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field-maps.type';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { type FlatViewFilterGroupMaps } from 'src/engine/metadata-modules/flat-view-filter-group/types/flat-view-filter-group-maps.type';
|
||||
@@ -57,6 +59,7 @@ import { type UniversalFlatRoleTarget } from 'src/engine/workspace-manager/works
|
||||
import { type UniversalFlatRowLevelPermissionPredicate } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-row-level-permission-predicate.type';
|
||||
import { type UniversalFlatRowLevelPermissionPredicateGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-row-level-permission-predicate-group.type';
|
||||
import { type UniversalFlatSkill } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-skill.type';
|
||||
import { type UniversalFlatViewFieldGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field-group.type';
|
||||
import { type UniversalFlatViewField } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field.type';
|
||||
import { type UniversalFlatViewFilterGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-filter-group.type';
|
||||
import { type UniversalFlatViewFilter } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-filter.type';
|
||||
@@ -199,6 +202,14 @@ import {
|
||||
type UniversalDeleteViewFieldAction,
|
||||
type UniversalUpdateViewFieldAction,
|
||||
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-field/types/workspace-migration-view-field-action.type';
|
||||
import {
|
||||
type FlatCreateViewFieldGroupAction,
|
||||
type FlatDeleteViewFieldGroupAction,
|
||||
type FlatUpdateViewFieldGroupAction,
|
||||
type UniversalCreateViewFieldGroupAction,
|
||||
type UniversalDeleteViewFieldGroupAction,
|
||||
type UniversalUpdateViewFieldGroupAction,
|
||||
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-field-group/types/workspace-migration-view-field-group-action.type';
|
||||
import {
|
||||
type FlatCreateViewFilterGroupAction,
|
||||
type FlatDeleteViewFilterGroupAction,
|
||||
@@ -308,6 +319,22 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
universalFlatEntity: UniversalFlatViewField;
|
||||
entity: MetadataEntity<'viewField'>;
|
||||
};
|
||||
viewFieldGroup: {
|
||||
flatEntityMaps: FlatViewFieldGroupMaps;
|
||||
universalActions: {
|
||||
create: UniversalCreateViewFieldGroupAction;
|
||||
update: UniversalUpdateViewFieldGroupAction;
|
||||
delete: UniversalDeleteViewFieldGroupAction;
|
||||
};
|
||||
flatActions: {
|
||||
create: FlatCreateViewFieldGroupAction;
|
||||
update: FlatUpdateViewFieldGroupAction;
|
||||
delete: FlatDeleteViewFieldGroupAction;
|
||||
};
|
||||
flatEntity: FlatViewFieldGroup;
|
||||
universalFlatEntity: UniversalFlatViewFieldGroup;
|
||||
entity: MetadataEntity<'viewFieldGroup'>;
|
||||
};
|
||||
viewGroup: {
|
||||
flatEntityMaps: FlatViewGroupMaps;
|
||||
universalActions: {
|
||||
|
||||
+10
-1
@@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`getMetadataRelatedMetadataNames should return related metadata names for agent 1`] = `[]`;
|
||||
|
||||
@@ -108,6 +108,7 @@ exports[`getMetadataRelatedMetadataNames should return related metadata names fo
|
||||
"viewFilter",
|
||||
"viewFilterGroup",
|
||||
"viewGroup",
|
||||
"viewFieldGroup",
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -115,6 +116,14 @@ exports[`getMetadataRelatedMetadataNames should return related metadata names fo
|
||||
[
|
||||
"fieldMetadata",
|
||||
"view",
|
||||
"viewFieldGroup",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`getMetadataRelatedMetadataNames should return related metadata names for viewFieldGroup 1`] = `
|
||||
[
|
||||
"view",
|
||||
"viewField",
|
||||
]
|
||||
`;
|
||||
|
||||
|
||||
+3
-2
@@ -4,10 +4,10 @@ exports[`sortMetadataNamesChildrenFirst should return metadata names sorted with
|
||||
[
|
||||
"rowLevelPermissionPredicate",
|
||||
"navigationMenuItem",
|
||||
"viewField",
|
||||
"viewFilter",
|
||||
"commandMenuItem",
|
||||
"pageLayoutWidget",
|
||||
"viewField",
|
||||
"index",
|
||||
"pageLayout",
|
||||
"roleTarget",
|
||||
@@ -18,9 +18,10 @@ exports[`sortMetadataNamesChildrenFirst should return metadata names sorted with
|
||||
"logicFunction",
|
||||
"pageLayoutTab",
|
||||
"skill",
|
||||
"view",
|
||||
"viewFieldGroup",
|
||||
"viewFilterGroup",
|
||||
"webhook",
|
||||
"view",
|
||||
"fieldMetadata",
|
||||
"role",
|
||||
"objectMetadata",
|
||||
|
||||
+2
@@ -80,6 +80,8 @@ export const recomputeViewFieldIdentifierAfterFlatObjectIdentifierUpdate = ({
|
||||
deletedAt: null,
|
||||
universalIdentifier: viewFieldId,
|
||||
aggregateOperation: null,
|
||||
viewFieldGroupId: null,
|
||||
viewFieldGroupUniversalIdentifier: null,
|
||||
applicationId: existingFlatObjectMetadata.applicationId,
|
||||
applicationUniversalIdentifier:
|
||||
existingFlatObjectMetadata.applicationUniversalIdentifier,
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
|
||||
|
||||
export const FLAT_VIEW_FIELD_GROUP_EDITABLE_PROPERTIES = [
|
||||
'name',
|
||||
'position',
|
||||
'isVisible',
|
||||
'deletedAt',
|
||||
] as const satisfies MetadataEntityPropertyName<'viewFieldGroup'>[];
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service';
|
||||
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
|
||||
import { FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { fromViewFieldGroupEntityToFlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/utils/from-view-field-group-entity-to-flat-view-field-group.util';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator';
|
||||
import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util';
|
||||
import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id';
|
||||
import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util';
|
||||
|
||||
@Injectable()
|
||||
@WorkspaceCache('flatViewFieldGroupMaps')
|
||||
export class WorkspaceFlatViewFieldGroupMapCacheService extends WorkspaceCacheProvider<FlatViewFieldGroupMaps> {
|
||||
constructor(
|
||||
@InjectRepository(ViewFieldGroupEntity)
|
||||
private readonly viewFieldGroupRepository: Repository<ViewFieldGroupEntity>,
|
||||
@InjectRepository(ApplicationEntity)
|
||||
private readonly applicationRepository: Repository<ApplicationEntity>,
|
||||
@InjectRepository(ViewEntity)
|
||||
private readonly viewRepository: Repository<ViewEntity>,
|
||||
@InjectRepository(ViewFieldEntity)
|
||||
private readonly viewFieldRepository: Repository<ViewFieldEntity>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async computeForCache(workspaceId: string): Promise<FlatViewFieldGroupMaps> {
|
||||
const [viewFieldGroups, applications, views, viewFields] =
|
||||
await Promise.all([
|
||||
this.viewFieldGroupRepository.find({
|
||||
where: { workspaceId },
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.applicationRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'universalIdentifier'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'universalIdentifier'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
this.viewFieldRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'universalIdentifier', 'viewFieldGroupId'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
const applicationIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(applications);
|
||||
const viewIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(views);
|
||||
|
||||
const viewFieldsByViewFieldGroupId =
|
||||
regroupEntitiesByRelatedEntityId<'viewField'>({
|
||||
entities: viewFields,
|
||||
foreignKey: 'viewFieldGroupId',
|
||||
});
|
||||
|
||||
const flatViewFieldGroupMaps = createEmptyFlatEntityMaps();
|
||||
|
||||
for (const viewFieldGroupEntity of viewFieldGroups) {
|
||||
const flatViewFieldGroup = fromViewFieldGroupEntityToFlatViewFieldGroup({
|
||||
entity: {
|
||||
...viewFieldGroupEntity,
|
||||
viewFields:
|
||||
viewFieldsByViewFieldGroupId.get(viewFieldGroupEntity.id) || [],
|
||||
},
|
||||
applicationIdToUniversalIdentifierMap,
|
||||
viewIdToUniversalIdentifierMap,
|
||||
});
|
||||
|
||||
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
|
||||
flatEntity: flatViewFieldGroup,
|
||||
flatEntityMapsToMutate: flatViewFieldGroupMaps,
|
||||
});
|
||||
}
|
||||
|
||||
return flatViewFieldGroupMaps;
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type';
|
||||
|
||||
export type FlatViewFieldGroupMaps = FlatEntityMaps<FlatViewFieldGroup>;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
import { type ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
|
||||
export type FlatViewFieldGroup = FlatEntityFrom<ViewFieldGroupEntity>;
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { type CreateViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/create-view-field-group.input';
|
||||
import { type UniversalFlatViewFieldGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field-group.type';
|
||||
|
||||
export type FromCreateViewFieldGroupInputToFlatViewFieldGroupToCreateArgs = {
|
||||
createViewFieldGroupInput: CreateViewFieldGroupInput;
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<AllFlatEntityMaps, 'flatViewMaps'>;
|
||||
|
||||
export const fromCreateViewFieldGroupInputToFlatViewFieldGroupToCreate = ({
|
||||
createViewFieldGroupInput: rawCreateViewFieldGroupInput,
|
||||
flatApplication,
|
||||
flatViewMaps,
|
||||
}: FromCreateViewFieldGroupInputToFlatViewFieldGroupToCreateArgs): UniversalFlatViewFieldGroup & {
|
||||
id: string;
|
||||
} => {
|
||||
const { viewId, ...createViewFieldGroupInput } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawCreateViewFieldGroupInput,
|
||||
['id', 'name', 'viewId'],
|
||||
);
|
||||
|
||||
const createdAt = new Date().toISOString();
|
||||
const viewFieldGroupId = createViewFieldGroupInput.id ?? v4();
|
||||
|
||||
const { viewUniversalIdentifier } = resolveEntityRelationUniversalIdentifiers(
|
||||
{
|
||||
metadataName: 'viewFieldGroup',
|
||||
foreignKeyValues: { viewId },
|
||||
flatEntityMaps: { flatViewMaps },
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
id: viewFieldGroupId,
|
||||
name: createViewFieldGroupInput.name,
|
||||
viewUniversalIdentifier,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: createViewFieldGroupInput.universalIdentifier ?? v4(),
|
||||
position: createViewFieldGroupInput.position ?? 0,
|
||||
isVisible: createViewFieldGroupInput.isVisible ?? true,
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
};
|
||||
};
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type DeleteViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/delete-view-field-group.input';
|
||||
import {
|
||||
ViewFieldGroupException,
|
||||
ViewFieldGroupExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-field-group/exceptions/view-field-group.exception';
|
||||
import { type UniversalFlatViewFieldGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field-group.type';
|
||||
|
||||
export const fromDeleteViewFieldGroupInputToFlatViewFieldGroupOrThrow = ({
|
||||
deleteViewFieldGroupInput: rawDeleteViewFieldGroupInput,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
deleteViewFieldGroupInput: DeleteViewFieldGroupInput;
|
||||
flatViewFieldGroupMaps: FlatViewFieldGroupMaps;
|
||||
}): UniversalFlatViewFieldGroup => {
|
||||
const { id: viewFieldGroupId } = extractAndSanitizeObjectStringFields(
|
||||
rawDeleteViewFieldGroupInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewFieldGroupToDelete = findFlatEntityByIdInFlatEntityMaps(
|
||||
{
|
||||
flatEntityId: viewFieldGroupId,
|
||||
flatEntityMaps: flatViewFieldGroupMaps,
|
||||
},
|
||||
);
|
||||
|
||||
if (!isDefined(existingFlatViewFieldGroupToDelete)) {
|
||||
throw new ViewFieldGroupException(
|
||||
t`View field group to delete not found`,
|
||||
ViewFieldGroupExceptionCode.VIEW_FIELD_GROUP_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatViewFieldGroupToDelete,
|
||||
deletedAt: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type DestroyViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/destroy-view-field-group.input';
|
||||
import {
|
||||
ViewFieldGroupException,
|
||||
ViewFieldGroupExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-field-group/exceptions/view-field-group.exception';
|
||||
import { type UniversalFlatViewFieldGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field-group.type';
|
||||
|
||||
export const fromDestroyViewFieldGroupInputToFlatViewFieldGroupOrThrow = ({
|
||||
destroyViewFieldGroupInput,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
destroyViewFieldGroupInput: DestroyViewFieldGroupInput;
|
||||
flatViewFieldGroupMaps: FlatViewFieldGroupMaps;
|
||||
}): UniversalFlatViewFieldGroup => {
|
||||
const { id: viewFieldGroupId } = extractAndSanitizeObjectStringFields(
|
||||
destroyViewFieldGroupInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewFieldGroupToDestroy =
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewFieldGroupId,
|
||||
flatEntityMaps: flatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(existingFlatViewFieldGroupToDestroy)) {
|
||||
throw new ViewFieldGroupException(
|
||||
t`View field group to destroy not found`,
|
||||
ViewFieldGroupExceptionCode.VIEW_FIELD_GROUP_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return existingFlatViewFieldGroupToDestroy;
|
||||
};
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { FLAT_VIEW_FIELD_GROUP_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-field-group/constants/flat-view-field-group-editable-properties.constant';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatViewFieldGroupMaps } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group-maps.type';
|
||||
import { type UpdateViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/update-view-field-group.input';
|
||||
import {
|
||||
ViewFieldGroupException,
|
||||
ViewFieldGroupExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-field-group/exceptions/view-field-group.exception';
|
||||
import { type UniversalFlatViewFieldGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field-group.type';
|
||||
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
|
||||
|
||||
export const fromUpdateViewFieldGroupInputToFlatViewFieldGroupToUpdateOrThrow =
|
||||
({
|
||||
updateViewFieldGroupInput: rawUpdateViewFieldGroupInput,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
updateViewFieldGroupInput: UpdateViewFieldGroupInput;
|
||||
flatViewFieldGroupMaps: FlatViewFieldGroupMaps;
|
||||
}): UniversalFlatViewFieldGroup => {
|
||||
const { id: viewFieldGroupToUpdateId } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawUpdateViewFieldGroupInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewFieldGroupToUpdate =
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewFieldGroupToUpdateId,
|
||||
flatEntityMaps: flatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(existingFlatViewFieldGroupToUpdate)) {
|
||||
throw new ViewFieldGroupException(
|
||||
t`View field group to update not found`,
|
||||
ViewFieldGroupExceptionCode.VIEW_FIELD_GROUP_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const updatedEditableProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateViewFieldGroupInput.update,
|
||||
FLAT_VIEW_FIELD_GROUP_EDITABLE_PROPERTIES,
|
||||
);
|
||||
|
||||
return mergeUpdateInExistingRecord({
|
||||
existing: existingFlatViewFieldGroupToUpdate,
|
||||
properties: FLAT_VIEW_FIELD_GROUP_EDITABLE_PROPERTIES,
|
||||
update: updatedEditableProperties,
|
||||
});
|
||||
};
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
FlatEntityMapsException,
|
||||
FlatEntityMapsExceptionCode,
|
||||
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
|
||||
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
|
||||
import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type';
|
||||
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
|
||||
|
||||
export const fromViewFieldGroupEntityToFlatViewFieldGroup = ({
|
||||
entity: viewFieldGroupEntity,
|
||||
applicationIdToUniversalIdentifierMap,
|
||||
viewIdToUniversalIdentifierMap,
|
||||
}: FromEntityToFlatEntityArgs<'viewFieldGroup'>): FlatViewFieldGroup => {
|
||||
const viewFieldGroupEntityWithoutRelations = removePropertiesFromRecord(
|
||||
viewFieldGroupEntity,
|
||||
getMetadataEntityRelationProperties('viewFieldGroup'),
|
||||
);
|
||||
|
||||
const applicationUniversalIdentifier =
|
||||
applicationIdToUniversalIdentifierMap.get(
|
||||
viewFieldGroupEntity.applicationId,
|
||||
);
|
||||
|
||||
if (!isDefined(applicationUniversalIdentifier)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`Application with id ${viewFieldGroupEntity.applicationId} not found for viewFieldGroup ${viewFieldGroupEntity.id}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
|
||||
viewFieldGroupEntity.viewId,
|
||||
);
|
||||
|
||||
if (!isDefined(viewUniversalIdentifier)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`View with id ${viewFieldGroupEntity.viewId} not found for viewFieldGroup ${viewFieldGroupEntity.id}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...viewFieldGroupEntityWithoutRelations,
|
||||
createdAt: viewFieldGroupEntity.createdAt.toISOString(),
|
||||
updatedAt: viewFieldGroupEntity.updatedAt.toISOString(),
|
||||
deletedAt: viewFieldGroupEntity.deletedAt?.toISOString() ?? null,
|
||||
universalIdentifier:
|
||||
viewFieldGroupEntityWithoutRelations.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
viewFieldIds:
|
||||
viewFieldGroupEntity.viewFields?.map((viewField) => viewField.id) ?? [],
|
||||
viewFieldUniversalIdentifiers:
|
||||
viewFieldGroupEntity.viewFields?.map(
|
||||
(viewField) => viewField.universalIdentifier,
|
||||
) ?? [],
|
||||
};
|
||||
};
|
||||
+1
@@ -5,4 +5,5 @@ export const FLAT_VIEW_FIELD_EDITABLE_PROPERTIES = [
|
||||
'size',
|
||||
'position',
|
||||
'aggregateOperation',
|
||||
'viewFieldGroupId',
|
||||
] as const satisfies MetadataEntityPropertyName<'viewField'>[];
|
||||
|
||||
+14
-4
@@ -10,6 +10,7 @@ import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/
|
||||
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
|
||||
import { FlatViewFieldMaps } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field-maps.type';
|
||||
import { fromViewFieldEntityToFlatViewField } from 'src/engine/metadata-modules/flat-view-field/utils/from-view-field-entity-to-flat-view-field.util';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator';
|
||||
@@ -28,13 +29,15 @@ export class WorkspaceFlatViewFieldMapCacheService extends WorkspaceCacheProvide
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
@InjectRepository(ViewEntity)
|
||||
private readonly viewRepository: Repository<ViewEntity>,
|
||||
@InjectRepository(ViewFieldGroupEntity)
|
||||
private readonly viewFieldGroupRepository: Repository<ViewFieldGroupEntity>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async computeForCache(workspaceId: string): Promise<FlatViewFieldMaps> {
|
||||
const [viewFields, applications, fieldMetadatas, views] = await Promise.all(
|
||||
[
|
||||
const [viewFields, applications, fieldMetadatas, views, viewFieldGroups] =
|
||||
await Promise.all([
|
||||
this.viewFieldRepository.find({
|
||||
where: { workspaceId },
|
||||
withDeleted: true,
|
||||
@@ -54,8 +57,12 @@ export class WorkspaceFlatViewFieldMapCacheService extends WorkspaceCacheProvide
|
||||
select: ['id', 'universalIdentifier'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
],
|
||||
);
|
||||
this.viewFieldGroupRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'universalIdentifier'],
|
||||
withDeleted: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
const applicationIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(applications);
|
||||
@@ -63,6 +70,8 @@ export class WorkspaceFlatViewFieldMapCacheService extends WorkspaceCacheProvide
|
||||
createIdToUniversalIdentifierMap(fieldMetadatas);
|
||||
const viewIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(views);
|
||||
const viewFieldGroupIdToUniversalIdentifierMap =
|
||||
createIdToUniversalIdentifierMap(viewFieldGroups);
|
||||
|
||||
const flatViewFieldMaps = createEmptyFlatEntityMaps();
|
||||
|
||||
@@ -72,6 +81,7 @@ export class WorkspaceFlatViewFieldMapCacheService extends WorkspaceCacheProvide
|
||||
applicationIdToUniversalIdentifierMap,
|
||||
fieldMetadataIdToUniversalIdentifierMap,
|
||||
viewIdToUniversalIdentifierMap,
|
||||
viewFieldGroupIdToUniversalIdentifierMap,
|
||||
});
|
||||
|
||||
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
|
||||
|
||||
+27
-9
@@ -11,31 +11,48 @@ import { type UniversalFlatViewField } from 'src/engine/workspace-manager/worksp
|
||||
export type FromCreateViewFieldInputToFlatViewFieldToCreateArgs = {
|
||||
createViewFieldInput: CreateViewFieldInput;
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<AllFlatEntityMaps, 'flatFieldMetadataMaps' | 'flatViewMaps'>;
|
||||
} & Pick<
|
||||
AllFlatEntityMaps,
|
||||
'flatFieldMetadataMaps' | 'flatViewMaps' | 'flatViewFieldGroupMaps'
|
||||
>;
|
||||
|
||||
export const fromCreateViewFieldInputToFlatViewFieldToCreate = ({
|
||||
createViewFieldInput: rawCreateViewFieldInput,
|
||||
flatApplication,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: FromCreateViewFieldInputToFlatViewFieldToCreateArgs): UniversalFlatViewField & {
|
||||
id: string;
|
||||
} => {
|
||||
const { fieldMetadataId, viewId, ...createViewFieldInput } =
|
||||
const { fieldMetadataId, viewId, viewFieldGroupId, ...createViewFieldInput } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawCreateViewFieldInput,
|
||||
['aggregateOperation', 'fieldMetadataId', 'id', 'viewId'],
|
||||
[
|
||||
'aggregateOperation',
|
||||
'fieldMetadataId',
|
||||
'id',
|
||||
'viewId',
|
||||
'viewFieldGroupId',
|
||||
],
|
||||
);
|
||||
|
||||
const createdAt = new Date().toISOString();
|
||||
const viewFieldId = createViewFieldInput.id ?? v4();
|
||||
|
||||
const { fieldMetadataUniversalIdentifier, viewUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'viewField',
|
||||
foreignKeyValues: { fieldMetadataId, viewId },
|
||||
flatEntityMaps: { flatFieldMetadataMaps, flatViewMaps },
|
||||
});
|
||||
const {
|
||||
fieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
viewFieldGroupUniversalIdentifier,
|
||||
} = resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'viewField',
|
||||
foreignKeyValues: { fieldMetadataId, viewId, viewFieldGroupId },
|
||||
flatEntityMaps: {
|
||||
flatFieldMetadataMaps,
|
||||
flatViewMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
id: viewFieldId,
|
||||
@@ -49,6 +66,7 @@ export const fromCreateViewFieldInputToFlatViewFieldToCreate = ({
|
||||
size: createViewFieldInput.size ?? DEFAULT_VIEW_FIELD_SIZE,
|
||||
position: createViewFieldInput.position ?? 0,
|
||||
aggregateOperation: createViewFieldInput.aggregateOperation ?? null,
|
||||
viewFieldGroupUniversalIdentifier,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
};
|
||||
};
|
||||
|
||||
+26
-3
@@ -5,8 +5,10 @@ import {
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { FLAT_VIEW_FIELD_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-field/constants/flat-view-field-editable-properties.constant';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { FLAT_VIEW_FIELD_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-field/constants/flat-view-field-editable-properties.constant';
|
||||
import { type FlatViewFieldMaps } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field-maps.type';
|
||||
import { type UpdateViewFieldInput } from 'src/engine/metadata-modules/view-field/dtos/inputs/update-view-field.input';
|
||||
import {
|
||||
@@ -19,10 +21,14 @@ import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-
|
||||
export const fromUpdateViewFieldInputToFlatViewFieldToUpdateOrThrow = ({
|
||||
updateViewFieldInput: rawUpdateViewFieldInput,
|
||||
flatViewFieldMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}: {
|
||||
updateViewFieldInput: UpdateViewFieldInput;
|
||||
flatViewFieldMaps: FlatViewFieldMaps;
|
||||
}): UniversalFlatViewField => {
|
||||
} & Pick<
|
||||
AllFlatEntityMaps,
|
||||
'flatViewFieldGroupMaps'
|
||||
>): UniversalFlatViewField => {
|
||||
const { id: viewFieldToUpdateId } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawUpdateViewFieldInput,
|
||||
@@ -40,14 +46,31 @@ export const fromUpdateViewFieldInputToFlatViewFieldToUpdateOrThrow = ({
|
||||
ViewFieldExceptionCode.VIEW_FIELD_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const updatedEditableFieldProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateViewFieldInput.update,
|
||||
FLAT_VIEW_FIELD_EDITABLE_PROPERTIES,
|
||||
);
|
||||
|
||||
return mergeUpdateInExistingRecord({
|
||||
const flatViewFieldToUpdate = mergeUpdateInExistingRecord({
|
||||
existing: existingFlatViewFieldToUpdate,
|
||||
properties: FLAT_VIEW_FIELD_EDITABLE_PROPERTIES,
|
||||
update: updatedEditableFieldProperties,
|
||||
});
|
||||
|
||||
if (updatedEditableFieldProperties.viewFieldGroupId !== undefined) {
|
||||
const { viewFieldGroupUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'viewField',
|
||||
foreignKeyValues: {
|
||||
viewFieldGroupId: flatViewFieldToUpdate.viewFieldGroupId,
|
||||
},
|
||||
flatEntityMaps: { flatViewFieldGroupMaps },
|
||||
});
|
||||
|
||||
flatViewFieldToUpdate.viewFieldGroupUniversalIdentifier =
|
||||
viewFieldGroupUniversalIdentifier;
|
||||
}
|
||||
|
||||
return flatViewFieldToUpdate;
|
||||
};
|
||||
|
||||
+18
@@ -13,6 +13,7 @@ export const fromViewFieldEntityToFlatViewField = ({
|
||||
applicationIdToUniversalIdentifierMap,
|
||||
fieldMetadataIdToUniversalIdentifierMap,
|
||||
viewIdToUniversalIdentifierMap,
|
||||
viewFieldGroupIdToUniversalIdentifierMap,
|
||||
}: FromEntityToFlatEntityArgs<'viewField'>): FlatViewField => {
|
||||
const viewFieldEntityWithoutRelations = removePropertiesFromRecord(
|
||||
viewFieldEntity,
|
||||
@@ -52,6 +53,22 @@ export const fromViewFieldEntityToFlatViewField = ({
|
||||
);
|
||||
}
|
||||
|
||||
let viewFieldGroupUniversalIdentifier: string | null = null;
|
||||
|
||||
if (isDefined(viewFieldEntity.viewFieldGroupId)) {
|
||||
viewFieldGroupUniversalIdentifier =
|
||||
viewFieldGroupIdToUniversalIdentifierMap.get(
|
||||
viewFieldEntity.viewFieldGroupId,
|
||||
) ?? null;
|
||||
|
||||
if (!isDefined(viewFieldGroupUniversalIdentifier)) {
|
||||
throw new FlatEntityMapsException(
|
||||
`ViewFieldGroup with id ${viewFieldEntity.viewFieldGroupId} not found for viewField ${viewFieldEntity.id}`,
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...viewFieldEntityWithoutRelations,
|
||||
createdAt: viewFieldEntity.createdAt.toISOString(),
|
||||
@@ -61,5 +78,6 @@ export const fromViewFieldEntityToFlatViewField = ({
|
||||
applicationUniversalIdentifier,
|
||||
fieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
viewFieldGroupUniversalIdentifier,
|
||||
};
|
||||
};
|
||||
|
||||
+1
@@ -87,6 +87,7 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewGroupUniversalIdentifiers: [],
|
||||
viewFieldGroupUniversalIdentifiers: [],
|
||||
viewFilterGroupUniversalIdentifiers: [],
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
};
|
||||
|
||||
+5
@@ -95,6 +95,7 @@ export const fromViewEntityToFlatView = ({
|
||||
deletedAt: viewEntity.deletedAt?.toISOString() ?? null,
|
||||
universalIdentifier: viewEntityWithoutRelations.universalIdentifier,
|
||||
viewFieldIds: viewEntity.viewFields.map(({ id }) => id),
|
||||
viewFieldGroupIds: viewEntity.viewFieldGroups?.map(({ id }) => id) ?? [],
|
||||
viewFilterIds: viewEntity.viewFilters.map(({ id }) => id),
|
||||
viewGroupIds: viewEntity.viewGroups.map(({ id }) => id),
|
||||
viewFilterGroupIds: viewEntity.viewFilterGroups?.map(({ id }) => id) ?? [],
|
||||
@@ -106,6 +107,10 @@ export const fromViewEntityToFlatView = ({
|
||||
viewFieldUniversalIdentifiers: viewEntity.viewFields.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
viewFieldGroupUniversalIdentifiers:
|
||||
viewEntity.viewFieldGroups?.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
) ?? [],
|
||||
viewFilterUniversalIdentifiers: viewEntity.viewFilters.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
|
||||
+2
@@ -549,6 +549,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
visibility: ViewVisibility.WORKSPACE,
|
||||
createdByUserWorkspaceId: null,
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
viewFieldGroupUniversalIdentifiers: [],
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewGroupUniversalIdentifiers: [],
|
||||
viewFilterGroupUniversalIdentifiers: [],
|
||||
@@ -580,6 +581,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
.map<UniversalFlatViewField>((field, index) => ({
|
||||
fieldMetadataUniversalIdentifier: field.universalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
viewFieldGroupUniversalIdentifier: null,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@InputType()
|
||||
export class CreateViewFieldGroupInput {
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
id?: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@Field({ nullable: false })
|
||||
name: string;
|
||||
|
||||
@IsUUID()
|
||||
@Field(() => UUIDScalarType, { nullable: false })
|
||||
viewId: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Field({ nullable: true, defaultValue: 0 })
|
||||
position?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true, defaultValue: true })
|
||||
isVisible?: boolean;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
|
||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
import { IsUUID } from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@InputType()
|
||||
export class DeleteViewFieldGroupInput {
|
||||
@IDField(() => UUIDScalarType, {
|
||||
description: 'The id of the view field group to delete.',
|
||||
})
|
||||
@IsUUID()
|
||||
id: string;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
|
||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
import { IsUUID } from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@InputType()
|
||||
export class DestroyViewFieldGroupInput {
|
||||
@IDField(() => UUIDScalarType, {
|
||||
description: 'The id of the view field group to destroy.',
|
||||
})
|
||||
@IsUUID()
|
||||
id: string;
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@InputType()
|
||||
class UpdateViewFieldGroupInputUpdates {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
name?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Field({ nullable: true })
|
||||
position?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true })
|
||||
isVisible?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
deletedAt?: string;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class UpdateViewFieldGroupInput {
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
@Field(() => UUIDScalarType, {
|
||||
description: 'The id of the view field group to update',
|
||||
})
|
||||
id: string;
|
||||
|
||||
@Type(() => UpdateViewFieldGroupInputUpdates)
|
||||
@ValidateNested()
|
||||
@Field(() => UpdateViewFieldGroupInputUpdates, {
|
||||
description: 'The view field group to update',
|
||||
})
|
||||
update: UpdateViewFieldGroupInputUpdates;
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
|
||||
@ObjectType('CoreViewFieldGroup')
|
||||
export class ViewFieldGroupDTO {
|
||||
@IDField(() => UUIDScalarType)
|
||||
id: string;
|
||||
|
||||
@Field({ nullable: false })
|
||||
name: string;
|
||||
|
||||
@Field({ nullable: false, defaultValue: 0 })
|
||||
position: number;
|
||||
|
||||
@Field({ nullable: false, defaultValue: true })
|
||||
isVisible: boolean;
|
||||
|
||||
@Field(() => UUIDScalarType, { nullable: false })
|
||||
viewId: string;
|
||||
|
||||
@Field(() => UUIDScalarType, { nullable: false })
|
||||
workspaceId: string;
|
||||
|
||||
@Field()
|
||||
createdAt: Date;
|
||||
|
||||
@Field()
|
||||
updatedAt: Date;
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
deletedAt?: Date | null;
|
||||
|
||||
@Field(() => [ViewFieldDTO])
|
||||
viewFields?: ViewFieldDTO[];
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
type Relation,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
|
||||
@Entity({ name: 'viewFieldGroup', schema: 'core' })
|
||||
@Index('IDX_VIEW_FIELD_GROUP_WORKSPACE_ID_VIEW_ID', ['workspaceId', 'viewId'])
|
||||
@Index('IDX_VIEW_FIELD_GROUP_VIEW_ID', ['viewId'])
|
||||
export class ViewFieldGroupEntity
|
||||
extends SyncableEntity
|
||||
implements Required<ViewFieldGroupEntity>
|
||||
{
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ nullable: false, type: 'text' })
|
||||
name: string;
|
||||
|
||||
@Column({ nullable: false, type: 'double precision', default: 0 })
|
||||
position: number;
|
||||
|
||||
@Column({ nullable: false, default: true })
|
||||
isVisible: boolean;
|
||||
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
viewId: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt: Date;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz' })
|
||||
deletedAt: Date | null;
|
||||
|
||||
@ManyToOne(() => ViewEntity, (view) => view.viewFieldGroups, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'viewId' })
|
||||
view: Relation<ViewEntity>;
|
||||
|
||||
@OneToMany(() => ViewFieldEntity, (viewField) => viewField.viewFieldGroup)
|
||||
viewFields: Relation<ViewFieldEntity[]>;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { type MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
|
||||
import { CustomException } from 'src/utils/custom-exception';
|
||||
|
||||
export class ViewFieldGroupException extends CustomException<ViewFieldGroupExceptionCode> {
|
||||
constructor(
|
||||
message: string,
|
||||
code: ViewFieldGroupExceptionCode,
|
||||
{ userFriendlyMessage }: { userFriendlyMessage?: MessageDescriptor } = {},
|
||||
) {
|
||||
super(message, code, {
|
||||
userFriendlyMessage:
|
||||
userFriendlyMessage ?? msg`A view field group error occurred.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export enum ViewFieldGroupExceptionCode {
|
||||
VIEW_FIELD_GROUP_NOT_FOUND = 'VIEW_FIELD_GROUP_NOT_FOUND',
|
||||
VIEW_NOT_FOUND = 'VIEW_NOT_FOUND',
|
||||
INVALID_VIEW_FIELD_GROUP_DATA = 'INVALID_VIEW_FIELD_GROUP_DATA',
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
Args,
|
||||
Context,
|
||||
Mutation,
|
||||
Parent,
|
||||
Query,
|
||||
ResolveField,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { isArray } from '@sniptt/guards';
|
||||
|
||||
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type IDataloaders } from 'src/engine/dataloaders/dataloader.interface';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { CreateViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/create-view-field-group.input';
|
||||
import { DeleteViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/delete-view-field-group.input';
|
||||
import { DestroyViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/destroy-view-field-group.input';
|
||||
import { UpdateViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/update-view-field-group.input';
|
||||
import { ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewFieldGroupService } from 'src/engine/metadata-modules/view-field-group/services/view-field-group.service';
|
||||
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
import { ViewGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/view/utils/view-graphql-api-exception.filter';
|
||||
|
||||
@MetadataResolver(() => ViewFieldGroupDTO)
|
||||
@UseFilters(ViewGraphqlApiExceptionFilter)
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
export class ViewFieldGroupResolver {
|
||||
constructor(private readonly viewFieldGroupService: ViewFieldGroupService) {}
|
||||
|
||||
@Query(() => [ViewFieldGroupDTO])
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async getCoreViewFieldGroups(
|
||||
@Args('viewId', { type: () => String }) viewId: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewFieldGroupEntity[]> {
|
||||
return this.viewFieldGroupService.findByViewId(workspace.id, viewId);
|
||||
}
|
||||
|
||||
@Query(() => ViewFieldGroupDTO, { nullable: true })
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async getCoreViewFieldGroup(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewFieldGroupEntity | null> {
|
||||
return this.viewFieldGroupService.findById(id, workspace.id);
|
||||
}
|
||||
|
||||
@Mutation(() => ViewFieldGroupDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async updateCoreViewFieldGroup(
|
||||
@Args('input') updateViewFieldGroupInput: UpdateViewFieldGroupInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldGroupDTO> {
|
||||
return await this.viewFieldGroupService.updateOne({
|
||||
updateViewFieldGroupInput,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => ViewFieldGroupDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async createCoreViewFieldGroup(
|
||||
@Args('input')
|
||||
createViewFieldGroupInput: CreateViewFieldGroupInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldGroupDTO> {
|
||||
return await this.viewFieldGroupService.createOne({
|
||||
createViewFieldGroupInput,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => [ViewFieldGroupDTO])
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async createManyCoreViewFieldGroups(
|
||||
@Args('inputs', { type: () => [CreateViewFieldGroupInput] })
|
||||
createViewFieldGroupInputs: CreateViewFieldGroupInput[],
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldGroupDTO[]> {
|
||||
return await this.viewFieldGroupService.createMany({
|
||||
createViewFieldGroupInputs,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => ViewFieldGroupDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async deleteCoreViewFieldGroup(
|
||||
@Args('input') deleteViewFieldGroupInput: DeleteViewFieldGroupInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldGroupDTO> {
|
||||
return await this.viewFieldGroupService.deleteOne({
|
||||
deleteViewFieldGroupInput,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => ViewFieldGroupDTO)
|
||||
@UseGuards(NoPermissionGuard)
|
||||
async destroyCoreViewFieldGroup(
|
||||
@Args('input')
|
||||
destroyViewFieldGroupInput: DestroyViewFieldGroupInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldGroupDTO> {
|
||||
return await this.viewFieldGroupService.destroyOne({
|
||||
destroyViewFieldGroupInput,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewFieldDTO])
|
||||
async viewFields(
|
||||
@Parent() viewFieldGroup: ViewFieldGroupDTO,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(viewFieldGroup.viewFields)) {
|
||||
return viewFieldGroup.viewFields;
|
||||
}
|
||||
|
||||
return context.loaders.viewFieldsByViewFieldGroupIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewFieldGroupId: viewFieldGroup.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { fromCreateViewFieldGroupInputToFlatViewFieldGroupToCreate } from 'src/engine/metadata-modules/flat-view-field-group/utils/from-create-view-field-group-input-to-flat-view-field-group-to-create.util';
|
||||
import { fromDeleteViewFieldGroupInputToFlatViewFieldGroupOrThrow } from 'src/engine/metadata-modules/flat-view-field-group/utils/from-delete-view-field-group-input-to-flat-view-field-group-or-throw.util';
|
||||
import { fromDestroyViewFieldGroupInputToFlatViewFieldGroupOrThrow } from 'src/engine/metadata-modules/flat-view-field-group/utils/from-destroy-view-field-group-input-to-flat-view-field-group-or-throw.util';
|
||||
import { fromUpdateViewFieldGroupInputToFlatViewFieldGroupToUpdateOrThrow } from 'src/engine/metadata-modules/flat-view-field-group/utils/from-update-view-field-group-input-to-flat-view-field-group-to-update-or-throw.util';
|
||||
import { CreateViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/create-view-field-group.input';
|
||||
import { DeleteViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/delete-view-field-group.input';
|
||||
import { DestroyViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/destroy-view-field-group.input';
|
||||
import { UpdateViewFieldGroupInput } from 'src/engine/metadata-modules/view-field-group/dtos/inputs/update-view-field-group.input';
|
||||
import { ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import {
|
||||
ViewFieldGroupException,
|
||||
ViewFieldGroupExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-field-group/exceptions/view-field-group.exception';
|
||||
import { fromFlatViewFieldGroupToViewFieldGroupDto } from 'src/engine/metadata-modules/view-field-group/utils/from-flat-view-field-group-to-view-field-group-dto.util';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
@Injectable()
|
||||
export class ViewFieldGroupService {
|
||||
constructor(
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
@InjectRepository(ViewFieldGroupEntity)
|
||||
private readonly viewFieldGroupRepository: Repository<ViewFieldGroupEntity>,
|
||||
private readonly applicationService: ApplicationService,
|
||||
) {}
|
||||
|
||||
async createOne({
|
||||
createViewFieldGroupInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
createViewFieldGroupInput: CreateViewFieldGroupInput;
|
||||
workspaceId: string;
|
||||
}): Promise<ViewFieldGroupDTO> {
|
||||
const [createdViewFieldGroup] = await this.createMany({
|
||||
workspaceId,
|
||||
createViewFieldGroupInputs: [createViewFieldGroupInput],
|
||||
});
|
||||
|
||||
if (!isDefined(createdViewFieldGroup)) {
|
||||
throw new ViewFieldGroupException(
|
||||
'Failed to create view field group',
|
||||
ViewFieldGroupExceptionCode.INVALID_VIEW_FIELD_GROUP_DATA,
|
||||
);
|
||||
}
|
||||
|
||||
return createdViewFieldGroup;
|
||||
}
|
||||
|
||||
async createMany({
|
||||
createViewFieldGroupInputs,
|
||||
workspaceId,
|
||||
}: {
|
||||
createViewFieldGroupInputs: CreateViewFieldGroupInput[];
|
||||
workspaceId: string;
|
||||
}): Promise<ViewFieldGroupDTO[]> {
|
||||
if (createViewFieldGroupInputs.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const { flatViewMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatViewFieldGroupsToCreate = createViewFieldGroupInputs.map(
|
||||
(createViewFieldGroupInput) =>
|
||||
fromCreateViewFieldGroupInputToFlatViewFieldGroupToCreate({
|
||||
createViewFieldGroupInput,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatViewMaps,
|
||||
}),
|
||||
);
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
viewFieldGroup: {
|
||||
flatEntityToCreate: flatViewFieldGroupsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while creating view field groups',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatViewFieldGroupMaps: recomputedExistingFlatViewFieldGroupMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewFieldGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return findManyFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityIds: flatViewFieldGroupsToCreate.map((entity) => entity.id),
|
||||
flatEntityMaps: recomputedExistingFlatViewFieldGroupMaps,
|
||||
}).map(fromFlatViewFieldGroupToViewFieldGroupDto);
|
||||
}
|
||||
|
||||
async updateOne({
|
||||
updateViewFieldGroupInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
updateViewFieldGroupInput: UpdateViewFieldGroupInput;
|
||||
}): Promise<ViewFieldGroupDTO> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const { flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewFieldGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const optimisticallyUpdatedFlatViewFieldGroup =
|
||||
fromUpdateViewFieldGroupInputToFlatViewFieldGroupToUpdateOrThrow({
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
updateViewFieldGroupInput,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
viewFieldGroup: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [optimisticallyUpdatedFlatViewFieldGroup],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while updating view field group',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatViewFieldGroupMaps: recomputedExistingFlatViewFieldGroupMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewFieldGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return fromFlatViewFieldGroupToViewFieldGroupDto(
|
||||
findFlatEntityByUniversalIdentifierOrThrow({
|
||||
universalIdentifier:
|
||||
optimisticallyUpdatedFlatViewFieldGroup.universalIdentifier,
|
||||
flatEntityMaps: recomputedExistingFlatViewFieldGroupMaps,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async deleteOne({
|
||||
deleteViewFieldGroupInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
deleteViewFieldGroupInput: DeleteViewFieldGroupInput;
|
||||
workspaceId: string;
|
||||
}): Promise<ViewFieldGroupDTO> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const { flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewFieldGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const optimisticallyUpdatedFlatViewFieldGroupWithDeletedAt =
|
||||
fromDeleteViewFieldGroupInputToFlatViewFieldGroupOrThrow({
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
deleteViewFieldGroupInput,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
viewFieldGroup: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [
|
||||
optimisticallyUpdatedFlatViewFieldGroupWithDeletedAt,
|
||||
],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while deleting view field group',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatViewFieldGroupMaps: recomputedExistingFlatViewFieldGroupMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewFieldGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return fromFlatViewFieldGroupToViewFieldGroupDto(
|
||||
findFlatEntityByUniversalIdentifierOrThrow({
|
||||
universalIdentifier:
|
||||
optimisticallyUpdatedFlatViewFieldGroupWithDeletedAt.universalIdentifier,
|
||||
flatEntityMaps: recomputedExistingFlatViewFieldGroupMaps,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async destroyOne({
|
||||
destroyViewFieldGroupInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
destroyViewFieldGroupInput: DestroyViewFieldGroupInput;
|
||||
workspaceId: string;
|
||||
}): Promise<ViewFieldGroupDTO> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const { flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewFieldGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const existingViewFieldGroupToDelete =
|
||||
fromDestroyViewFieldGroupInputToFlatViewFieldGroupOrThrow({
|
||||
destroyViewFieldGroupInput,
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
const existingFlatViewFieldGroup =
|
||||
findFlatEntityByUniversalIdentifierOrThrow({
|
||||
universalIdentifier: existingViewFieldGroupToDelete.universalIdentifier,
|
||||
flatEntityMaps: existingFlatViewFieldGroupMaps,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
viewFieldGroup: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [existingViewFieldGroupToDelete],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while destroying view field group',
|
||||
);
|
||||
}
|
||||
|
||||
return fromFlatViewFieldGroupToViewFieldGroupDto({
|
||||
...existingFlatViewFieldGroup,
|
||||
deletedAt: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async findByViewId(
|
||||
workspaceId: string,
|
||||
viewId: string,
|
||||
): Promise<ViewFieldGroupEntity[]> {
|
||||
return this.viewFieldGroupRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
viewId,
|
||||
deletedAt: IsNull(),
|
||||
},
|
||||
order: { position: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
async findById(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<ViewFieldGroupEntity | null> {
|
||||
const viewFieldGroup = await this.viewFieldGroupRepository.findOne({
|
||||
where: {
|
||||
id,
|
||||
workspaceId,
|
||||
deletedAt: IsNull(),
|
||||
},
|
||||
});
|
||||
|
||||
return viewFieldGroup || null;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type';
|
||||
import { type ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
|
||||
export const fromFlatViewFieldGroupToViewFieldGroupDto = (
|
||||
flatViewFieldGroup: FlatViewFieldGroup,
|
||||
): ViewFieldGroupDTO => {
|
||||
const { createdAt, updatedAt, deletedAt, ...rest } = flatViewFieldGroup;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
createdAt: new Date(createdAt),
|
||||
updatedAt: new Date(updatedAt),
|
||||
deletedAt: deletedAt ? new Date(deletedAt) : null,
|
||||
};
|
||||
};
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewFieldGroupResolver } from 'src/engine/metadata-modules/view-field-group/resolvers/view-field-group.resolver';
|
||||
import { ViewFieldGroupService } from 'src/engine/metadata-modules/view-field-group/services/view-field-group.service';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([ViewFieldGroupEntity, ViewEntity]),
|
||||
WorkspaceCacheStorageModule,
|
||||
ApplicationModule,
|
||||
PermissionsModule,
|
||||
WorkspaceMigrationModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
],
|
||||
providers: [ViewFieldGroupResolver, ViewFieldGroupService],
|
||||
exports: [ViewFieldGroupService],
|
||||
})
|
||||
export class ViewFieldGroupModule {}
|
||||
+8
-8
@@ -29,7 +29,7 @@ import {
|
||||
ViewFieldExceptionMessageKey,
|
||||
} from 'src/engine/metadata-modules/view-field/exceptions/view-field.exception';
|
||||
import { ViewFieldRestApiExceptionFilter } from 'src/engine/metadata-modules/view-field/filters/view-field-rest-api-exception.filter';
|
||||
import { ViewFieldV2Service } from 'src/engine/metadata-modules/view-field/services/view-field-v2.service';
|
||||
import { ViewFieldService } from 'src/engine/metadata-modules/view-field/services/view-field.service';
|
||||
import { CreateViewFieldPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/create-view-field-permission.guard';
|
||||
import { DeleteViewFieldPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/delete-view-field-permission.guard';
|
||||
import { UpdateViewFieldPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/update-view-field-permission.guard';
|
||||
@@ -38,7 +38,7 @@ import { UpdateViewFieldPermissionGuard } from 'src/engine/metadata-modules/view
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@UseFilters(ViewFieldRestApiExceptionFilter)
|
||||
export class ViewFieldController {
|
||||
constructor(private readonly viewFieldV2Service: ViewFieldV2Service) {}
|
||||
constructor(private readonly viewFieldService: ViewFieldService) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(NoPermissionGuard)
|
||||
@@ -47,10 +47,10 @@ export class ViewFieldController {
|
||||
@Query('viewId') viewId?: string,
|
||||
): Promise<ViewFieldEntity[]> {
|
||||
if (viewId) {
|
||||
return this.viewFieldV2Service.findByViewId(workspace.id, viewId);
|
||||
return this.viewFieldService.findByViewId(workspace.id, viewId);
|
||||
}
|
||||
|
||||
return this.viewFieldV2Service.findByWorkspaceId(workspace.id);
|
||||
return this.viewFieldService.findByWorkspaceId(workspace.id);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@@ -59,7 +59,7 @@ export class ViewFieldController {
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewFieldEntity> {
|
||||
const viewField = await this.viewFieldV2Service.findById(id, workspace.id);
|
||||
const viewField = await this.viewFieldService.findById(id, workspace.id);
|
||||
|
||||
if (!isDefined(viewField)) {
|
||||
throw new ViewFieldException(
|
||||
@@ -86,7 +86,7 @@ export class ViewFieldController {
|
||||
@Body() input: UpdateViewFieldInput['update'],
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewFieldDTO> {
|
||||
return await this.viewFieldV2Service.updateOne({
|
||||
return await this.viewFieldService.updateOne({
|
||||
updateViewFieldInput: { id, update: input },
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
@@ -98,7 +98,7 @@ export class ViewFieldController {
|
||||
@Body() input: CreateViewFieldInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewFieldDTO> {
|
||||
return await this.viewFieldV2Service.createOne({
|
||||
return await this.viewFieldService.createOne({
|
||||
createViewFieldInput: input,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
@@ -110,7 +110,7 @@ export class ViewFieldController {
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<{ success: boolean }> {
|
||||
const deletedViewField = await this.viewFieldV2Service.deleteOne({
|
||||
const deletedViewField = await this.viewFieldService.deleteOne({
|
||||
deleteViewFieldInput: { id },
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
+5
@@ -46,6 +46,11 @@ export class CreateViewFieldInput {
|
||||
@Field(() => AggregateOperations, { nullable: true })
|
||||
aggregateOperation?: AggregateOperations;
|
||||
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
viewFieldGroupId?: string;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
|
||||
+5
@@ -35,6 +35,11 @@ class UpdateViewFieldInputUpdates {
|
||||
@IsEnum(AggregateOperations)
|
||||
@Field(() => AggregateOperations, { nullable: true })
|
||||
aggregateOperation?: AggregateOperations;
|
||||
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
viewFieldGroupId?: string | null;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
|
||||
+15
@@ -13,6 +13,7 @@ import {
|
||||
|
||||
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
|
||||
@@ -64,6 +65,9 @@ export class ViewFieldEntity
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
viewId: string;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
viewFieldGroupId: string | null;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@@ -78,4 +82,15 @@ export class ViewFieldEntity
|
||||
})
|
||||
@JoinColumn({ name: 'viewId' })
|
||||
view: Relation<ViewEntity>;
|
||||
|
||||
@ManyToOne(
|
||||
() => ViewFieldGroupEntity,
|
||||
(viewFieldGroup) => viewFieldGroup.viewFields,
|
||||
{
|
||||
onDelete: 'SET NULL',
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: 'viewFieldGroupId' })
|
||||
viewFieldGroup: Relation<ViewFieldGroupEntity> | null;
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,9 +1,9 @@
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Query } from '@nestjs/graphql';
|
||||
|
||||
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { CreateViewFieldInput } from 'src/engine/metadata-modules/view-field/dtos/inputs/create-view-field.input';
|
||||
@@ -12,7 +12,7 @@ import { DestroyViewFieldInput } from 'src/engine/metadata-modules/view-field/dt
|
||||
import { UpdateViewFieldInput } from 'src/engine/metadata-modules/view-field/dtos/inputs/update-view-field.input';
|
||||
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewFieldV2Service } from 'src/engine/metadata-modules/view-field/services/view-field-v2.service';
|
||||
import { ViewFieldService } from 'src/engine/metadata-modules/view-field/services/view-field.service';
|
||||
import { CreateViewFieldPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/create-view-field-permission.guard';
|
||||
import { DeleteViewFieldPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/delete-view-field-permission.guard';
|
||||
import { DestroyViewFieldPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/destroy-view-field-permission.guard';
|
||||
@@ -23,7 +23,7 @@ import { ViewGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/view/
|
||||
@UseFilters(ViewGraphqlApiExceptionFilter)
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
export class ViewFieldResolver {
|
||||
constructor(private readonly viewFieldV2Service: ViewFieldV2Service) {}
|
||||
constructor(private readonly viewFieldService: ViewFieldService) {}
|
||||
|
||||
@Query(() => [ViewFieldDTO])
|
||||
@UseGuards(NoPermissionGuard)
|
||||
@@ -31,7 +31,7 @@ export class ViewFieldResolver {
|
||||
@Args('viewId', { type: () => String }) viewId: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewFieldEntity[]> {
|
||||
return this.viewFieldV2Service.findByViewId(workspace.id, viewId);
|
||||
return this.viewFieldService.findByViewId(workspace.id, viewId);
|
||||
}
|
||||
|
||||
@Query(() => ViewFieldDTO, { nullable: true })
|
||||
@@ -40,7 +40,7 @@ export class ViewFieldResolver {
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewFieldEntity | null> {
|
||||
return this.viewFieldV2Service.findById(id, workspace.id);
|
||||
return this.viewFieldService.findById(id, workspace.id);
|
||||
}
|
||||
|
||||
@Mutation(() => ViewFieldDTO)
|
||||
@@ -49,7 +49,7 @@ export class ViewFieldResolver {
|
||||
@Args('input') updateViewFieldInput: UpdateViewFieldInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldDTO> {
|
||||
return await this.viewFieldV2Service.updateOne({
|
||||
return await this.viewFieldService.updateOne({
|
||||
updateViewFieldInput,
|
||||
workspaceId,
|
||||
});
|
||||
@@ -61,7 +61,7 @@ export class ViewFieldResolver {
|
||||
@Args('input') createViewFieldInput: CreateViewFieldInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldDTO> {
|
||||
return await this.viewFieldV2Service.createOne({
|
||||
return await this.viewFieldService.createOne({
|
||||
createViewFieldInput,
|
||||
workspaceId,
|
||||
});
|
||||
@@ -74,7 +74,7 @@ export class ViewFieldResolver {
|
||||
createViewFieldInputs: CreateViewFieldInput[],
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldDTO[]> {
|
||||
return await this.viewFieldV2Service.createMany({
|
||||
return await this.viewFieldService.createMany({
|
||||
createViewFieldInputs,
|
||||
workspaceId,
|
||||
});
|
||||
@@ -86,7 +86,7 @@ export class ViewFieldResolver {
|
||||
@Args('input') deleteViewFieldInput: DeleteViewFieldInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldDTO> {
|
||||
return await this.viewFieldV2Service.deleteOne({
|
||||
return await this.viewFieldService.deleteOne({
|
||||
deleteViewFieldInput,
|
||||
workspaceId,
|
||||
});
|
||||
@@ -98,7 +98,7 @@ export class ViewFieldResolver {
|
||||
@Args('input') destroyViewFieldInput: DestroyViewFieldInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<ViewFieldDTO> {
|
||||
return await this.viewFieldV2Service.destroyOne({
|
||||
return await this.viewFieldService.destroyOne({
|
||||
destroyViewFieldInput,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
+14
-5
@@ -27,7 +27,7 @@ import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
@Injectable()
|
||||
export class ViewFieldV2Service {
|
||||
export class ViewFieldService {
|
||||
constructor(
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
@@ -76,11 +76,15 @@ export class ViewFieldV2Service {
|
||||
},
|
||||
);
|
||||
|
||||
const { flatFieldMetadataMaps, flatViewMaps } =
|
||||
const { flatFieldMetadataMaps, flatViewMaps, flatViewFieldGroupMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatFieldMetadataMaps', 'flatViewMaps'],
|
||||
flatMapsKeys: [
|
||||
'flatFieldMetadataMaps',
|
||||
'flatViewMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
@@ -91,6 +95,7 @@ export class ViewFieldV2Service {
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatFieldMetadataMaps,
|
||||
flatViewMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -146,17 +151,21 @@ export class ViewFieldV2Service {
|
||||
},
|
||||
);
|
||||
|
||||
const { flatViewFieldMaps: existingFlatViewFieldMaps } =
|
||||
const {
|
||||
flatViewFieldMaps: existingFlatViewFieldMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
} =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewFieldMaps'],
|
||||
flatMapsKeys: ['flatViewFieldMaps', 'flatViewFieldGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const optimisticallyUpdatedFlatView =
|
||||
fromUpdateViewFieldInputToFlatViewFieldToUpdateOrThrow({
|
||||
flatViewFieldMaps: existingFlatViewFieldMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
updateViewFieldInput,
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permi
|
||||
import { ViewFieldController } from 'src/engine/metadata-modules/view-field/controllers/view-field.controller';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewFieldResolver } from 'src/engine/metadata-modules/view-field/resolvers/view-field.resolver';
|
||||
import { ViewFieldV2Service } from 'src/engine/metadata-modules/view-field/services/view-field-v2.service';
|
||||
import { ViewFieldService } from 'src/engine/metadata-modules/view-field/services/view-field.service';
|
||||
import { ViewPermissionsModule } from 'src/engine/metadata-modules/view-permissions/view-permissions.module';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||
@@ -24,7 +24,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
ViewPermissionsModule,
|
||||
],
|
||||
controllers: [ViewFieldController],
|
||||
providers: [ViewFieldResolver, ViewFieldV2Service],
|
||||
exports: [ViewFieldV2Service],
|
||||
providers: [ViewFieldResolver, ViewFieldService],
|
||||
exports: [ViewFieldService],
|
||||
})
|
||||
export class ViewFieldModule {}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
|
||||
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
import { ViewFilterGroupDTO } from 'src/engine/metadata-modules/view-filter-group/dtos/view-filter-group.dto';
|
||||
import { ViewFilterDTO } from 'src/engine/metadata-modules/view-filter/dtos/view-filter.dto';
|
||||
@@ -104,6 +105,9 @@ export class ViewDTO {
|
||||
@Field(() => [ViewGroupDTO])
|
||||
viewGroups?: ViewGroupDTO[];
|
||||
|
||||
@Field(() => [ViewFieldGroupDTO])
|
||||
viewFieldGroups?: ViewFieldGroupDTO[];
|
||||
|
||||
@Field(() => ViewVisibility, {
|
||||
nullable: false,
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity';
|
||||
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
@@ -191,6 +192,12 @@ export class ViewEntity extends SyncableEntity implements Required<ViewEntity> {
|
||||
@OneToMany(() => ViewFieldEntity, (viewField) => viewField.view)
|
||||
viewFields: Relation<ViewFieldEntity[]>;
|
||||
|
||||
@OneToMany(
|
||||
() => ViewFieldGroupEntity,
|
||||
(viewFieldGroup) => viewFieldGroup.view,
|
||||
)
|
||||
viewFieldGroups: Relation<ViewFieldGroupEntity[]>;
|
||||
|
||||
@OneToMany(() => ViewFilterEntity, (viewFilter) => viewFilter.view)
|
||||
viewFilters: Relation<ViewFilterEntity[]>;
|
||||
|
||||
|
||||
@@ -11,19 +11,20 @@ import {
|
||||
import { isArray } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
|
||||
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
|
||||
import { type I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type IDataloaders } from 'src/engine/dataloaders/dataloader.interface';
|
||||
import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
|
||||
import { CustomPermissionGuard } from 'src/engine/guards/custom-permission.guard';
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
import { ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
import { ViewFieldV2Service } from 'src/engine/metadata-modules/view-field/services/view-field-v2.service';
|
||||
import { ViewFieldService } from 'src/engine/metadata-modules/view-field/services/view-field.service';
|
||||
import { ViewFilterGroupDTO } from 'src/engine/metadata-modules/view-filter-group/dtos/view-filter-group.dto';
|
||||
import { ViewFilterGroupService } from 'src/engine/metadata-modules/view-filter-group/services/view-filter-group.service';
|
||||
import { ViewFilterDTO } from 'src/engine/metadata-modules/view-filter/dtos/view-filter.dto';
|
||||
@@ -56,7 +57,7 @@ export class ViewResolver {
|
||||
private readonly viewGroupService: ViewGroupService,
|
||||
private readonly i18nService: I18nService,
|
||||
|
||||
private readonly viewFieldV2Service: ViewFieldV2Service,
|
||||
private readonly viewFieldService: ViewFieldService,
|
||||
) {}
|
||||
|
||||
@ResolveField(() => String)
|
||||
@@ -209,7 +210,7 @@ export class ViewResolver {
|
||||
return view.viewFields;
|
||||
}
|
||||
|
||||
return this.viewFieldV2Service.findByViewId(workspace.id, view.id);
|
||||
return this.viewFieldService.findByViewId(workspace.id, view.id);
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewFilterDTO])
|
||||
@@ -259,4 +260,20 @@ export class ViewResolver {
|
||||
|
||||
return this.viewGroupService.findByViewId(workspace.id, view.id);
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewFieldGroupDTO])
|
||||
async viewFieldGroups(
|
||||
@Parent() view: ViewDTO,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(view.viewFieldGroups)) {
|
||||
return view.viewFieldGroups;
|
||||
}
|
||||
|
||||
return context.loaders.viewFieldGroupsByViewIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewId: view.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+20
@@ -7,6 +7,10 @@ import {
|
||||
NotFoundError,
|
||||
UserInputError,
|
||||
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import {
|
||||
ViewFieldGroupException,
|
||||
ViewFieldGroupExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view-field-group/exceptions/view-field-group.exception';
|
||||
import {
|
||||
ViewFieldException,
|
||||
ViewFieldExceptionCode,
|
||||
@@ -77,6 +81,22 @@ export const viewGraphqlApiExceptionHandler = (error: Error, i18n: I18n) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (error instanceof ViewFieldGroupException) {
|
||||
switch (error.code) {
|
||||
case ViewFieldGroupExceptionCode.VIEW_FIELD_GROUP_NOT_FOUND:
|
||||
throw new NotFoundError(error.message);
|
||||
case ViewFieldGroupExceptionCode.VIEW_NOT_FOUND:
|
||||
throw new NotFoundError(error.message);
|
||||
case ViewFieldGroupExceptionCode.INVALID_VIEW_FIELD_GROUP_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:
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
import { SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
|
||||
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
|
||||
import { ViewFieldGroupException } from 'src/engine/metadata-modules/view-field-group/exceptions/view-field-group.exception';
|
||||
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';
|
||||
@@ -35,6 +36,7 @@ export class ViewGraphqlApiExceptionFilter implements ExceptionFilter {
|
||||
exception:
|
||||
| ViewException
|
||||
| ViewFieldException
|
||||
| ViewFieldGroupException
|
||||
| ViewFilterException
|
||||
| ViewFilterGroupException
|
||||
| ViewGroupException
|
||||
|
||||
@@ -7,6 +7,7 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata
|
||||
import { FlatViewModule } from 'src/engine/metadata-modules/flat-view/flat-view.module';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
|
||||
import { ViewFieldGroupModule } from 'src/engine/metadata-modules/view-field-group/view-field-group.module';
|
||||
import { ViewFieldModule } from 'src/engine/metadata-modules/view-field/view-field.module';
|
||||
import { ViewFilterGroupModule } from 'src/engine/metadata-modules/view-filter-group/view-filter-group.module';
|
||||
import { ViewFilterModule } from 'src/engine/metadata-modules/view-filter/view-filter.module';
|
||||
@@ -27,6 +28,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
TypeOrmModule.forFeature([ViewEntity]),
|
||||
ViewPermissionsModule,
|
||||
ViewFieldModule,
|
||||
ViewFieldGroupModule,
|
||||
ViewFilterModule,
|
||||
ViewFilterGroupModule,
|
||||
ViewGroupModule,
|
||||
|
||||
Reference in New Issue
Block a user