Activity injection into Apollo cache (#3665)
- Created addRecordInCache to inject a record in Apollo cache and inject single read query on this record - Created createOneRecordInCache and createManyRecordsInCache that uses this addRecordInCache - Created useOpenCreateActivityDrawerV2 hook to create an activity in cache and inject it into all other relevant requests in the app before opening activity drawer - Refactored DEFAULT_SEARCH_REQUEST_LIMIT constant and hardcoded arbitrary request limits - Added Apollo dev logs to see errors in the console when manipulating cache
This commit is contained in:
72
packages/twenty-front/src/modules/object-record/cache/hooks/useAddRecordInCache.ts
vendored
Normal file
72
packages/twenty-front/src/modules/object-record/cache/hooks/useAddRecordInCache.ts
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import gql from 'graphql-tag';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useGenerateFindOneRecordQuery } from '@/object-record/hooks/useGenerateFindOneRecordQuery';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const useAddRecordInCache = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const generateFindOneRecordQuery = useGenerateFindOneRecordQuery();
|
||||
|
||||
const findOneRecordQuery = generateFindOneRecordQuery({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
return useRecoilCallback(
|
||||
({ set }) =>
|
||||
(record: ObjectRecord) => {
|
||||
apolloClient.writeFragment({
|
||||
id: `${capitalize(objectMetadataItem.nameSingular)}:${record.id}`,
|
||||
fragment: gql`
|
||||
fragment Create${capitalize(
|
||||
objectMetadataItem.nameSingular,
|
||||
)}InCache on ${capitalize(objectMetadataItem.nameSingular)} {
|
||||
__typename
|
||||
id
|
||||
${objectMetadataItem.fields
|
||||
.map((field) => mapFieldMetadataToGraphQLQuery(field))
|
||||
.join('\n')}
|
||||
}
|
||||
`,
|
||||
data: {
|
||||
__typename: `${capitalize(objectMetadataItem.nameSingular)}`,
|
||||
...record,
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: Turn into injectIntoFindOneRecordQueryCache
|
||||
apolloClient.writeQuery({
|
||||
query: findOneRecordQuery,
|
||||
variables: {
|
||||
objectRecordId: record.id,
|
||||
},
|
||||
data: {
|
||||
[objectMetadataItem.nameSingular]: {
|
||||
__typename: `${capitalize(objectMetadataItem.nameSingular)}`,
|
||||
...record,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: remove this once we get rid of entityFieldsFamilyState
|
||||
set(recordStoreFamilyState(record.id), record);
|
||||
},
|
||||
[
|
||||
objectMetadataItem,
|
||||
apolloClient,
|
||||
mapFieldMetadataToGraphQLQuery,
|
||||
findOneRecordQuery,
|
||||
],
|
||||
);
|
||||
};
|
||||
31
packages/twenty-front/src/modules/object-record/cache/utils/getCacheReferenceFromRecord.ts
vendored
Normal file
31
packages/twenty-front/src/modules/object-record/cache/utils/getCacheReferenceFromRecord.ts
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
import { ApolloClient, makeReference, Reference } from '@apollo/client';
|
||||
|
||||
import { getCachedRecordFromRecord } from '@/object-record/cache/utils/getCachedRecordFromRecord';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export const getCacheReferenceFromRecord = <T extends ObjectRecord>({
|
||||
apolloClient,
|
||||
objectNameSingular,
|
||||
record,
|
||||
}: {
|
||||
apolloClient: ApolloClient<object>;
|
||||
objectNameSingular: string;
|
||||
record: T;
|
||||
}): Reference => {
|
||||
const cachedRecord = getCachedRecordFromRecord({
|
||||
objectNameSingular,
|
||||
record,
|
||||
});
|
||||
|
||||
const id = apolloClient.cache.identify(cachedRecord);
|
||||
|
||||
if (!id) {
|
||||
throw new Error(
|
||||
`Could not identify record "${objectNameSingular}", id : "${record.id}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const recordReference = makeReference(id);
|
||||
|
||||
return recordReference;
|
||||
};
|
||||
43
packages/twenty-front/src/modules/object-record/cache/utils/getCachedRecordEdgesFromRecords.ts
vendored
Normal file
43
packages/twenty-front/src/modules/object-record/cache/utils/getCachedRecordEdgesFromRecords.ts
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
import { ApolloClient, makeReference } from '@apollo/client';
|
||||
|
||||
import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge';
|
||||
import { getCachedRecordFromRecord } from '@/object-record/cache/utils/getCachedRecordFromRecord';
|
||||
import { getEdgeTypename } from '@/object-record/cache/utils/getEdgeTypename';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export const getCachedRecordEdgesFromRecords = <T extends ObjectRecord>({
|
||||
apolloClient,
|
||||
objectNameSingular,
|
||||
records,
|
||||
}: {
|
||||
apolloClient: ApolloClient<object>;
|
||||
objectNameSingular: string;
|
||||
records: T[];
|
||||
}): CachedObjectRecordEdge[] => {
|
||||
const cachedRecordEdges = records.map((record) => {
|
||||
const cachedRecord = getCachedRecordFromRecord({
|
||||
objectNameSingular,
|
||||
record,
|
||||
});
|
||||
|
||||
const id = apolloClient.cache.identify(cachedRecord);
|
||||
|
||||
if (!id) {
|
||||
throw new Error(
|
||||
`Could not identify record "${objectNameSingular}", id : "${record.id}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const reference = makeReference(id);
|
||||
|
||||
const cachedObjectRecordEdge: CachedObjectRecordEdge = {
|
||||
cursor: '',
|
||||
node: reference,
|
||||
__typename: getEdgeTypename({ objectNameSingular }),
|
||||
};
|
||||
|
||||
return cachedObjectRecordEdge;
|
||||
});
|
||||
|
||||
return cachedRecordEdges;
|
||||
};
|
||||
16
packages/twenty-front/src/modules/object-record/cache/utils/getCachedRecordFromRecord.ts
vendored
Normal file
16
packages/twenty-front/src/modules/object-record/cache/utils/getCachedRecordFromRecord.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord';
|
||||
import { getNodeTypename } from '@/object-record/cache/utils/getNodeTypename';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export const getCachedRecordFromRecord = <T extends ObjectRecord>({
|
||||
objectNameSingular,
|
||||
record,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
record: T;
|
||||
}): CachedObjectRecord<T> => {
|
||||
return {
|
||||
__typename: getNodeTypename({ objectNameSingular }),
|
||||
...record,
|
||||
};
|
||||
};
|
||||
9
packages/twenty-front/src/modules/object-record/cache/utils/getConnectionTypename.ts
vendored
Normal file
9
packages/twenty-front/src/modules/object-record/cache/utils/getConnectionTypename.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const getConnectionTypename = ({
|
||||
objectNameSingular,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
return `${capitalize(objectNameSingular)}Connection`;
|
||||
};
|
||||
9
packages/twenty-front/src/modules/object-record/cache/utils/getEdgeTypename.ts
vendored
Normal file
9
packages/twenty-front/src/modules/object-record/cache/utils/getEdgeTypename.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const getEdgeTypename = ({
|
||||
objectNameSingular,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
return `${capitalize(objectNameSingular)}Edge`;
|
||||
};
|
||||
8
packages/twenty-front/src/modules/object-record/cache/utils/getEmptyPageInfo.ts
vendored
Normal file
8
packages/twenty-front/src/modules/object-record/cache/utils/getEmptyPageInfo.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
export const getEmptyPageInfo = () => {
|
||||
return {
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
startCursor: null,
|
||||
endCursor: null,
|
||||
};
|
||||
};
|
||||
9
packages/twenty-front/src/modules/object-record/cache/utils/getNodeTypename.ts
vendored
Normal file
9
packages/twenty-front/src/modules/object-record/cache/utils/getNodeTypename.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const getNodeTypename = ({
|
||||
objectNameSingular,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
return capitalize(objectNameSingular);
|
||||
};
|
||||
19
packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromEdges.ts
vendored
Normal file
19
packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromEdges.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import { getConnectionTypename } from '@/object-record/cache/utils/getConnectionTypename';
|
||||
import { getEmptyPageInfo } from '@/object-record/cache/utils/getEmptyPageInfo';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection';
|
||||
import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge';
|
||||
|
||||
export const getRecordConnectionFromEdges = <T extends ObjectRecord>({
|
||||
objectNameSingular,
|
||||
edges,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
edges: ObjectRecordEdge<T>[];
|
||||
}) => {
|
||||
return {
|
||||
__typename: getConnectionTypename({ objectNameSingular }),
|
||||
edges: edges,
|
||||
pageInfo: getEmptyPageInfo(),
|
||||
} as ObjectRecordConnection<T>;
|
||||
};
|
||||
24
packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromRecords.ts
vendored
Normal file
24
packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromRecords.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
import { getConnectionTypename } from '@/object-record/cache/utils/getConnectionTypename';
|
||||
import { getEmptyPageInfo } from '@/object-record/cache/utils/getEmptyPageInfo';
|
||||
import { getRecordEdgeFromRecord } from '@/object-record/cache/utils/getRecordEdgeFromRecord';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection';
|
||||
|
||||
export const getRecordConnectionFromRecords = <T extends ObjectRecord>({
|
||||
objectNameSingular,
|
||||
records,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
records: T[];
|
||||
}) => {
|
||||
return {
|
||||
__typename: getConnectionTypename({ objectNameSingular }),
|
||||
edges: records.map((record) => {
|
||||
return getRecordEdgeFromRecord({
|
||||
objectNameSingular,
|
||||
record,
|
||||
});
|
||||
}),
|
||||
pageInfo: getEmptyPageInfo(),
|
||||
} as ObjectRecordConnection<T>;
|
||||
};
|
||||
21
packages/twenty-front/src/modules/object-record/cache/utils/getRecordEdgeFromRecord.ts
vendored
Normal file
21
packages/twenty-front/src/modules/object-record/cache/utils/getRecordEdgeFromRecord.ts
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
import { getEdgeTypename } from '@/object-record/cache/utils/getEdgeTypename';
|
||||
import { getNodeTypename } from '@/object-record/cache/utils/getNodeTypename';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge';
|
||||
|
||||
export const getRecordEdgeFromRecord = <T extends ObjectRecord>({
|
||||
objectNameSingular,
|
||||
record,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
record: T;
|
||||
}) => {
|
||||
return {
|
||||
__typename: getEdgeTypename({ objectNameSingular }),
|
||||
node: {
|
||||
__typename: getNodeTypename({ objectNameSingular }),
|
||||
...record,
|
||||
},
|
||||
cursor: '',
|
||||
} as ObjectRecordEdge<T>;
|
||||
};
|
||||
10
packages/twenty-front/src/modules/object-record/cache/utils/getRecordsFromRecordConnection.ts
vendored
Normal file
10
packages/twenty-front/src/modules/object-record/cache/utils/getRecordsFromRecordConnection.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection';
|
||||
|
||||
export const getRecordsFromRecordConnection = <T extends ObjectRecord>({
|
||||
recordConnection,
|
||||
}: {
|
||||
recordConnection: ObjectRecordConnection<T>;
|
||||
}): T[] => {
|
||||
return recordConnection.edges.map((edge) => edge.node);
|
||||
};
|
||||
@ -0,0 +1 @@
|
||||
export const DEFAULT_SEARCH_REQUEST_LIMIT = 60;
|
||||
@ -5,7 +5,7 @@ export const query = gql`
|
||||
$filter: PersonFilterInput
|
||||
$orderBy: PersonOrderByInput
|
||||
$lastCursor: String
|
||||
$limit: Float = 30
|
||||
$limit: Float
|
||||
) {
|
||||
people(
|
||||
filter: $filter
|
||||
|
||||
@ -5,7 +5,7 @@ import { act, renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { useModifyRecordFromCache } from '@/object-record/hooks/useModifyRecordFromCache';
|
||||
import { useModifyRecordFromCache } from '@/object-record/cache/hooks/useModifyRecordFromCache';
|
||||
|
||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<MockedProvider addTypename={false}>
|
||||
|
||||
@ -3,7 +3,7 @@ import { useApolloClient } from '@apollo/client';
|
||||
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
||||
import { useGenerateCachedObjectRecord } from '@/object-record/hooks/useGenerateCachedObjectRecord';
|
||||
import { useGenerateCachedObjectRecord } from '@/object-record/cache/hooks/useGenerateCachedObjectRecord';
|
||||
import { getCreateManyRecordsMutationResponseField } from '@/object-record/hooks/useGenerateCreateManyRecordMutation';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput';
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
||||
import { useAddRecordInCache } from '@/object-record/cache/hooks/useAddRecordInCache';
|
||||
import { useGenerateCachedObjectRecord } from '@/object-record/cache/hooks/useGenerateCachedObjectRecord';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export const useCreateManyRecordsInCache = <T extends ObjectRecord>({
|
||||
objectNameSingular,
|
||||
}: ObjectMetadataItemIdentifier) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { generateCachedObjectRecord } = useGenerateCachedObjectRecord({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const addRecordInCache = useAddRecordInCache({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const createManyRecordsInCache = async (data: Partial<T>[]) => {
|
||||
const recordsWithId = data.map((record) => ({
|
||||
...record,
|
||||
id: (record.id as string) ?? v4(),
|
||||
}));
|
||||
|
||||
const createdRecordsInCache = [] as T[];
|
||||
|
||||
for (const record of recordsWithId) {
|
||||
const generatedCachedObjectRecord = generateCachedObjectRecord<T>({
|
||||
...record,
|
||||
});
|
||||
|
||||
if (generatedCachedObjectRecord) {
|
||||
addRecordInCache(generatedCachedObjectRecord);
|
||||
|
||||
createdRecordsInCache.push(generatedCachedObjectRecord);
|
||||
}
|
||||
}
|
||||
|
||||
return createdRecordsInCache;
|
||||
};
|
||||
|
||||
return { createManyRecordsInCache };
|
||||
};
|
||||
@ -2,7 +2,7 @@ import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useGenerateCachedObjectRecord } from '@/object-record/hooks/useGenerateCachedObjectRecord';
|
||||
import { useGenerateCachedObjectRecord } from '@/object-record/cache/hooks/useGenerateCachedObjectRecord';
|
||||
import { getCreateOneRecordMutationResponseField } from '@/object-record/hooks/useGenerateCreateOneRecordMutation';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput';
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useAddRecordInCache } from '@/object-record/cache/hooks/useAddRecordInCache';
|
||||
import { useGenerateCachedObjectRecord } from '@/object-record/cache/hooks/useGenerateCachedObjectRecord';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
type useCreateOneRecordInCacheProps = {
|
||||
objectNameSingular: string;
|
||||
};
|
||||
|
||||
export const useCreateOneRecordInCache = <T>({
|
||||
objectNameSingular,
|
||||
}: useCreateOneRecordInCacheProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { generateCachedObjectRecord } = useGenerateCachedObjectRecord({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const addRecordInCache = useAddRecordInCache({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const createOneRecordInCache = async (input: ObjectRecord) => {
|
||||
const generatedCachedObjectRecord = generateCachedObjectRecord({
|
||||
createdAt: new Date().toISOString(),
|
||||
...input,
|
||||
});
|
||||
|
||||
addRecordInCache(generatedCachedObjectRecord);
|
||||
|
||||
return generatedCachedObjectRecord as T;
|
||||
};
|
||||
|
||||
return {
|
||||
createOneRecordInCache,
|
||||
};
|
||||
};
|
||||
@ -13,7 +13,6 @@ import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnec
|
||||
import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge';
|
||||
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
|
||||
import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor';
|
||||
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { logError } from '~/utils/logError';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
@ -28,7 +27,7 @@ export const useFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
|
||||
objectNameSingular,
|
||||
filter,
|
||||
orderBy,
|
||||
limit = DEFAULT_SEARCH_REQUEST_LIMIT,
|
||||
limit,
|
||||
onCompleted,
|
||||
skip,
|
||||
useRecordsWithoutConnection = false,
|
||||
|
||||
@ -20,7 +20,7 @@ export const useGenerateFindManyRecordsQuery = () => {
|
||||
objectMetadataItem.nameSingular,
|
||||
)}FilterInput, $orderBy: ${capitalize(
|
||||
objectMetadataItem.nameSingular,
|
||||
)}OrderByInput, $lastCursor: String, $limit: Float = 60) {
|
||||
)}OrderByInput, $lastCursor: String, $limit: Float) {
|
||||
${
|
||||
objectMetadataItem.namePlural
|
||||
}(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor){
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
URLFilter,
|
||||
UUIDFilter,
|
||||
} from '@/object-record/record-filter/types/ObjectRecordQueryFilter';
|
||||
import { andFilterVariables } from '@/object-record/utils/andFilterVariables';
|
||||
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { Field } from '~/generated/graphql';
|
||||
|
||||
@ -260,5 +260,5 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
|
||||
}
|
||||
}
|
||||
|
||||
return andFilterVariables(objectRecordFilters);
|
||||
return makeAndFilterVariables(objectRecordFilters);
|
||||
};
|
||||
|
||||
@ -238,16 +238,21 @@ export const RecordShowContainer = ({
|
||||
</>
|
||||
)}
|
||||
</ShowPageLeftContainer>
|
||||
<ShowPageRightContainer
|
||||
targetableObject={{
|
||||
id: record?.id ?? '',
|
||||
targetObjectNameSingular: objectMetadataItem?.nameSingular,
|
||||
}}
|
||||
timeline
|
||||
tasks
|
||||
notes
|
||||
emails
|
||||
/>
|
||||
{record ? (
|
||||
<ShowPageRightContainer
|
||||
targetableObject={{
|
||||
id: record.id,
|
||||
targetObjectNameSingular: objectMetadataItem?.nameSingular,
|
||||
targetObjectRecord: record,
|
||||
}}
|
||||
timeline
|
||||
tasks
|
||||
notes
|
||||
emails
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</ShowPageContainer>
|
||||
</RecoilScope>
|
||||
);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import { useMultiObjectSearchSelectedItemsQuery } from '@/object-record/relation
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
|
||||
|
||||
export const DEFAULT_SEARCH_REQUEST_LIMIT = 5;
|
||||
export const MULTI_OBJECT_SEARCH_REQUEST_LIMIT = 5;
|
||||
|
||||
export type ObjectRecordForSelect = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
import { SelectedObjectRecordId } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
|
||||
import { useOrderByFieldPerMetadataItem } from '@/object-record/relation-picker/hooks/useOrderByFieldPerMetadataItem';
|
||||
import { useSearchFilterPerMetadataItem } from '@/object-record/relation-picker/hooks/useSearchFilterPerMetadataItem';
|
||||
import { andFilterVariables } from '@/object-record/utils/andFilterVariables';
|
||||
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
@ -69,7 +69,7 @@ export const useMultiObjectSearchMatchesSearchFilterAndToSelectQuery = ({
|
||||
|
||||
return [
|
||||
`filter${capitalize(nameSingular)}`,
|
||||
andFilterVariables(searchFilters),
|
||||
makeAndFilterVariables(searchFilters),
|
||||
];
|
||||
})
|
||||
.filter(isDefined),
|
||||
|
||||
@ -2,13 +2,12 @@ import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { OrderBy } from '@/object-metadata/types/OrderBy';
|
||||
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { SelectableRecord } from '@/object-record/select/types/SelectableRecord';
|
||||
import { getObjectFilterFields } from '@/object-record/select/utils/getObjectFilterFields';
|
||||
import { andFilterVariables } from '@/object-record/utils/andFilterVariables';
|
||||
import { orFilterVariables } from '@/object-record/utils/orFilterVariables';
|
||||
|
||||
export const DEFAULT_SEARCH_REQUEST_LIMIT = 60;
|
||||
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
||||
import { makeOrFilterVariables } from '@/object-record/utils/makeOrFilterVariables';
|
||||
|
||||
export const useRecordsForSelect = ({
|
||||
searchFilterText,
|
||||
@ -53,7 +52,7 @@ export const useRecordsForSelect = ({
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return orFilterVariables(
|
||||
return makeOrFilterVariables(
|
||||
fieldNames.map((fieldName) => {
|
||||
const [parentFieldName, subFieldName] = fieldName.split('.');
|
||||
|
||||
@ -81,7 +80,7 @@ export const useRecordsForSelect = ({
|
||||
loading: filteredSelectedRecordsLoading,
|
||||
records: filteredSelectedRecordsData,
|
||||
} = useFindManyRecords({
|
||||
filter: andFilterVariables([...searchFilters, selectedIdsFilter]),
|
||||
filter: makeAndFilterVariables([...searchFilters, selectedIdsFilter]),
|
||||
orderBy: orderByField,
|
||||
objectNameSingular,
|
||||
skip: !selectedIds.length,
|
||||
@ -93,7 +92,7 @@ export const useRecordsForSelect = ({
|
||||
: undefined;
|
||||
const { loading: recordsToSelectLoading, records: recordsToSelectData } =
|
||||
useFindManyRecords({
|
||||
filter: andFilterVariables([...searchFilters, notFilter]),
|
||||
filter: makeAndFilterVariables([...searchFilters, notFilter]),
|
||||
limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT,
|
||||
orderBy: orderByField,
|
||||
objectNameSingular,
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { FieldMetadataType } from '~/generated/graphql';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const generateEmptyFieldValue = (
|
||||
fieldMetadataItem: FieldMetadataItem,
|
||||
@ -39,7 +42,21 @@ export const generateEmptyFieldValue = (
|
||||
return true;
|
||||
}
|
||||
case FieldMetadataType.Relation: {
|
||||
return null;
|
||||
if (
|
||||
!isNonEmptyString(
|
||||
fieldMetadataItem.fromRelationMetadata?.toObjectMetadata
|
||||
?.nameSingular,
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
__typename: `${capitalize(
|
||||
fieldMetadataItem.fromRelationMetadata.toObjectMetadata.nameSingular,
|
||||
)}Connection`,
|
||||
edges: [],
|
||||
};
|
||||
}
|
||||
case FieldMetadataType.Currency: {
|
||||
return {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const andFilterVariables = (
|
||||
export const makeAndFilterVariables = (
|
||||
filters: (ObjectRecordQueryFilter | undefined)[],
|
||||
): ObjectRecordQueryFilter | undefined => {
|
||||
const definedFilters = filters.filter(isDefined);
|
||||
@ -1,7 +1,7 @@
|
||||
import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const orFilterVariables = (
|
||||
export const makeOrFilterVariables = (
|
||||
filters: (ObjectRecordQueryFilter | undefined)[],
|
||||
): ObjectRecordQueryFilter | undefined => {
|
||||
const definedFilters = filters.filter(isDefined);
|
||||
@ -0,0 +1,5 @@
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export const mapToRecordId = (objectRecord: ObjectRecord) => {
|
||||
return objectRecord.id;
|
||||
};
|
||||
Reference in New Issue
Block a user