breaking (soft) - Migrate viewGroup.fieldMetadataId -> view.mainGroupByFieldMetadataId (2/3) (#16277)
Should be merged once https://github.com/twentyhq/twenty/pull/16206 has been released + command run to prod In this PR - Remove usage of viewGroup.fieldMetadataId, both in BE and FE states. - But we still need to properly populate it until we fully remove viewGroup.fieldMetadataId from db and ORM entity (upcoming 3rd PR out of 3). fieldMetadataId was removed from CoreViewGroup type and CreateViewGroupInput and is determined BE-side based on the associated view's mainGroupByFieldMetadataId. **I expect this means a downtime on viewGroup creation, until both FE and BE are deployed and cache is flushed.** This seems acceptable to me as it only regards viewGroup creation. - this information is replaced by view.mainGroupByFieldMetadataID - Handle view group creation, update and deletion in the BE as a side-effect of a view creation, update or deletion. Optimistic effects are still used - Add validation at view creation or update regarding mainGroupByFieldMetadata Left to do in 3rd PR - Remove viewGroup.fieldMetadataId from db and ORM entity - Restore feature allowing to update an existing grouped view's group by field (already OK on BE side but need to rebuild FE optimistic)
This commit is contained in:
+29
-3
@@ -1,6 +1,12 @@
|
||||
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils';
|
||||
import {
|
||||
isDefined,
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type';
|
||||
import { computeFlatViewGroupsOnViewCreate } from 'src/engine/metadata-modules/flat-view-group/utils/compute-flat-view-groups-on-view-create.util';
|
||||
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';
|
||||
@@ -12,12 +18,17 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
workspaceId,
|
||||
createdByUserWorkspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatFieldMetadataMaps,
|
||||
}: {
|
||||
createViewInput: CreateViewInput;
|
||||
workspaceId: string;
|
||||
createdByUserWorkspaceId?: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
}): FlatView => {
|
||||
flatFieldMetadataMaps: AllFlatEntityMaps['flatFieldMetadataMaps'];
|
||||
}): {
|
||||
flatViewToCreate: FlatView;
|
||||
flatViewGroupsToCreate: FlatViewGroup[];
|
||||
} => {
|
||||
const { objectMetadataId, ...createViewInput } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawCreateViewInput,
|
||||
@@ -27,7 +38,7 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
const createdAt = new Date();
|
||||
const viewId = createViewInput.id ?? v4();
|
||||
|
||||
return {
|
||||
const flatViewToCreate = {
|
||||
id: viewId,
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
@@ -58,4 +69,19 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
viewGroupIds: [],
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
};
|
||||
|
||||
let flatViewGroupsToCreate: FlatViewGroup[] = [];
|
||||
|
||||
if (isDefined(flatViewToCreate.mainGroupByFieldMetadataId)) {
|
||||
flatViewGroupsToCreate = computeFlatViewGroupsOnViewCreate({
|
||||
flatViewToCreateId: flatViewToCreate.id,
|
||||
mainGroupByFieldMetadataId: flatViewToCreate.mainGroupByFieldMetadataId,
|
||||
flatFieldMetadataMaps,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
flatViewToCreate,
|
||||
flatViewGroupsToCreate,
|
||||
};
|
||||
};
|
||||
|
||||
+43
-2
@@ -5,9 +5,14 @@ import {
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatViewGroupMaps } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group-maps.type';
|
||||
import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type';
|
||||
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 { handleFlatViewUpdateSideEffect } from 'src/engine/metadata-modules/flat-view/utils/handle-flat-view-update-side-effect.util';
|
||||
import { type UpdateViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/update-view.input';
|
||||
import {
|
||||
ViewException,
|
||||
@@ -18,10 +23,20 @@ import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-
|
||||
export const fromUpdateViewInputToFlatViewToUpdateOrThrow = ({
|
||||
updateViewInput: rawUpdateViewInput,
|
||||
flatViewMaps,
|
||||
flatViewGroupMaps,
|
||||
flatFieldMetadataMaps,
|
||||
userWorkspaceId,
|
||||
}: {
|
||||
updateViewInput: UpdateViewInput;
|
||||
flatViewMaps: FlatViewMaps;
|
||||
}): FlatView => {
|
||||
flatViewGroupMaps: FlatViewGroupMaps;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
userWorkspaceId?: string;
|
||||
}): {
|
||||
flatViewToUpdate: FlatView;
|
||||
flatViewGroupsToDelete: FlatViewGroup[];
|
||||
flatViewGroupsToCreate: FlatViewGroup[];
|
||||
} => {
|
||||
const { id: viewToUpdateId } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawUpdateViewInput,
|
||||
@@ -42,9 +57,35 @@ export const fromUpdateViewInputToFlatViewToUpdateOrThrow = ({
|
||||
FLAT_VIEW_EDITABLE_PROPERTIES,
|
||||
);
|
||||
|
||||
return mergeUpdateInExistingRecord({
|
||||
const flatViewToUpdate = mergeUpdateInExistingRecord({
|
||||
existing: existingFlatViewToUpdate,
|
||||
properties: FLAT_VIEW_EDITABLE_PROPERTIES,
|
||||
update: updatedEditableFieldProperties,
|
||||
});
|
||||
|
||||
// If changing visibility from WORKSPACE to UNLISTED, ensure createdByUserWorkspaceId is set
|
||||
// This prevents the view from disappearing for the user making the change
|
||||
if (
|
||||
isDefined(rawUpdateViewInput.visibility) &&
|
||||
rawUpdateViewInput.visibility === 'UNLISTED' &&
|
||||
existingFlatViewToUpdate.visibility === 'WORKSPACE' &&
|
||||
isDefined(userWorkspaceId)
|
||||
) {
|
||||
// Re-allocate the view to the current user
|
||||
flatViewToUpdate.createdByUserWorkspaceId = userWorkspaceId;
|
||||
}
|
||||
|
||||
const { flatViewGroupsToDelete, flatViewGroupsToCreate } =
|
||||
handleFlatViewUpdateSideEffect({
|
||||
fromFlatView: existingFlatViewToUpdate,
|
||||
toFlatView: flatViewToUpdate,
|
||||
flatViewGroupMaps: flatViewGroupMaps,
|
||||
flatFieldMetadataMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
return {
|
||||
flatViewToUpdate,
|
||||
flatViewGroupsToDelete,
|
||||
flatViewGroupsToCreate,
|
||||
};
|
||||
};
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type';
|
||||
import { computeFlatViewGroupsOnViewCreate } from 'src/engine/metadata-modules/flat-view-group/utils/compute-flat-view-groups-on-view-create.util';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
|
||||
export type FlatViewUpdateSideEffects = {
|
||||
flatViewGroupsToDelete: FlatViewGroup[];
|
||||
flatViewGroupsToCreate: FlatViewGroup[];
|
||||
};
|
||||
|
||||
type HandleFlatViewUpdateSideEffectArgs = FromTo<FlatView, 'flatView'> &
|
||||
Pick<AllFlatEntityMaps, 'flatViewGroupMaps' | 'flatFieldMetadataMaps'>;
|
||||
|
||||
export const FLAT_VIEW_UPDATE_EMPTY_SIDE_EFFECTS: FlatViewUpdateSideEffects = {
|
||||
flatViewGroupsToDelete: [],
|
||||
flatViewGroupsToCreate: [],
|
||||
};
|
||||
|
||||
export const handleFlatViewUpdateSideEffect = ({
|
||||
fromFlatView,
|
||||
toFlatView,
|
||||
flatViewGroupMaps,
|
||||
flatFieldMetadataMaps,
|
||||
}: HandleFlatViewUpdateSideEffectArgs): FlatViewUpdateSideEffects => {
|
||||
const sideEffectResult = structuredClone(FLAT_VIEW_UPDATE_EMPTY_SIDE_EFFECTS);
|
||||
|
||||
const newMainGroupByFieldMetadataId = toFlatView.mainGroupByFieldMetadataId;
|
||||
|
||||
const hasMainGroupByFieldMetadataIdChanged =
|
||||
fromFlatView.mainGroupByFieldMetadataId !== newMainGroupByFieldMetadataId;
|
||||
|
||||
if (!hasMainGroupByFieldMetadataIdChanged) {
|
||||
return sideEffectResult;
|
||||
}
|
||||
|
||||
if (fromFlatView.viewGroupIds.length > 0) {
|
||||
sideEffectResult.flatViewGroupsToDelete =
|
||||
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityIds: fromFlatView.viewGroupIds,
|
||||
flatEntityMaps: flatViewGroupMaps,
|
||||
});
|
||||
}
|
||||
|
||||
if (!isDefined(newMainGroupByFieldMetadataId)) {
|
||||
return sideEffectResult;
|
||||
}
|
||||
|
||||
sideEffectResult.flatViewGroupsToCreate = computeFlatViewGroupsOnViewCreate({
|
||||
flatViewToCreateId: toFlatView.id,
|
||||
mainGroupByFieldMetadataId: newMainGroupByFieldMetadataId,
|
||||
flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
return sideEffectResult;
|
||||
};
|
||||
Reference in New Issue
Block a user