[Requires "warm" cache flush (no immediate downtime before flush)] Migrate viewGroup.fieldMetadataId -> view.mainGroupByFieldMetadataId (1/3) (#16206)

In this PR (1/3)
- introduce view.mainGroupByFieldMetadataId as the new reference
determining which fieldMetadataId is used in a grouped view, in order to
deprecate viewGroup.fieldMetadataId which creates inconsistencies.
view.mainGroupByFieldMetadataId is now filled at every view creation,
though not in use yet.
- Introduce a command to backfill view.mainGroupByFieldMetadataId for
existing views + delete all viewGroup.fieldMetadataId with a
fieldMetadataId that is not view.mainGroupByFieldMetadataId. (It should
concern 37 active workspaces)
- Temporarily disable the option to change a grouped view's
fieldMetadataId as for now it creates inconsistencies. This feature can
be reintroduced when we have done the full migration.

In a next PR
- (2/3) use view.mainGroupByFieldMetadataId instead of
viewGroup.fieldMetadataId. In FE we may keep viewGroup.fieldMetadataId
as a state (TBD). View groups will now be created / deleted as a side
effect of view's mainGroupByFieldMetadataId update.
- (3/3) remove viewGroup.fieldMetadataId

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Marie
2025-12-02 16:31:07 +01:00
committed by GitHub
parent aa729a2a0a
commit 77409b6eb2
71 changed files with 484 additions and 99 deletions
@@ -77,7 +77,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
id,
name,
icon,
kanbanFieldMetadataId,
mainGroupByFieldMetadataId,
calendarFieldMetadataId,
type,
visibility,
@@ -87,7 +87,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
| 'id'
| 'name'
| 'icon'
| 'kanbanFieldMetadataId'
| 'mainGroupByFieldMetadataId'
| 'calendarFieldMetadataId'
| 'type'
| 'visibility'
@@ -133,6 +133,9 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
shouldCopyFiltersAndSortsAndAggregate
? sourceView.kanbanAggregateOperationFieldMetadataId
: undefined,
mainGroupByFieldMetadataId: shouldCopyFiltersAndSortsAndAggregate
? sourceView.mainGroupByFieldMetadataId
: mainGroupByFieldMetadataId,
type: convertViewTypeToCore(viewType),
objectMetadataId: sourceView.objectMetadataId,
openRecordIn: convertViewOpenRecordInToCore(
@@ -179,19 +182,19 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
}
if (type === ViewType.Kanban) {
if (!isDefined(kanbanFieldMetadataId)) {
if (!isDefined(mainGroupByFieldMetadataId)) {
throw new Error('Kanban view must have a kanban field');
}
const viewGroupsToCreate =
objectMetadataItem.fields
?.find((field) => field.id === kanbanFieldMetadataId)
?.find((field) => field.id === mainGroupByFieldMetadataId)
?.options?.map(
(option, index) =>
({
id: v4(),
__typename: 'ViewGroup',
fieldMetadataId: kanbanFieldMetadataId,
fieldMetadataId: mainGroupByFieldMetadataId,
fieldValue: option.value,
isVisible: true,
position: index,
@@ -204,7 +207,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
fieldValue: '',
position: viewGroupsToCreate.length,
isVisible: true,
fieldMetadataId: kanbanFieldMetadataId,
fieldMetadataId: mainGroupByFieldMetadataId,
} satisfies ViewGroup);
const groupResult = await createViewGroups({