ViewGroup and ViewFilters side effect in v2 (#15096)

# Introduction

### Summary
Implements side effect handling for `ViewGroup` and `ViewFilters` when
field metadata is updated in the v2 architecture. This ensures that
view-related records are properly maintained when enum field options are
modified, deleted, or created.

### Side effects
- **Side Effect System**: Added side effect handling for field metadata
updates that manages related view groups and view filters
- **Enum Field Updates**: When enum field options are modified, the
system now:
- **View Groups**: Creates new groups for added options, updates
existing groups for modified options, and deletes groups for removed
options
- **View Filters**: Updates filter values to reflect option changes and
removes filters that reference deleted options

### Enum runner fix
Update now works for both atomic enum and array enum ( multi select for
instance )

### Compute flat entity maps from to
Standardized this method usage across v2 services
Next step is to require dependencies dynamically

## Conclusion
closes https://github.com/twentyhq/core-team-issues/issues/1649
This commit is contained in:
Paul Rastoin
2025-10-17 17:09:26 +02:00
committed by GitHub
parent 4f1623ff76
commit 3462a2e288
58 changed files with 3108 additions and 1075 deletions
@@ -0,0 +1,39 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type';
type FlatViewGroupsByViewId = {
flatViewGroupRecordByViewId: Record<string, Record<string, FlatViewGroup>>;
highestViewGroupPositionByViewId: Record<string, number>;
};
export const reduceFlatViewGroupsByViewId = ({
flatViewGroups,
}: {
flatViewGroups: FlatViewGroup[];
}): FlatViewGroupsByViewId => {
const initialAccumulator: FlatViewGroupsByViewId = {
flatViewGroupRecordByViewId: {},
highestViewGroupPositionByViewId: {},
};
return flatViewGroups.reduce((accumulator, flatViewGroup) => {
const accumulatorHighestPosition =
accumulator.highestViewGroupPositionByViewId[flatViewGroup.viewId];
return {
flatViewGroupRecordByViewId: {
...accumulator.flatViewGroupRecordByViewId,
[flatViewGroup.viewId]: {
...accumulator.flatViewGroupRecordByViewId[flatViewGroup.viewId],
[flatViewGroup.id]: flatViewGroup,
},
},
highestViewGroupPositionByViewId: {
...accumulator.highestViewGroupPositionByViewId,
[flatViewGroup.viewId]: isDefined(accumulatorHighestPosition)
? Math.max(accumulatorHighestPosition, flatViewGroup.position)
: flatViewGroup.position,
},
};
}, initialAccumulator);
};