Move view in metadata-modules/ and create atomic folder + module for each view entity (#14990)
# Introduction Preparing view-filter and view-group introduction in v2 core engine Moving view from `core-modules` to `metadata-modules` ## What happened ### Created dedicated modules for each view entity: - ViewFieldModule - ViewFilterModule - ViewFilterGroupModule - ViewGroupModule - ViewSortModule ### Each module is now completely independent with its own: - Controller - Resolver - Service - Entity ### Created dedicated abstraction metadata module folder for: - flat-view-field - flat-view ### Dependencies - Eleminated circular dep on ViewModule to all others ones - Granular import not importing the whole viewModule anymore everywhere close https://github.com/twentyhq/core-team-issues/issues/1703
This commit is contained in:
+56
@@ -0,0 +1,56 @@
|
||||
import diff from 'microdiff';
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { FLAT_VIEW_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-view/constants/flat-view-properties-to-compare.constant';
|
||||
import { type FlatViewPropertiesToCompare } from 'src/engine/metadata-modules/flat-view/types/flat-view-properties-to-compare.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type UpdateViewAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
|
||||
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||
|
||||
type GetWorkspaceMigrationUpdateViewActionArgs = FromTo<FlatView, 'FlatView'>;
|
||||
|
||||
export const compareTwoFlatView = ({
|
||||
fromFlatView,
|
||||
toFlatView,
|
||||
}: GetWorkspaceMigrationUpdateViewActionArgs) => {
|
||||
const transformMetadataForComparisonParameters = {
|
||||
shouldIgnoreProperty: (property: string) =>
|
||||
!FLAT_VIEW_PROPERTIES_TO_COMPARE.includes(
|
||||
property as FlatViewPropertiesToCompare,
|
||||
),
|
||||
propertiesToStringify: [],
|
||||
};
|
||||
const fromCompare = transformMetadataForComparison(
|
||||
fromFlatView,
|
||||
transformMetadataForComparisonParameters,
|
||||
);
|
||||
const toCompare = transformMetadataForComparison(
|
||||
toFlatView,
|
||||
transformMetadataForComparisonParameters,
|
||||
);
|
||||
|
||||
const flatViewDifferences = diff(fromCompare, toCompare);
|
||||
|
||||
return flatViewDifferences.flatMap<UpdateViewAction['updates'][number]>(
|
||||
(difference) => {
|
||||
switch (difference.type) {
|
||||
case 'CHANGE': {
|
||||
const { oldValue, path, value } = difference;
|
||||
const property = path[0] as FlatViewPropertiesToCompare;
|
||||
|
||||
return {
|
||||
from: oldValue,
|
||||
to: value,
|
||||
property,
|
||||
};
|
||||
}
|
||||
case 'CREATE':
|
||||
case 'REMOVE':
|
||||
default: {
|
||||
// Should never occurs, we should only provide null never undefined and so on
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type CreateViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/create-view.input';
|
||||
import { ViewOpenRecordIn } from 'src/engine/metadata-modules/view/enums/view-open-record-in';
|
||||
import { ViewType } from 'src/engine/metadata-modules/view/enums/view-type.enum';
|
||||
|
||||
export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
createViewInput: rawCreateViewInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
createViewInput: CreateViewInput;
|
||||
workspaceId: string;
|
||||
}): FlatView => {
|
||||
const { objectMetadataId, ...createViewInput } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawCreateViewInput,
|
||||
['id', 'name', 'objectMetadataId'],
|
||||
);
|
||||
|
||||
const createdAt = new Date();
|
||||
|
||||
return {
|
||||
id: createViewInput.id ?? v4(),
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
name: createViewInput.name,
|
||||
createdAt: createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
isCustom: true,
|
||||
anyFieldFilterValue: createViewInput.anyFieldFilterValue ?? null,
|
||||
calendarFieldMetadataId: createViewInput.calendarFieldMetadataId ?? null,
|
||||
calendarLayout: createViewInput.calendarLayout ?? null,
|
||||
icon: createViewInput.icon,
|
||||
isCompact: createViewInput.isCompact ?? false,
|
||||
kanbanAggregateOperation: createViewInput.kanbanAggregateOperation ?? null,
|
||||
kanbanAggregateOperationFieldMetadataId:
|
||||
createViewInput.kanbanAggregateOperationFieldMetadataId ?? null,
|
||||
key: createViewInput.key ?? null,
|
||||
openRecordIn: createViewInput.openRecordIn ?? ViewOpenRecordIn.SIDE_PANEL,
|
||||
position: createViewInput.position ?? 0,
|
||||
type: createViewInput.type ?? ViewType.TABLE,
|
||||
universalIdentifier: v4(),
|
||||
viewFieldIds: [],
|
||||
};
|
||||
};
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatViewMaps } from 'src/engine/metadata-modules/flat-view/types/flat-view-maps.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type DeleteViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/delete-view.input';
|
||||
import {
|
||||
ViewException,
|
||||
ViewExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view/exceptions/view.exception';
|
||||
|
||||
export const fromDeleteViewInputToFlatViewOrThrow = ({
|
||||
deleteViewInput: rawDeleteViewInput,
|
||||
flatViewMaps,
|
||||
}: {
|
||||
deleteViewInput: DeleteViewInput;
|
||||
flatViewMaps: FlatViewMaps;
|
||||
}): FlatView => {
|
||||
const { id: viewId } = extractAndSanitizeObjectStringFields(
|
||||
rawDeleteViewInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewToDelete = flatViewMaps.byId[viewId];
|
||||
|
||||
if (!isDefined(existingFlatViewToDelete)) {
|
||||
throw new ViewException(
|
||||
t`View to delete not found`,
|
||||
ViewExceptionCode.VIEW_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatViewToDelete,
|
||||
deletedAt: new Date(),
|
||||
};
|
||||
};
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatViewMaps } from 'src/engine/metadata-modules/flat-view/types/flat-view-maps.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type DestroyViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/destroy-view.input';
|
||||
import {
|
||||
ViewException,
|
||||
ViewExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view/exceptions/view.exception';
|
||||
|
||||
export const fromDestroyViewInputToFlatViewOrThrow = ({
|
||||
destroyViewInput: rawDestroyViewInput,
|
||||
flatViewMaps,
|
||||
}: {
|
||||
destroyViewInput: DestroyViewInput;
|
||||
flatViewMaps: FlatViewMaps;
|
||||
}): FlatView => {
|
||||
const { id: viewId } = extractAndSanitizeObjectStringFields(
|
||||
rawDestroyViewInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewToDestroy = flatViewMaps.byId[viewId];
|
||||
|
||||
if (!isDefined(existingFlatViewToDestroy)) {
|
||||
throw new ViewException(
|
||||
t`View to destroy not found`,
|
||||
ViewExceptionCode.VIEW_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return existingFlatViewToDestroy;
|
||||
};
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { ViewOpenRecordIn } from 'src/engine/metadata-modules/view/enums/view-open-record-in';
|
||||
import { ViewType } from 'src/engine/metadata-modules/view/enums/view-type.enum';
|
||||
|
||||
export const fromPartialFlatViewToFlatViewWithDefault = (
|
||||
partialFlatView: Partial<FlatView>,
|
||||
): FlatView => {
|
||||
const createdAt = new Date();
|
||||
const viewId = partialFlatView.id ?? v4();
|
||||
|
||||
return {
|
||||
...partialFlatView,
|
||||
id: viewId,
|
||||
name: partialFlatView.name ?? '',
|
||||
objectMetadataId: partialFlatView.objectMetadataId ?? '',
|
||||
type: partialFlatView.type ?? ViewType.TABLE,
|
||||
key: partialFlatView.key ?? null,
|
||||
icon: partialFlatView.icon ?? '',
|
||||
position: partialFlatView.position ?? 0,
|
||||
isCompact: partialFlatView.isCompact ?? false,
|
||||
isCustom: partialFlatView.isCustom ?? false,
|
||||
openRecordIn: partialFlatView.openRecordIn ?? ViewOpenRecordIn.SIDE_PANEL,
|
||||
kanbanAggregateOperation: partialFlatView.kanbanAggregateOperation ?? null,
|
||||
kanbanAggregateOperationFieldMetadataId:
|
||||
partialFlatView.kanbanAggregateOperationFieldMetadataId ?? null,
|
||||
workspaceId: partialFlatView.workspaceId ?? '',
|
||||
createdAt: createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
anyFieldFilterValue: partialFlatView.anyFieldFilterValue ?? null,
|
||||
universalIdentifier: partialFlatView.universalIdentifier ?? viewId,
|
||||
viewFieldIds: partialFlatView.viewFieldIds ?? [],
|
||||
calendarLayout: partialFlatView.calendarLayout ?? null,
|
||||
calendarFieldMetadataId: partialFlatView.calendarFieldMetadataId ?? null,
|
||||
};
|
||||
};
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { FLAT_VIEW_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view/constants/flat-view-editable-properties.constant';
|
||||
import { type FlatViewMaps } from 'src/engine/metadata-modules/flat-view/types/flat-view-maps.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type UpdateViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/update-view.input';
|
||||
import {
|
||||
ViewException,
|
||||
ViewExceptionCode,
|
||||
} from 'src/engine/metadata-modules/view/exceptions/view.exception';
|
||||
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
|
||||
|
||||
export const fromUpdateViewInputToFlatViewToUpdateOrThrow = ({
|
||||
updateViewInput: rawUpdateViewInput,
|
||||
flatViewMaps,
|
||||
}: {
|
||||
updateViewInput: UpdateViewInput;
|
||||
flatViewMaps: FlatViewMaps;
|
||||
}): FlatView => {
|
||||
const { id: viewToUpdateId } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawUpdateViewInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatViewToUpdate = flatViewMaps.byId[viewToUpdateId];
|
||||
|
||||
if (!isDefined(existingFlatViewToUpdate)) {
|
||||
throw new ViewException(
|
||||
t`View to update not found`,
|
||||
ViewExceptionCode.VIEW_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const updatedEditableFieldProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateViewInput,
|
||||
FLAT_VIEW_EDITABLE_PROPERTIES,
|
||||
);
|
||||
|
||||
return mergeUpdateInExistingRecord({
|
||||
existing: existingFlatViewToUpdate,
|
||||
properties: FLAT_VIEW_EDITABLE_PROPERTIES,
|
||||
update: updatedEditableFieldProperties,
|
||||
});
|
||||
};
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { removePropertiesFromRecord } from 'twenty-shared/utils';
|
||||
|
||||
import { VIEW_ENTITY_RELATION_PROPERTIES } from 'src/engine/metadata-modules/flat-view/constants/view-entity-relation-properties.constant';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
|
||||
export const fromViewEntityToFlatView = (viewEntity: ViewEntity): FlatView => {
|
||||
const viewEntityWithoutRelations = removePropertiesFromRecord(
|
||||
viewEntity,
|
||||
VIEW_ENTITY_RELATION_PROPERTIES,
|
||||
);
|
||||
|
||||
return {
|
||||
...viewEntityWithoutRelations,
|
||||
universalIdentifier:
|
||||
viewEntityWithoutRelations.universalIdentifier ??
|
||||
viewEntityWithoutRelations.id,
|
||||
viewFieldIds: viewEntity.viewFields.map((viewField) => viewField.id) ?? [],
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user