Prefetching views and favorites (#4421)
* wip * Push * Complete work on prefetch * Add comment * Fix * Fix * Fix * Fix * Remove dead code * Simplify * Fix tests * Fix tests * Fix according to review * Fix according to review --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -1,24 +1,18 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { QueryMethodName } from '@/object-metadata/types/QueryMethodName';
|
||||
import { useCachedRootQuery } from '@/object-record/cache/hooks/useCachedRootQuery';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
|
||||
export const useDefaultHomePagePath = () => {
|
||||
const { objectMetadataItem: companyObjectMetadataItem } =
|
||||
useObjectMetadataItem({
|
||||
objectNameSingular: CoreObjectNameSingular.Company,
|
||||
});
|
||||
const { objectMetadataItem: viewObjectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
const { cachedRootQuery } = useCachedRootQuery({
|
||||
objectMetadataItem: viewObjectMetadataItem,
|
||||
queryMethodName: QueryMethodName.FindMany,
|
||||
});
|
||||
|
||||
const companyViewId = cachedRootQuery?.views?.edges?.find(
|
||||
(view: any) =>
|
||||
view?.node?.objectMetadataId === companyObjectMetadataItem.id,
|
||||
const { records } = usePrefetchedData(PrefetchKey.AllViews);
|
||||
|
||||
const companyViewId = records.find(
|
||||
(view: any) => view?.objectMetadataId === companyObjectMetadataItem.id,
|
||||
)?.node.id;
|
||||
const defaultHomePagePath =
|
||||
'/objects/companies' + (companyViewId ? `?view=${companyViewId}` : '');
|
||||
|
||||
@ -13,6 +13,7 @@ import { ExceptionHandlerProvider } from '@/error-handler/components/ExceptionHa
|
||||
import { PromiseRejectionEffect } from '@/error-handler/components/PromiseRejectionEffect';
|
||||
import { ApolloMetadataClientProvider } from '@/object-metadata/components/ApolloMetadataClientProvider';
|
||||
import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
|
||||
import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider';
|
||||
import { IconsProvider } from '@/ui/display/icon/components/IconsProvider';
|
||||
import { DialogManager } from '@/ui/feedback/dialog-manager/components/DialogManager';
|
||||
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
|
||||
@ -47,18 +48,20 @@ root.render(
|
||||
<UserProvider>
|
||||
<ApolloMetadataClientProvider>
|
||||
<ObjectMetadataItemsProvider>
|
||||
<AppThemeProvider>
|
||||
<SnackBarProvider>
|
||||
<DialogManagerScope dialogManagerScopeId="dialog-manager">
|
||||
<DialogManager>
|
||||
<StrictMode>
|
||||
<PromiseRejectionEffect />
|
||||
<App />
|
||||
</StrictMode>
|
||||
</DialogManager>
|
||||
</DialogManagerScope>
|
||||
</SnackBarProvider>
|
||||
</AppThemeProvider>
|
||||
<PrefetchDataProvider>
|
||||
<AppThemeProvider>
|
||||
<SnackBarProvider>
|
||||
<DialogManagerScope dialogManagerScopeId="dialog-manager">
|
||||
<DialogManager>
|
||||
<StrictMode>
|
||||
<PromiseRejectionEffect />
|
||||
<App />
|
||||
</StrictMode>
|
||||
</DialogManager>
|
||||
</DialogManagerScope>
|
||||
</SnackBarProvider>
|
||||
</AppThemeProvider>
|
||||
</PrefetchDataProvider>
|
||||
<PageChangeEffect />
|
||||
</ObjectMetadataItemsProvider>
|
||||
</ApolloMetadataClientProvider>
|
||||
|
||||
@ -6,38 +6,38 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe
|
||||
import { Favorite } from '@/favorites/types/Favorite';
|
||||
import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/hooks/useGetObjectRecordIdentifierByNameSingular';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useFavorites = () => {
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState());
|
||||
|
||||
const favoriteObjectNameSingular = 'favorite';
|
||||
|
||||
const { objectMetadataItem: favoriteObjectMetadataItem } =
|
||||
useObjectMetadataItem({
|
||||
objectNameSingular: favoriteObjectNameSingular,
|
||||
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||
});
|
||||
|
||||
const { deleteOneRecord } = useDeleteOneRecord({
|
||||
objectNameSingular: favoriteObjectNameSingular,
|
||||
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||
});
|
||||
|
||||
const { updateOneRecord: updateOneFavorite } = useUpdateOneRecord({
|
||||
objectNameSingular: favoriteObjectNameSingular,
|
||||
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||
});
|
||||
|
||||
const { createOneRecord: createOneFavorite } = useCreateOneRecord({
|
||||
objectNameSingular: favoriteObjectNameSingular,
|
||||
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||
});
|
||||
|
||||
const { records: favorites } = useFindManyRecords<Favorite>({
|
||||
objectNameSingular: favoriteObjectNameSingular,
|
||||
});
|
||||
const { records: favorites } = usePrefetchedData<Favorite>(
|
||||
PrefetchKey.AllFavorites,
|
||||
);
|
||||
|
||||
const favoriteRelationFieldMetadataItems = useMemo(
|
||||
() =>
|
||||
|
||||
@ -1,37 +1,19 @@
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { QueryMethodName } from '@/object-metadata/types/QueryMethodName';
|
||||
import { useCachedRootQuery } from '@/object-record/cache/hooks/useCachedRootQuery';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
|
||||
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
|
||||
export const ObjectMetadataNavItems = () => {
|
||||
const { activeObjectMetadataItems, findObjectMetadataItemByNamePlural } =
|
||||
useObjectMetadataItemForSettings();
|
||||
const { activeObjectMetadataItems } = useObjectMetadataItemForSettings();
|
||||
const navigate = useNavigate();
|
||||
const { getIcon } = useIcons();
|
||||
const currentPath = useLocation().pathname;
|
||||
|
||||
const viewObjectMetadataItem = findObjectMetadataItemByNamePlural('views');
|
||||
|
||||
const { cachedRootQuery } = useCachedRootQuery({
|
||||
objectMetadataItem: viewObjectMetadataItem,
|
||||
queryMethodName: QueryMethodName.FindMany,
|
||||
});
|
||||
|
||||
const { records } = useFindManyRecords({
|
||||
skip: cachedRootQuery?.views,
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
useRecordsWithoutConnection: true,
|
||||
});
|
||||
|
||||
const views =
|
||||
records.length > 0
|
||||
? records
|
||||
: cachedRootQuery?.views?.edges?.map((edge: any) => edge?.node);
|
||||
const { records } = usePrefetchedData<GraphQLView>(PrefetchKey.AllViews);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -63,7 +45,7 @@ export const ObjectMetadataNavItems = () => {
|
||||
: -1;
|
||||
}),
|
||||
].map((objectMetadataItem) => {
|
||||
const viewId = views?.find(
|
||||
const viewId = records?.find(
|
||||
(view: any) => view?.objectMetadataId === objectMetadataItem.id,
|
||||
)?.id;
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ export const mapObjectMetadataToGraphQLQuery = ({
|
||||
eagerLoadedRelations,
|
||||
}: {
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
objectMetadataItem: Pick<ObjectMetadataItem, 'fields'>;
|
||||
objectMetadataItem: Pick<ObjectMetadataItem, 'nameSingular' | 'fields'>;
|
||||
depth?: number;
|
||||
eagerLoadedRelations?: Record<string, any>;
|
||||
}): any => {
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
import { useApolloClient } from '@apollo/client/react/hooks/useApolloClient';
|
||||
import gql from 'graphql-tag';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { QueryMethodName } from '@/object-metadata/types/QueryMethodName';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
|
||||
export const useCachedRootQuery = ({
|
||||
objectMetadataItem,
|
||||
queryMethodName,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem | undefined;
|
||||
queryMethodName: QueryMethodName;
|
||||
}) => {
|
||||
const apolloClient = useApolloClient();
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState());
|
||||
|
||||
if (!objectMetadataItem) {
|
||||
return { cachedRootQuery: null };
|
||||
}
|
||||
|
||||
const cacheReadFragment = gql`
|
||||
fragment RootQuery on Query {
|
||||
${
|
||||
QueryMethodName.FindMany === queryMethodName
|
||||
? objectMetadataItem.namePlural
|
||||
: objectMetadataItem.nameSingular
|
||||
}
|
||||
${QueryMethodName.FindMany === queryMethodName ? '{ edges { node ' : ''}
|
||||
${mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems,
|
||||
objectMetadataItem,
|
||||
depth: 0,
|
||||
})}
|
||||
${QueryMethodName.FindMany === queryMethodName ? '}}' : ''}
|
||||
}
|
||||
`;
|
||||
|
||||
const cachedRootQuery = apolloClient.readFragment({
|
||||
id: 'ROOT_QUERY',
|
||||
fragment: cacheReadFragment,
|
||||
});
|
||||
|
||||
return { cachedRootQuery };
|
||||
};
|
||||
@ -10,7 +10,10 @@ import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQu
|
||||
export const useUpsertFindManyRecordsQueryInCache = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
objectMetadataItem: Pick<
|
||||
ObjectMetadataItem,
|
||||
'fields' | 'namePlural' | 'nameSingular'
|
||||
>;
|
||||
}) => {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { getEdgeTypename } from '@/object-record/cache/utils/getEdgeTypename';
|
||||
import { getNodeTypename } from '@/object-record/cache/utils/getNodeTypename';
|
||||
import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge';
|
||||
|
||||
@ -10,11 +11,26 @@ export const getRecordEdgeFromRecord = <T extends ObjectRecord>({
|
||||
objectNameSingular: string;
|
||||
record: T;
|
||||
}) => {
|
||||
const nestedRecord = Object.fromEntries(
|
||||
Object.entries(record).map(([key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
return [
|
||||
key,
|
||||
getRecordConnectionFromRecords({
|
||||
objectNameSingular: key,
|
||||
records: value as ObjectRecord[],
|
||||
}),
|
||||
];
|
||||
}
|
||||
return [key, value];
|
||||
}),
|
||||
) as T; // Todo fix typing once we have investigated apollo edges / nodes removal
|
||||
|
||||
return {
|
||||
__typename: getEdgeTypename({ objectNameSingular }),
|
||||
node: {
|
||||
__typename: getNodeTypename({ objectNameSingular }),
|
||||
...record,
|
||||
...nestedRecord,
|
||||
},
|
||||
cursor: '',
|
||||
} as ObjectRecordEdge<T>;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { isNonEmptyArray } from '~/utils/isNonEmptyArray';
|
||||
@ -12,6 +14,7 @@ export const useGenerateFindManyRecordsForMultipleMetadataItemsQuery = ({
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
depth?: number;
|
||||
}) => {
|
||||
const allObjectMetadataItems = useRecoilValue(objectMetadataItemsState());
|
||||
const capitalizedObjectNameSingulars = objectMetadataItems.map(
|
||||
({ nameSingular }) => capitalize(nameSingular),
|
||||
);
|
||||
@ -44,7 +47,7 @@ export const useGenerateFindManyRecordsForMultipleMetadataItemsQuery = ({
|
||||
const limitPerMetadataItemArray = capitalizedObjectNameSingulars
|
||||
.map(
|
||||
(capitalizedObjectNameSingular) =>
|
||||
`$limit${capitalizedObjectNameSingular}: Float = 5`,
|
||||
`$limit${capitalizedObjectNameSingular}: Float`,
|
||||
)
|
||||
.join(', ');
|
||||
|
||||
@ -69,7 +72,7 @@ export const useGenerateFindManyRecordsForMultipleMetadataItemsQuery = ({
|
||||
)}){
|
||||
edges {
|
||||
node ${mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems,
|
||||
objectMetadataItems: allObjectMetadataItems,
|
||||
objectMetadataItem,
|
||||
depth,
|
||||
})}
|
||||
@ -80,6 +83,7 @@ export const useGenerateFindManyRecordsForMultipleMetadataItemsQuery = ({
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
totalCount
|
||||
}`,
|
||||
)
|
||||
.join('\n')}
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
|
||||
|
||||
export type QueryKey = {
|
||||
objectNameSingular: string;
|
||||
variables: ObjectRecordQueryVariables;
|
||||
depth: number;
|
||||
};
|
||||
@ -13,7 +13,7 @@ const query = gql`
|
||||
$filterNameSingular: NameSingularFilterInput
|
||||
$orderByNameSingular: NameSingularOrderByInput
|
||||
$lastCursorNameSingular: String
|
||||
$limitNameSingular: Float = 5
|
||||
$limitNameSingular: Float
|
||||
) {
|
||||
namePlural(
|
||||
filter: $filterNameSingular
|
||||
@ -33,6 +33,7 @@ const query = gql`
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import { PrefetchRunQueriesEffect } from '@/prefetch/components/PrefetchRunQueriesEffect';
|
||||
|
||||
export const PrefetchDataProvider = ({ children }: React.PropsWithChildren) => {
|
||||
return (
|
||||
<>
|
||||
<PrefetchRunQueriesEffect />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,53 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useGenerateFindManyRecordsForMultipleMetadataItemsQuery } from '@/object-record/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery';
|
||||
import { MultiObjectRecordQueryResult } from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
|
||||
import { usePrefetchRunQuery } from '@/prefetch/hooks/internal/usePrefetchRunQuery';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const PrefetchRunQueriesEffect = () => {
|
||||
const {
|
||||
objectMetadataItem: objectMetadataItemView,
|
||||
upsertRecordsInCache: upsertViewsInCache,
|
||||
} = usePrefetchRunQuery({
|
||||
prefetchKey: PrefetchKey.AllViews,
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const {
|
||||
objectMetadataItem: objectMetadataItemFavorite,
|
||||
upsertRecordsInCache: upsertFavoritesInCache,
|
||||
} = usePrefetchRunQuery({
|
||||
prefetchKey: PrefetchKey.AllFavorites,
|
||||
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||
});
|
||||
|
||||
const prefetchFindManyQuery =
|
||||
useGenerateFindManyRecordsForMultipleMetadataItemsQuery({
|
||||
objectMetadataItems: [objectMetadataItemView, objectMetadataItemFavorite],
|
||||
depth: 2,
|
||||
});
|
||||
|
||||
if (!isDefined(prefetchFindManyQuery)) {
|
||||
throw new Error('Could not prefetch recrds');
|
||||
}
|
||||
|
||||
const { data } = useQuery<MultiObjectRecordQueryResult>(
|
||||
prefetchFindManyQuery,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(data?.views)) {
|
||||
upsertViewsInCache(data.views);
|
||||
}
|
||||
|
||||
if (isDefined(data?.favorites)) {
|
||||
upsertFavoritesInCache(data.favorites);
|
||||
}
|
||||
}, [data, upsertViewsInCache, upsertFavoritesInCache]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -0,0 +1,9 @@
|
||||
import { QueryKey } from '@/object-record/query-keys/types/QueryKey';
|
||||
import { ALL_FAVORITES_QUERY_KEY } from '@/prefetch/query-keys/AllFavoritesQueryKey';
|
||||
import { ALL_VIEWS_QUERY_KEY } from '@/prefetch/query-keys/AllViewsQueryKey';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
|
||||
export const PREFETCH_CONFIG: Record<PrefetchKey, QueryKey> = {
|
||||
ALL_VIEWS: ALL_VIEWS_QUERY_KEY,
|
||||
ALL_FAVORITES: ALL_FAVORITES_QUERY_KEY,
|
||||
};
|
||||
@ -0,0 +1,55 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache';
|
||||
import { useMapConnectionToRecords } from '@/object-record/hooks/useMapConnectionToRecords';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection';
|
||||
import { ALL_VIEWS_QUERY_KEY } from '@/prefetch/query-keys/AllViewsQueryKey';
|
||||
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
|
||||
export type UsePrefetchRunQuery = {
|
||||
prefetchKey: PrefetchKey;
|
||||
objectNameSingular: CoreObjectNameSingular;
|
||||
};
|
||||
|
||||
export const usePrefetchRunQuery = <T extends ObjectRecord>({
|
||||
prefetchKey,
|
||||
objectNameSingular,
|
||||
}: UsePrefetchRunQuery) => {
|
||||
const setPrefetchDataIsLoadedLoaded = useSetRecoilState(
|
||||
prefetchIsLoadedFamilyState(prefetchKey),
|
||||
);
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: objectNameSingular,
|
||||
});
|
||||
|
||||
const { upsertFindManyRecordsQueryInCache } =
|
||||
useUpsertFindManyRecordsQueryInCache({
|
||||
objectMetadataItem: objectMetadataItem,
|
||||
});
|
||||
|
||||
const mapConnectionToRecords = useMapConnectionToRecords();
|
||||
|
||||
const upsertRecordsInCache = (records: ObjectRecordConnection<T>) => {
|
||||
upsertFindManyRecordsQueryInCache({
|
||||
queryVariables: ALL_VIEWS_QUERY_KEY.variables,
|
||||
depth: ALL_VIEWS_QUERY_KEY.depth,
|
||||
objectRecordsToOverwrite:
|
||||
mapConnectionToRecords({
|
||||
objectRecordConnection: records,
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
depth: 2,
|
||||
}) ?? [],
|
||||
});
|
||||
setPrefetchDataIsLoadedLoaded(true);
|
||||
};
|
||||
|
||||
return {
|
||||
objectMetadataItem,
|
||||
setPrefetchDataIsLoadedLoaded,
|
||||
upsertRecordsInCache,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,27 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { PREFETCH_CONFIG } from '@/prefetch/constants/PrefetchConfig';
|
||||
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
|
||||
export const usePrefetchedData = <T extends ObjectRecord>(
|
||||
prefetchKey: PrefetchKey,
|
||||
) => {
|
||||
const isDataPrefetched = useRecoilValue(
|
||||
prefetchIsLoadedFamilyState(prefetchKey),
|
||||
);
|
||||
const prefetchQueryKey = PREFETCH_CONFIG[prefetchKey];
|
||||
|
||||
const { records } = useFindManyRecords<T>({
|
||||
skip: !isDataPrefetched,
|
||||
...prefetchQueryKey,
|
||||
useRecordsWithoutConnection: true,
|
||||
});
|
||||
|
||||
return {
|
||||
isDataPrefetched,
|
||||
records,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { QueryKey } from '@/object-record/query-keys/types/QueryKey';
|
||||
|
||||
export const ALL_FAVORITES_QUERY_KEY: QueryKey = {
|
||||
objectNameSingular: CoreObjectNameSingular.Favorite,
|
||||
variables: {},
|
||||
depth: 1,
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { QueryKey } from '@/object-record/query-keys/types/QueryKey';
|
||||
|
||||
export const ALL_VIEWS_QUERY_KEY: QueryKey = {
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
variables: {},
|
||||
depth: 1,
|
||||
};
|
||||
@ -0,0 +1,10 @@
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
|
||||
|
||||
export const prefetchIsLoadedFamilyState = createFamilyState<
|
||||
boolean,
|
||||
PrefetchKey
|
||||
>({
|
||||
key: 'prefetchIsLoadedFamilyState',
|
||||
defaultValue: false,
|
||||
});
|
||||
@ -0,0 +1,4 @@
|
||||
export enum PrefetchKey {
|
||||
AllViews = 'ALL_VIEWS',
|
||||
AllFavorites = 'ALL_FAVORITES',
|
||||
}
|
||||
@ -2,8 +2,8 @@ import { useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
@ -31,25 +31,26 @@ export const ViewBarEffect = () => {
|
||||
const viewObjectMetadataId = useRecoilValue(viewObjectMetadataIdState);
|
||||
const setCurrentViewId = useSetRecoilState(currentViewIdState);
|
||||
|
||||
const { records: newViews } = useFindManyRecords<GraphQLView>({
|
||||
skip: !viewObjectMetadataId,
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
filter: {
|
||||
objectMetadataId: { eq: viewObjectMetadataId },
|
||||
},
|
||||
useRecordsWithoutConnection: true,
|
||||
});
|
||||
const { records: newViews } = usePrefetchedData<GraphQLView>(
|
||||
PrefetchKey.AllViews,
|
||||
);
|
||||
|
||||
const newViewsOnCurrentObject = newViews.filter(
|
||||
(view) => view.objectMetadataId === viewObjectMetadataId,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!newViews.length) return;
|
||||
if (!newViewsOnCurrentObject.length) return;
|
||||
|
||||
if (!isDeeplyEqual(views, newViews)) {
|
||||
setViews(newViews);
|
||||
if (!isDeeplyEqual(views, newViewsOnCurrentObject)) {
|
||||
setViews(newViewsOnCurrentObject);
|
||||
}
|
||||
|
||||
const currentView =
|
||||
newViews.find((view) => view.id === currentViewIdFromUrl) ??
|
||||
newViews[0] ??
|
||||
newViewsOnCurrentObject.find(
|
||||
(view) => view.id === currentViewIdFromUrl,
|
||||
) ??
|
||||
newViewsOnCurrentObject[0] ??
|
||||
null;
|
||||
|
||||
if (isUndefinedOrNull(currentView)) return;
|
||||
@ -69,17 +70,17 @@ export const ViewBarEffect = () => {
|
||||
loadViewFields,
|
||||
loadViewFilters,
|
||||
loadViewSorts,
|
||||
newViews,
|
||||
newViewsOnCurrentObject,
|
||||
setCurrentViewId,
|
||||
setViews,
|
||||
views,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentViewIdFromUrl || !newViews.length) return;
|
||||
if (!currentViewIdFromUrl || !newViewsOnCurrentObject.length) return;
|
||||
|
||||
loadView(currentViewIdFromUrl);
|
||||
}, [currentViewIdFromUrl, loadView, newViews]);
|
||||
}, [currentViewIdFromUrl, loadView, newViewsOnCurrentObject]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user