Added record filter hidden fields in query (#18149)
Fixes https://github.com/twentyhq/twenty/issues/17506 Hidden fields are now queried when they are in record filters, to avoid optimistic and filtering bugs with hidden fields.
This commit is contained in:
+2
-2
@@ -10,7 +10,7 @@ import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecord
|
||||
import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError';
|
||||
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
|
||||
|
||||
import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
@@ -28,7 +28,7 @@ export const useLazyFindManyRecordsWithOffset = ({
|
||||
|
||||
const params = useFindManyRecordIndexTableParams(objectNameSingular);
|
||||
|
||||
const recordGqlFields = useRecordsFieldVisibleGqlFields({
|
||||
const recordGqlFields = useRelevantRecordsGqlFields({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { dispatchObjectRecordOperationBrowserEvent } from '@/browser-event/utils/dispatchObjectRecordOperationBrowserEvent';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { generateUpdateOneRecordMutation } from '@/object-metadata/utils/generateUpdateOneRecordMutation';
|
||||
@@ -16,7 +17,6 @@ import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggr
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
|
||||
import { dispatchObjectRecordOperationBrowserEvent } from '@/browser-event/utils/dispatchObjectRecordOperationBrowserEvent';
|
||||
import { getUpdatedFieldsFromRecordInput } from '@/object-record/utils/getUpdatedFieldsFromRecordInput';
|
||||
import { getUpdateOneRecordMutationResponseField } from '@/object-record/utils/getUpdateOneRecordMutationResponseField';
|
||||
import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput';
|
||||
|
||||
+3
-3
@@ -4,13 +4,13 @@ import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getR
|
||||
import { useGroupByRecordsQuery } from '@/object-record/hooks/useGroupByRecordsQuery';
|
||||
import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar/contexts/RecordCalendarContext';
|
||||
import { useRecordCalendarQueryDateRangeFilter } from '@/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter';
|
||||
import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
import { recordIndexCalendarFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexCalendarFieldMetadataIdState';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { buildGroupByFieldObject } from '@/page-layout/widgets/graph/utils/buildGroupByFieldObject';
|
||||
import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useMemo } from 'react';
|
||||
import { type Temporal } from 'temporal-polyfill';
|
||||
import {
|
||||
@@ -30,7 +30,7 @@ export const useRecordCalendarGroupByRecords = (
|
||||
recordIndexCalendarFieldMetadataIdState,
|
||||
);
|
||||
|
||||
const recordGqlFields = useRecordsFieldVisibleGqlFields({
|
||||
const recordGqlFields = useRelevantRecordsGqlFields({
|
||||
objectMetadataItem,
|
||||
additionalFieldMetadataId: recordIndexCalendarFieldMetadataId,
|
||||
});
|
||||
|
||||
+35
-12
@@ -1,42 +1,65 @@
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getImageIdentifierFieldMetadataItem } from '@/object-metadata/utils/getImageIdentifierFieldMetadataItem';
|
||||
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||
import { hasObjectMetadataItemPositionField } from '@/object-metadata/utils/hasObjectMetadataItemPositionField';
|
||||
import { generateActivityTargetGqlFields } from '@/object-record/graphql/record-gql-fields/utils/generateActivityTargetGqlFields';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
|
||||
import { generateDepthRecordGqlFieldsFromFields } from '@/object-record/graphql/record-gql-fields/utils/generateDepthRecordGqlFieldsFromFields';
|
||||
import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type UseRecordsFieldVisibleGqlFields = {
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { filterDuplicatesById, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type UseRecordsUsefulGqlFields = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
additionalFieldMetadataId?: string | null;
|
||||
};
|
||||
|
||||
export const useRecordsFieldVisibleGqlFields = ({
|
||||
export const useRelevantRecordsGqlFields = ({
|
||||
objectMetadataItem,
|
||||
additionalFieldMetadataId,
|
||||
}: UseRecordsFieldVisibleGqlFields) => {
|
||||
}: UseRecordsUsefulGqlFields) => {
|
||||
const visibleRecordFields = useAtomComponentSelectorValue(
|
||||
visibleRecordFieldsComponentSelector,
|
||||
);
|
||||
|
||||
const currentRecordFilters = useAtomComponentStateValue(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const { fieldMetadataItemByFieldMetadataItemId } =
|
||||
useRecordIndexContextOrThrow();
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const visibleRecordFieldMetadataItems = visibleRecordFields
|
||||
.map(
|
||||
(field) =>
|
||||
fieldMetadataItemByFieldMetadataItemId[field.fieldMetadataItemId],
|
||||
)
|
||||
.filter(isDefined);
|
||||
|
||||
const recordFilterFields = currentRecordFilters
|
||||
.map((recordFilter) =>
|
||||
objectMetadataItem.fields.find(
|
||||
(field) => field.id === recordFilter.fieldMetadataId,
|
||||
),
|
||||
)
|
||||
.filter(isDefined);
|
||||
|
||||
const fieldMetadataItemsToUse = [
|
||||
...visibleRecordFieldMetadataItems,
|
||||
...(recordFilterFields ?? []),
|
||||
].filter(filterDuplicatesById);
|
||||
|
||||
const allDepthOneGqlFields = generateDepthRecordGqlFieldsFromFields({
|
||||
objectMetadataItems,
|
||||
fields: visibleRecordFields
|
||||
.map(
|
||||
(field) =>
|
||||
fieldMetadataItemByFieldMetadataItemId[field.fieldMetadataItemId],
|
||||
)
|
||||
.filter(isDefined),
|
||||
fields: fieldMetadataItemsToUse,
|
||||
depth: 1,
|
||||
});
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
@@ -63,7 +63,7 @@ export const useRecordIndexGroupCommonQueryVariables = () => {
|
||||
recordIndexGroupFieldMetadataItemComponentState,
|
||||
);
|
||||
|
||||
const recordGqlFields = useRecordsFieldVisibleGqlFields({
|
||||
const recordGqlFields = useRelevantRecordsGqlFields({
|
||||
objectMetadataItem,
|
||||
additionalFieldMetadataId: recordIndexGroupFieldMetadataItem?.id,
|
||||
});
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
|
||||
import { type RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { generateGroupsRecordsGroupByQuery } from '@/object-record/record-aggregate/utils/generateGroupsRecordsGroupByQuery';
|
||||
|
||||
import { useRecordIndexGroupCommonQueryVariables } from '@/object-record/record-index/hooks/useRecordIndexGroupCommonQueryVariables';
|
||||
import { buildGroupByFieldObject } from '@/page-layout/widgets/graph/utils/buildGroupByFieldObject';
|
||||
import { useLazyQuery } from '@apollo/client';
|
||||
@@ -63,6 +64,7 @@ export const useRecordIndexGroupsRecordsLazyGroupBy = ({
|
||||
limit: recordGroupsLimit,
|
||||
},
|
||||
client: apolloCoreClient,
|
||||
fetchPolicy: 'no-cache',
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||
import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||
|
||||
export const useRecordIndexTableFetchMore = (objectNameSingular: string) => {
|
||||
@@ -10,7 +10,7 @@ export const useRecordIndexTableFetchMore = (objectNameSingular: string) => {
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const recordGqlFields = useRecordsFieldVisibleGqlFields({
|
||||
const recordGqlFields = useRelevantRecordsGqlFields({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||
import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
@@ -14,7 +14,7 @@ export const useRecordIndexTableQuery = (objectNameSingular: string) => {
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const recordGqlFields = useRecordsFieldVisibleGqlFields({
|
||||
const recordGqlFields = useRelevantRecordsGqlFields({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
|
||||
+4
-3
@@ -1,9 +1,9 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||
import { useRecordsFieldVisibleGqlFields } from '@/object-record/record-field/hooks/useRecordsFieldVisibleGqlFields';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
|
||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||
import { useTriggerFetchPages } from '@/object-record/record-table/virtualization/hooks/useTriggerFetchPages';
|
||||
@@ -29,7 +29,8 @@ export const useResetVirtualizationBecauseDataChanged = (
|
||||
|
||||
const params = useFindManyRecordIndexTableParams(objectNameSingular);
|
||||
|
||||
const recordGqlFields = useRecordsFieldVisibleGqlFields({
|
||||
// TODO: we could optimize this by using an aggregate or using only id: true in recordGqlFields
|
||||
const recordGqlFields = useRelevantRecordsGqlFields({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { filterDuplicatesById } from '@/utils/array/filterDuplicatesById';
|
||||
|
||||
type ObjectRecordTest = { id: string };
|
||||
|
||||
describe('filterDuplicatesById', () => {
|
||||
it('should work with empty array', () => {
|
||||
const array: ObjectRecordTest[] = [];
|
||||
|
||||
const filteredArray = array.filter(filterDuplicatesById);
|
||||
|
||||
expect(filteredArray).toEqual([]);
|
||||
});
|
||||
|
||||
it('should work with no duplicates', () => {
|
||||
const array: ObjectRecordTest[] = [
|
||||
{
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
},
|
||||
];
|
||||
|
||||
const filteredArray = array.filter(filterDuplicatesById);
|
||||
|
||||
expect(filteredArray).toEqual(array);
|
||||
});
|
||||
|
||||
it('should work with one duplicate', () => {
|
||||
const array: ObjectRecordTest[] = [
|
||||
{
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
},
|
||||
];
|
||||
|
||||
const filteredArray = array.filter(filterDuplicatesById);
|
||||
|
||||
expect(filteredArray).toEqual([{ id: '1' }]);
|
||||
});
|
||||
|
||||
it('should work with multiple duplicates', () => {
|
||||
const array: ObjectRecordTest[] = [
|
||||
{
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
},
|
||||
];
|
||||
|
||||
const filteredArray = array.filter(filterDuplicatesById);
|
||||
|
||||
expect(filteredArray).toEqual([
|
||||
{
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
export const filterDuplicatesById = <T extends { id: string }>(
|
||||
item: T,
|
||||
index: number,
|
||||
self: T[],
|
||||
) => {
|
||||
return self.findIndex((i) => i.id === item.id) === index;
|
||||
};
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
export { applyDiff } from './applyDiff';
|
||||
export { compareArraysOfObjectsByProperty } from './array/compareArraysOfObjectsByProperty';
|
||||
export { filterDuplicatesById } from './array/filterDuplicatesById';
|
||||
export { filterOutByProperty } from './array/filterOutByProperty';
|
||||
export { findById } from './array/findById';
|
||||
export { findByProperty } from './array/findByProperty';
|
||||
|
||||
Reference in New Issue
Block a user