Implemented view filter group CRUD hooks and utils (#10551)
This PR implements hooks and utils logic for handling CRUD and view filter group comparison. The main hook is useAreViewFilterGroupsDifferentFromRecordFilterGroups, like view filters and view sorts. Inside this hook we implement getViewFilterGroupsToCreate, getViewFilterGroupsToDelete and getViewFilterGroupsToUpdate. All of those come with their unit tests. In this PR we also introduce a new util to prevent nasty bugs happening when we compare undefined === null, This util is called compareStrictlyExceptForNullAndUndefined and it should replace every strict equality comparison between values that can be null or undefined (which we have a lot) This could be enforced by a custom ESLint rule, the autofix may also be implemented (maybe the util should be put in twenty-shared ?)
This commit is contained in:
@ -0,0 +1,21 @@
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const areViewFilterGroupsEqual = (
|
||||
viewFilterGroupA: ViewFilterGroup,
|
||||
viewFilterGroupB: ViewFilterGroup,
|
||||
) => {
|
||||
const propertiesToCompare: (keyof ViewFilterGroup)[] = [
|
||||
'positionInViewFilterGroup',
|
||||
'logicalOperator',
|
||||
'parentViewFilterGroupId',
|
||||
'viewId',
|
||||
];
|
||||
|
||||
return propertiesToCompare.every((property) =>
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
viewFilterGroupA[property],
|
||||
viewFilterGroupB[property],
|
||||
),
|
||||
);
|
||||
};
|
||||
@ -1,4 +1,5 @@
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const areViewFiltersEqual = (
|
||||
viewFilterA: ViewFilter,
|
||||
@ -13,7 +14,10 @@ export const areViewFiltersEqual = (
|
||||
'operand',
|
||||
];
|
||||
|
||||
return propertiesToCompare.every(
|
||||
(property) => viewFilterA[property] === viewFilterB[property],
|
||||
return propertiesToCompare.every((property) =>
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
viewFilterA[property],
|
||||
viewFilterB[property],
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { ViewSort } from '@/views/types/ViewSort';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const areViewSortsEqual = (viewSortA: ViewSort, viewSortB: ViewSort) => {
|
||||
const propertiesToCompare: (keyof ViewSort)[] = [
|
||||
@ -6,7 +7,10 @@ export const areViewSortsEqual = (viewSortA: ViewSort, viewSortB: ViewSort) => {
|
||||
'direction',
|
||||
];
|
||||
|
||||
return propertiesToCompare.every(
|
||||
(property) => viewSortA[property] === viewSortB[property],
|
||||
return propertiesToCompare.every((property) =>
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
viewSortA[property],
|
||||
viewSortB[property],
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const getViewFilterGroupsToCreate = (
|
||||
currentViewFilterGroups: ViewFilterGroup[],
|
||||
newViewFilterGroups: ViewFilterGroup[],
|
||||
) => {
|
||||
return newViewFilterGroups.filter((newViewFilterGroup) => {
|
||||
const correspondingViewFilterGroup = currentViewFilterGroups.find(
|
||||
(currentViewFilterGroup) =>
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
currentViewFilterGroup.id,
|
||||
newViewFilterGroup.id,
|
||||
),
|
||||
);
|
||||
|
||||
const shouldCreateBecauseViewFilterGroupIsNew = !isDefined(
|
||||
correspondingViewFilterGroup,
|
||||
);
|
||||
|
||||
return shouldCreateBecauseViewFilterGroupIsNew;
|
||||
});
|
||||
};
|
||||
@ -0,0 +1,17 @@
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const getViewFilterGroupsToDelete = (
|
||||
currentViewFilterGroups: ViewFilterGroup[],
|
||||
newViewFilterGroups: ViewFilterGroup[],
|
||||
) => {
|
||||
return currentViewFilterGroups.filter(
|
||||
(currentViewFilterGroup) =>
|
||||
!newViewFilterGroups.some((newViewFilterGroup) =>
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
newViewFilterGroup.id,
|
||||
currentViewFilterGroup.id,
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { areViewFilterGroupsEqual } from '@/views/utils/areViewFilterGroupsEqual';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
|
||||
|
||||
export const getViewFilterGroupsToUpdate = (
|
||||
currentViewFilterGroups: ViewFilterGroup[],
|
||||
newViewFilterGroups: ViewFilterGroup[],
|
||||
) => {
|
||||
return newViewFilterGroups.filter((newViewFilterGroup) => {
|
||||
const correspondingViewFilterGroup = currentViewFilterGroups.find(
|
||||
(currentViewFilterGroup) =>
|
||||
compareStrictlyExceptForNullAndUndefined(
|
||||
currentViewFilterGroup.id,
|
||||
newViewFilterGroup.id,
|
||||
),
|
||||
);
|
||||
|
||||
if (!isDefined(correspondingViewFilterGroup)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const shouldUpdateBecauseViewFilterGroupIsDifferent =
|
||||
!areViewFilterGroupsEqual(
|
||||
newViewFilterGroup,
|
||||
correspondingViewFilterGroup,
|
||||
);
|
||||
|
||||
return shouldUpdateBecauseViewFilterGroupIsDifferent;
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user