Feat: Advanced filter (#7700)

Design:


![twenty-advanced-filters-design](https://github.com/user-attachments/assets/7d99971c-9ee1-4a78-a2fb-7ae5a9b3a836)

Not ready to be merged yet!

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
ad-elias
2024-10-24 16:59:59 +02:00
committed by GitHub
parent 1dfeba39eb
commit 315820ec86
99 changed files with 3349 additions and 1079 deletions

View File

@ -0,0 +1,214 @@
import { useApolloClient } from '@apollo/client';
import { useCallback } from 'react';
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
import { triggerDestroyRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDestroyRecordsOptimisticEffect';
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
import { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
import { useDestroyOneRecordMutation } from '@/object-record/hooks/useDestroyOneRecordMutation';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { GraphQLView } from '@/views/types/GraphQLView';
import { ViewFilterGroup } from '@/views/types/ViewFilterGroup';
import { isDefined } from 'twenty-ui';
export const usePersistViewFilterGroupRecords = () => {
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const getRecordFromCache = useGetRecordFromCache({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { destroyOneRecordMutation } = useDestroyOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { createOneRecordMutation } = useCreateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { updateOneRecordMutation } = useUpdateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { objectMetadataItems } = useObjectMetadataItems();
const apolloClient = useApolloClient();
const createViewFilterGroupRecord = useCallback(
async (viewFilterGroup: ViewFilterGroup, view: GraphQLView) => {
const result = await apolloClient.mutate<{
createViewFilterGroup: ViewFilterGroup;
}>({
mutation: createOneRecordMutation,
variables: {
input: {
id: viewFilterGroup.id,
viewId: view.id,
parentViewFilterGroupId: viewFilterGroup.parentViewFilterGroupId,
logicalOperator: viewFilterGroup.logicalOperator,
positionInViewFilterGroup:
viewFilterGroup.positionInViewFilterGroup,
},
},
update: (cache, { data }) => {
const record = data?.createViewFilterGroup;
if (!record) return;
triggerCreateRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToCreate: [record],
objectMetadataItems,
});
},
});
if (!result.data) {
throw new Error('Failed to create view filter group');
}
return { newRecordId: result.data.createViewFilterGroup.id };
},
[
apolloClient,
createOneRecordMutation,
objectMetadataItem,
objectMetadataItems,
],
);
const createViewFilterGroupRecords = useCallback(
async (viewFilterGroupsToCreate: ViewFilterGroup[], view: GraphQLView) => {
if (!viewFilterGroupsToCreate.length) return [];
const oldToNewId = new Map<string, string>();
for (const viewFilterGroupToCreate of viewFilterGroupsToCreate) {
const newParentViewFilterGroupId = isDefined(
viewFilterGroupToCreate.parentViewFilterGroupId,
)
? (oldToNewId.get(viewFilterGroupToCreate.parentViewFilterGroupId) ??
viewFilterGroupToCreate.parentViewFilterGroupId)
: undefined;
const { newRecordId } = await createViewFilterGroupRecord(
{
...viewFilterGroupToCreate,
parentViewFilterGroupId: newParentViewFilterGroupId,
},
view,
);
oldToNewId.set(viewFilterGroupToCreate.id, newRecordId);
}
const newRecordIds = viewFilterGroupsToCreate.map((viewFilterGroup) => {
const newId = oldToNewId.get(viewFilterGroup.id);
if (!newId) {
throw new Error('Failed to create view filter group');
}
return newId;
});
return newRecordIds;
},
[createViewFilterGroupRecord],
);
const updateViewFilterGroupRecords = useCallback(
(viewFilterGroupsToUpdate: ViewFilterGroup[]) => {
if (!viewFilterGroupsToUpdate.length) return;
return Promise.all(
viewFilterGroupsToUpdate.map((viewFilterGroup) =>
apolloClient.mutate<{ updateViewFilterGroup: ViewFilterGroup }>({
mutation: updateOneRecordMutation,
variables: {
idToUpdate: viewFilterGroup.id,
input: {
parentViewFilterGroupId:
viewFilterGroup.parentViewFilterGroupId,
logicalOperator: viewFilterGroup.logicalOperator,
positionInViewFilterGroup:
viewFilterGroup.positionInViewFilterGroup,
},
},
update: (cache, { data }) => {
const record = data?.updateViewFilterGroup;
if (!record) return;
const cachedRecord = getRecordFromCache<ObjectRecord>(record.id);
if (!cachedRecord) return;
triggerUpdateRecordOptimisticEffect({
cache,
objectMetadataItem,
currentRecord: cachedRecord,
updatedRecord: record,
objectMetadataItems,
});
},
}),
),
);
},
[
apolloClient,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
updateOneRecordMutation,
],
);
const deleteViewFilterGroupRecords = useCallback(
(viewFilterGroupIdsToDelete: string[]) => {
if (!viewFilterGroupIdsToDelete.length) return;
return Promise.all(
viewFilterGroupIdsToDelete.map((viewFilterGroupId) =>
apolloClient.mutate<{ destroyViewFilterGroup: ViewFilterGroup }>({
mutation: destroyOneRecordMutation,
variables: {
idToDestroy: viewFilterGroupId,
},
update: (cache, { data }) => {
const record = data?.destroyViewFilterGroup;
if (!record) return;
const cachedRecord = getRecordFromCache(record.id, cache);
if (!cachedRecord) return;
triggerDestroyRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToDestroy: [cachedRecord],
objectMetadataItems,
});
},
}),
),
);
},
[
apolloClient,
destroyOneRecordMutation,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
],
);
return {
createViewFilterGroupRecords,
updateViewFilterGroupRecords,
deleteViewFilterGroupRecords,
};
};

View File

@ -50,11 +50,13 @@ export const usePersistViewFilterRecords = () => {
mutation: createOneRecordMutation,
variables: {
input: {
id: viewFilter.id,
fieldMetadataId: viewFilter.fieldMetadataId,
viewId: view.id,
value: viewFilter.value,
displayValue: viewFilter.displayValue,
operand: viewFilter.operand,
viewFilterGroupId: viewFilter.viewFilterGroupId,
},
},
update: (cache, { data }) => {

View File

@ -4,9 +4,11 @@ import { RecordIndexRootPropsContext } from '@/object-record/record-index/contex
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { usePersistViewFieldRecords } from '@/views/hooks/internal/usePersistViewFieldRecords';
import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePersistViewFilterGroupRecords';
import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords';
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords';
import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords';
import { useGetViewFilterGroupsCombined } from '@/views/hooks/useGetCombinedViewFilterGroups';
import { useGetViewFiltersCombined } from '@/views/hooks/useGetCombinedViewFilters';
import { useGetViewSortsCombined } from '@/views/hooks/useGetCombinedViewSorts';
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
@ -45,6 +47,8 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
const { getViewSortsCombined } = useGetViewSortsCombined(viewBarComponentId);
const { getViewFiltersCombined } =
useGetViewFiltersCombined(viewBarComponentId);
const { getViewFilterGroupsCombined } =
useGetViewFilterGroupsCombined(viewBarComponentId);
const { createViewSortRecords } = usePersistViewSortRecords();
@ -52,6 +56,8 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
const { createViewFilterRecords } = usePersistViewFilterRecords();
const { createViewFilterGroupRecords } = usePersistViewFilterGroupRecords();
const { objectMetadataItem } = useContext(RecordIndexRootPropsContext);
const createViewFromCurrentView = useRecoilCallback(
@ -143,11 +149,18 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
}
if (shouldCopyFiltersAndSorts === true) {
const sourceViewCombinedFilterGroups = getViewFilterGroupsCombined(
view.id,
);
const sourceViewCombinedFilters = getViewFiltersCombined(view.id);
const sourceViewCombinedSorts = getViewSortsCombined(view.id);
await createViewSortRecords(sourceViewCombinedSorts, view);
await createViewFilterRecords(sourceViewCombinedFilters, view);
await createViewFilterGroupRecords(
sourceViewCombinedFilterGroups,
view,
);
}
set(isPersistingViewFieldsCallbackState, false);
@ -160,10 +173,12 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
createViewFieldRecords,
getViewSortsCombined,
getViewFiltersCombined,
getViewFilterGroupsCombined,
currentViewIdCallbackState,
getViewFromCache,
isPersistingViewFieldsCallbackState,
createViewGroupRecords,
createViewFilterGroupRecords,
],
);

View File

@ -0,0 +1,67 @@
import { useRecoilCallback } from 'recoil';
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
import { View } from '@/views/types/View';
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
import { isDefined } from '~/utils/isDefined';
export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
const unsavedToUpsertViewFilterGroupsCallbackState =
useRecoilComponentCallbackStateV2(
unsavedToUpsertViewFilterGroupsComponentFamilyState,
viewBarComponentId,
);
const unsavedToDeleteViewFilterGroupIdsCallbackState =
useRecoilComponentCallbackStateV2(
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
viewBarComponentId,
);
const getViewFilterGroupsCombined = useRecoilCallback(
({ snapshot }) =>
(viewId: string) => {
const view = views.find((view) => view.id === viewId);
if (!isDefined(view)) {
throw new Error(
`Cannot get view with id ${viewId}, because it cannot be found in client cache data.`,
);
}
const unsavedToUpsertViewFilterGroups = getSnapshotValue(
snapshot,
unsavedToUpsertViewFilterGroupsCallbackState({ viewId: view.id }),
);
const unsavedToDeleteViewFilterGroupIds = getSnapshotValue(
snapshot,
unsavedToDeleteViewFilterGroupIdsCallbackState({ viewId: view.id }),
);
const combinedViewFilterGroups = getCombinedViewFilterGroups(
view.viewFilterGroups ?? [],
unsavedToUpsertViewFilterGroups,
unsavedToDeleteViewFilterGroupIds,
);
return combinedViewFilterGroups;
},
[
views,
unsavedToDeleteViewFilterGroupIdsCallbackState,
unsavedToUpsertViewFilterGroupsCallbackState,
],
);
return {
getViewFilterGroupsCombined,
};
};

View File

@ -9,12 +9,15 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
import { isCurrentViewKeyIndexComponentState } from '@/views/states/isCurrentViewIndexComponentState';
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
import { View } from '@/views/types/View';
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
@ -70,6 +73,12 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
instanceId,
);
const unsavedToUpsertViewFilterGroups = useRecoilComponentFamilyValueV2(
unsavedToUpsertViewFilterGroupsComponentFamilyState,
{ viewId },
instanceId,
);
const unsavedToUpsertViewSorts = useRecoilComponentFamilyValueV2(
unsavedToUpsertViewSortsComponentFamilyState,
{ viewId },
@ -82,6 +91,12 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
instanceId,
);
const unsavedToDeleteViewFilterGroupIds = useRecoilComponentFamilyValueV2(
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
{ viewId },
instanceId,
);
const unsavedToDeleteViewSortIds = useRecoilComponentFamilyValueV2(
unsavedToDeleteViewSortIdsComponentFamilyState,
{ viewId },
@ -104,6 +119,11 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
unsavedToUpsertViewFilters,
unsavedToDeleteViewFilterIds,
),
viewFilterGroups: getCombinedViewFilterGroups(
currentView.viewFilterGroups ?? [],
unsavedToUpsertViewFilterGroups,
unsavedToDeleteViewFilterGroupIds,
),
viewSorts: getCombinedViewSorts(
currentView.viewSorts,
unsavedToUpsertViewSorts,

View File

@ -1,6 +1,8 @@
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
import { useRecoilCallback } from 'recoil';
@ -18,6 +20,12 @@ export const useResetUnsavedViewStates = (viewBarInstanceId?: string) => {
viewBarInstanceId,
);
const unsavedToDeleteViewFilterGroupIdsCallbackState =
useRecoilComponentCallbackStateV2(
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
viewBarInstanceId,
);
const setUnsavedToUpsertViewFiltersCallbackState =
useRecoilComponentCallbackStateV2(
unsavedToUpsertViewFiltersComponentFamilyState,
@ -30,19 +38,29 @@ export const useResetUnsavedViewStates = (viewBarInstanceId?: string) => {
viewBarInstanceId,
);
const unsavedToUpsertViewFilterGroupsCallbackState =
useRecoilComponentCallbackStateV2(
unsavedToUpsertViewFilterGroupsComponentFamilyState,
viewBarInstanceId,
);
const resetUnsavedViewStates = useRecoilCallback(
({ set }) =>
(viewId: string) => {
set(unsavedToDeleteViewFilterGroupIdsCallbackState({ viewId }), []);
set(setUnsavedToDeleteViewFilterIdsCallbackState({ viewId }), []);
set(setUnsavedToDeleteViewSortIdsCallbackState({ viewId }), []);
set(unsavedToUpsertViewFilterGroupsCallbackState({ viewId }), []);
set(setUnsavedToUpsertViewFiltersCallbackState({ viewId }), []);
set(unsavedToUpsertViewSortsCallbackState({ viewId }), []);
},
[
unsavedToUpsertViewSortsCallbackState,
setUnsavedToUpsertViewFiltersCallbackState,
unsavedToUpsertViewFilterGroupsCallbackState,
setUnsavedToDeleteViewSortIdsCallbackState,
setUnsavedToDeleteViewFilterIdsCallbackState,
unsavedToDeleteViewFilterGroupIdsCallbackState,
],
);

View File

@ -2,13 +2,16 @@ import { useRecoilCallback } from 'recoil';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePersistViewFilterGroupRecords';
import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords';
import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords';
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
import { isDefined } from '~/utils/isDefined';
@ -48,6 +51,18 @@ export const useSaveCurrentViewFiltersAndSorts = (
viewBarComponentId,
);
const unsavedToUpsertViewFilterGroupsCallbackState =
useRecoilComponentCallbackStateV2(
unsavedToUpsertViewFilterGroupsComponentFamilyState,
viewBarComponentId,
);
const unsavedToDeleteViewFilterGroupIdsCallbackState =
useRecoilComponentCallbackStateV2(
unsavedToDeleteViewFilterGroupIdsComponentFamilyState,
viewBarComponentId,
);
const {
createViewSortRecords,
updateViewSortRecords,
@ -60,6 +75,12 @@ export const useSaveCurrentViewFiltersAndSorts = (
deleteViewFilterRecords,
} = usePersistViewFilterRecords();
const {
createViewFilterGroupRecords,
deleteViewFilterGroupRecords,
updateViewFilterGroupRecords,
} = usePersistViewFilterGroupRecords();
const { resetUnsavedViewStates } =
useResetUnsavedViewStates(viewBarComponentId);
@ -131,14 +152,14 @@ export const useSaveCurrentViewFiltersAndSorts = (
const viewFiltersToCreate = unsavedToUpsertViewFilters.filter(
(viewFilter) =>
!view.viewFilters.some(
(vf) => vf.fieldMetadataId === viewFilter.fieldMetadataId,
(viewFilterToFilter) => viewFilterToFilter.id === viewFilter.id,
),
);
const viewFiltersToUpdate = unsavedToUpsertViewFilters.filter(
(viewFilter) =>
view.viewFilters.some(
(vf) => vf.fieldMetadataId === viewFilter.fieldMetadataId,
(viewFilterToFilter) => viewFilterToFilter.id === viewFilter.id,
),
);
@ -156,6 +177,55 @@ export const useSaveCurrentViewFiltersAndSorts = (
],
);
const saveViewFilterGroups = useRecoilCallback(
({ snapshot }) =>
async (viewId: string) => {
const unsavedToDeleteViewFilterGroupIds = getSnapshotValue(
snapshot,
unsavedToDeleteViewFilterGroupIdsCallbackState({ viewId }),
);
const unsavedToUpsertViewFilterGroups = getSnapshotValue(
snapshot,
unsavedToUpsertViewFilterGroupsCallbackState({ viewId }),
);
const view = await getViewFromCache(viewId);
if (isUndefinedOrNull(view)) {
return;
}
const viewFilterGroupsToCreate = unsavedToUpsertViewFilterGroups.filter(
(viewFilterGroup) =>
!view.viewFilterGroups?.some(
(viewFilterGroupToFilter) =>
viewFilterGroupToFilter.id === viewFilterGroup.id,
),
);
const viewFilterGroupsToUpdate = unsavedToUpsertViewFilterGroups.filter(
(viewFilterGroup) =>
view.viewFilterGroups?.some(
(viewFilterGroupToFilter) =>
viewFilterGroupToFilter.id === viewFilterGroup.id,
),
);
await createViewFilterGroupRecords(viewFilterGroupsToCreate, view);
await updateViewFilterGroupRecords(viewFilterGroupsToUpdate);
await deleteViewFilterGroupRecords(unsavedToDeleteViewFilterGroupIds);
},
[
getViewFromCache,
createViewFilterGroupRecords,
deleteViewFilterGroupRecords,
unsavedToDeleteViewFilterGroupIdsCallbackState,
unsavedToUpsertViewFilterGroupsCallbackState,
updateViewFilterGroupRecords,
],
);
const saveCurrentViewFilterAndSorts = useRecoilCallback(
({ snapshot }) =>
async (viewIdFromProps?: string) => {
@ -169,6 +239,7 @@ export const useSaveCurrentViewFiltersAndSorts = (
const viewId = viewIdFromProps ?? currentViewId;
await saveViewFilterGroups(viewId);
await saveViewFilters(viewId);
await saveViewSorts(viewId);
@ -179,6 +250,7 @@ export const useSaveCurrentViewFiltersAndSorts = (
resetUnsavedViewStates,
saveViewFilters,
saveViewSorts,
saveViewFilterGroups,
],
);

View File

@ -8,6 +8,7 @@ import { currentViewIdComponentState } from '@/views/states/currentViewIdCompone
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
import { ViewFilter } from '@/views/types/ViewFilter';
import { shouldReplaceFilter } from '@/views/utils/shouldReplaceFilter';
import { isDefined } from '~/utils/isDefined';
export const useUpsertCombinedViewFilters = (viewBarComponentId?: string) => {
@ -59,19 +60,16 @@ export const useUpsertCombinedViewFilters = (viewBarComponentId?: string) => {
}
const matchingFilterInCurrentView = currentView.viewFilters.find(
(viewFilter) =>
viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId,
(viewFilter) => shouldReplaceFilter(viewFilter, upsertedFilter),
);
const matchingFilterInUnsavedFilters = unsavedToUpsertViewFilters.find(
(viewFilter) =>
viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId,
(viewFilter) => shouldReplaceFilter(viewFilter, upsertedFilter),
);
if (isDefined(matchingFilterInUnsavedFilters)) {
const updatedFilters = unsavedToUpsertViewFilters.map((viewFilter) =>
viewFilter.fieldMetadataId ===
matchingFilterInUnsavedFilters.fieldMetadataId
shouldReplaceFilter(viewFilter, matchingFilterInUnsavedFilters)
? { ...viewFilter, ...upsertedFilter, id: viewFilter.id }
: viewFilter,
);