Fix page change effect being rerun after changes on views (#12869)
`useDefaultHomePagePath` was rerendered each time a view was changed, so the PageChangeEffect reran every time a view was updated, but we only want this effect to run on page change.
This commit is contained in:
@ -6,6 +6,7 @@ import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceSta
|
|||||||
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||||
|
import { arePrefetchViewsLoadedState } from '@/prefetch/states/arePrefetchViewsLoaded';
|
||||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
@ -31,8 +32,12 @@ const renderHooks = ({
|
|||||||
objectMetadataItemsState,
|
objectMetadataItemsState,
|
||||||
);
|
);
|
||||||
const setPrefetchViews = useSetRecoilState(prefetchViewsState);
|
const setPrefetchViews = useSetRecoilState(prefetchViewsState);
|
||||||
|
const setArePrefetchViewsLoaded = useSetRecoilState(
|
||||||
|
arePrefetchViewsLoadedState,
|
||||||
|
);
|
||||||
|
|
||||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
setArePrefetchViewsLoaded(true);
|
||||||
|
|
||||||
if (withExistingView) {
|
if (withExistingView) {
|
||||||
setPrefetchViews([
|
setPrefetchViews([
|
||||||
@ -56,6 +61,8 @@ const renderHooks = ({
|
|||||||
__typename: 'View',
|
__typename: 'View',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
} else {
|
||||||
|
setPrefetchViews([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (withCurrentUser) {
|
if (withCurrentUser) {
|
||||||
@ -70,6 +77,7 @@ const renderHooks = ({
|
|||||||
);
|
);
|
||||||
return { result };
|
return { result };
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('useDefaultHomePagePath', () => {
|
describe('useDefaultHomePagePath', () => {
|
||||||
it('should return proper path when no currentUser', () => {
|
it('should return proper path when no currentUser', () => {
|
||||||
const { result } = renderHooks({
|
const { result } = renderHooks({
|
||||||
|
|||||||
@ -3,12 +3,13 @@ import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVi
|
|||||||
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||||
|
import { arePrefetchViewsLoadedState } from '@/prefetch/states/arePrefetchViewsLoaded';
|
||||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import isEmpty from 'lodash.isempty';
|
import isEmpty from 'lodash.isempty';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { getAppPath } from '~/utils/navigation/getAppPath';
|
import { getAppPath } from '~/utils/navigation/getAppPath';
|
||||||
|
|
||||||
@ -21,6 +22,8 @@ export const useDefaultHomePagePath = () => {
|
|||||||
alphaSortedActiveNonSystemObjectMetadataItems,
|
alphaSortedActiveNonSystemObjectMetadataItems,
|
||||||
} = useFilteredObjectMetadataItems();
|
} = useFilteredObjectMetadataItems();
|
||||||
|
|
||||||
|
const arePrefetchViewsLoaded = useRecoilValue(arePrefetchViewsLoadedState);
|
||||||
|
|
||||||
const readableAlphaSortedActiveNonSystemObjectMetadataItems = useMemo(() => {
|
const readableAlphaSortedActiveNonSystemObjectMetadataItems = useMemo(() => {
|
||||||
return alphaSortedActiveNonSystemObjectMetadataItems.filter((item) => {
|
return alphaSortedActiveNonSystemObjectMetadataItems.filter((item) => {
|
||||||
const objectPermissions = objectPermissionsByObjectMetadataId[item.id];
|
const objectPermissions = objectPermissionsByObjectMetadataId[item.id];
|
||||||
@ -31,11 +34,6 @@ export const useDefaultHomePagePath = () => {
|
|||||||
objectPermissionsByObjectMetadataId,
|
objectPermissionsByObjectMetadataId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const prefetchViews = useRecoilValue(prefetchViewsState);
|
|
||||||
const lastVisitedObjectMetadataItemId = useRecoilValue(
|
|
||||||
lastVisitedObjectMetadataItemIdState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const getActiveObjectMetadataItemMatchingId = useCallback(
|
const getActiveObjectMetadataItemMatchingId = useCallback(
|
||||||
(objectMetadataId: string) => {
|
(objectMetadataId: string) => {
|
||||||
return activeNonSystemObjectMetadataItems.find(
|
return activeNonSystemObjectMetadataItems.find(
|
||||||
@ -45,12 +43,21 @@ export const useDefaultHomePagePath = () => {
|
|||||||
[activeNonSystemObjectMetadataItems],
|
[activeNonSystemObjectMetadataItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const getFirstView = useCallback(
|
const getFirstView = useRecoilCallback(
|
||||||
(objectMetadataItemId: string | undefined | null) =>
|
({ snapshot }) => {
|
||||||
prefetchViews.find(
|
return (objectMetadataItemId: string | undefined | null) => {
|
||||||
(view) => view.objectMetadataId === objectMetadataItemId,
|
if (!arePrefetchViewsLoaded) {
|
||||||
),
|
return undefined;
|
||||||
[prefetchViews],
|
}
|
||||||
|
|
||||||
|
const views = snapshot.getLoadable(prefetchViewsState).getValue();
|
||||||
|
|
||||||
|
return views.find(
|
||||||
|
(view) => view.objectMetadataId === objectMetadataItemId,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[arePrefetchViewsLoaded],
|
||||||
);
|
);
|
||||||
|
|
||||||
const firstObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
|
const firstObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
|
||||||
@ -64,38 +71,51 @@ export const useDefaultHomePagePath = () => {
|
|||||||
const view = getFirstView(firstObjectMetadataItem?.id);
|
const view = getFirstView(firstObjectMetadataItem?.id);
|
||||||
|
|
||||||
return { objectMetadataItem: firstObjectMetadataItem, view };
|
return { objectMetadataItem: firstObjectMetadataItem, view };
|
||||||
}, [readableAlphaSortedActiveNonSystemObjectMetadataItems, getFirstView]);
|
}, [getFirstView, readableAlphaSortedActiveNonSystemObjectMetadataItems]);
|
||||||
|
|
||||||
const defaultObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
|
const getDefaultObjectPathInfo = useRecoilCallback(
|
||||||
if (
|
({ snapshot }) => {
|
||||||
!isDefined(lastVisitedObjectMetadataItemId) ||
|
return () => {
|
||||||
!objectPermissionsByObjectMetadataId[lastVisitedObjectMetadataItemId]
|
const lastVisitedObjectMetadataItemId = snapshot
|
||||||
?.canReadObjectRecords
|
.getLoadable(lastVisitedObjectMetadataItemIdState)
|
||||||
) {
|
.getValue();
|
||||||
return firstObjectPathInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastVisitedObjectMetadataItem = getActiveObjectMetadataItemMatchingId(
|
if (
|
||||||
lastVisitedObjectMetadataItemId,
|
!isDefined(lastVisitedObjectMetadataItemId) ||
|
||||||
);
|
!objectPermissionsByObjectMetadataId[lastVisitedObjectMetadataItemId]
|
||||||
|
?.canReadObjectRecords
|
||||||
|
) {
|
||||||
|
return firstObjectPathInfo;
|
||||||
|
}
|
||||||
|
|
||||||
if (isDefined(lastVisitedObjectMetadataItem)) {
|
const lastVisitedObjectMetadataItem =
|
||||||
return {
|
getActiveObjectMetadataItemMatchingId(
|
||||||
view: getFirstView(lastVisitedObjectMetadataItemId),
|
lastVisitedObjectMetadataItemId,
|
||||||
objectMetadataItem: lastVisitedObjectMetadataItem,
|
);
|
||||||
|
|
||||||
|
if (isDefined(lastVisitedObjectMetadataItem)) {
|
||||||
|
return {
|
||||||
|
view: getFirstView(lastVisitedObjectMetadataItemId),
|
||||||
|
objectMetadataItem: lastVisitedObjectMetadataItem,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstObjectPathInfo;
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
|
[
|
||||||
return firstObjectPathInfo;
|
firstObjectPathInfo,
|
||||||
}, [
|
getActiveObjectMetadataItemMatchingId,
|
||||||
firstObjectPathInfo,
|
getFirstView,
|
||||||
getActiveObjectMetadataItemMatchingId,
|
objectPermissionsByObjectMetadataId,
|
||||||
getFirstView,
|
],
|
||||||
lastVisitedObjectMetadataItemId,
|
);
|
||||||
objectPermissionsByObjectMetadataId,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const defaultHomePagePath = useMemo(() => {
|
const defaultHomePagePath = useMemo(() => {
|
||||||
|
if (!arePrefetchViewsLoaded) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isDefined(currentUser)) {
|
if (!isDefined(currentUser)) {
|
||||||
return AppPath.SignInUp;
|
return AppPath.SignInUp;
|
||||||
}
|
}
|
||||||
@ -104,6 +124,8 @@ export const useDefaultHomePagePath = () => {
|
|||||||
return `${AppPath.Settings}/${SettingsPath.ProfilePage}`;
|
return `${AppPath.Settings}/${SettingsPath.ProfilePage}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultObjectPathInfo = getDefaultObjectPathInfo();
|
||||||
|
|
||||||
if (!isDefined(defaultObjectPathInfo)) {
|
if (!isDefined(defaultObjectPathInfo)) {
|
||||||
return AppPath.NotFound;
|
return AppPath.NotFound;
|
||||||
}
|
}
|
||||||
@ -117,8 +139,9 @@ export const useDefaultHomePagePath = () => {
|
|||||||
viewId ? { viewId } : undefined,
|
viewId ? { viewId } : undefined,
|
||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
|
arePrefetchViewsLoaded,
|
||||||
currentUser,
|
currentUser,
|
||||||
defaultObjectPathInfo,
|
getDefaultObjectPathInfo,
|
||||||
readableAlphaSortedActiveNonSystemObjectMetadataItems,
|
readableAlphaSortedActiveNonSystemObjectMetadataItems,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadat
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { findAllViewsOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory';
|
import { findAllViewsOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory';
|
||||||
|
import { arePrefetchViewsLoadedState } from '@/prefetch/states/arePrefetchViewsLoaded';
|
||||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||||
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
@ -45,6 +46,7 @@ export const PrefetchRunViewQueryEffect = () => {
|
|||||||
|
|
||||||
if (!isDeeplyEqual(existingViews, views)) {
|
if (!isDeeplyEqual(existingViews, views)) {
|
||||||
set(prefetchViewsState, views);
|
set(prefetchViewsState, views);
|
||||||
|
set(arePrefetchViewsLoadedState, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { createState } from 'twenty-ui/utilities';
|
||||||
|
|
||||||
|
export const arePrefetchViewsLoadedState = createState<boolean>({
|
||||||
|
key: 'arePrefetchViewsLoadedState',
|
||||||
|
defaultValue: false,
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user