diff --git a/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts b/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts index 8b72885a6..04374b388 100644 --- a/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts +++ b/packages/twenty-front/src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts @@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react'; import { RecoilRoot, useSetRecoilState } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; +import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations'; @@ -23,6 +24,9 @@ const renderHooks = ({ const { result } = renderHook( () => { const setCurrentUser = useSetRecoilState(currentUserState); + const setCurrentUserWorkspace = useSetRecoilState( + currentUserWorkspaceState, + ); const setObjectMetadataItems = useSetRecoilState( objectMetadataItemsState, ); @@ -56,6 +60,7 @@ const renderHooks = ({ if (withCurrentUser) { setCurrentUser(mockedUserData); + setCurrentUserWorkspace(mockedUserData.currentUserWorkspace); } return useDefaultHomePagePath(); }, diff --git a/packages/twenty-front/src/modules/navigation/hooks/useDefaultHomePagePath.ts b/packages/twenty-front/src/modules/navigation/hooks/useDefaultHomePagePath.ts index 26b245ce5..a8a965f02 100644 --- a/packages/twenty-front/src/modules/navigation/hooks/useDefaultHomePagePath.ts +++ b/packages/twenty-front/src/modules/navigation/hooks/useDefaultHomePagePath.ts @@ -2,8 +2,11 @@ import { currentUserState } from '@/auth/states/currentUserState'; import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState'; import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState'; import { AppPath } from '@/types/AppPath'; +import { SettingsPath } from '@/types/SettingsPath'; +import isEmpty from 'lodash.isempty'; import { useCallback, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; @@ -11,10 +14,23 @@ import { getAppPath } from '~/utils/navigation/getAppPath'; export const useDefaultHomePagePath = () => { const currentUser = useRecoilValue(currentUserState); + const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); + const { activeNonSystemObjectMetadataItems, alphaSortedActiveNonSystemObjectMetadataItems, } = useFilteredObjectMetadataItems(); + + const readableAlphaSortedActiveNonSystemObjectMetadataItems = useMemo(() => { + return alphaSortedActiveNonSystemObjectMetadataItems.filter((item) => { + const objectPermissions = objectPermissionsByObjectMetadataId[item.id]; + return objectPermissions?.canReadObjectRecords; + }); + }, [ + alphaSortedActiveNonSystemObjectMetadataItems, + objectPermissionsByObjectMetadataId, + ]); + const prefetchViews = useRecoilValue(prefetchViewsState); const lastVisitedObjectMetadataItemId = useRecoilValue( lastVisitedObjectMetadataItemIdState, @@ -39,7 +55,7 @@ export const useDefaultHomePagePath = () => { const firstObjectPathInfo = useMemo(() => { const [firstObjectMetadataItem] = - alphaSortedActiveNonSystemObjectMetadataItems; + readableAlphaSortedActiveNonSystemObjectMetadataItems; if (!isDefined(firstObjectMetadataItem)) { return null; @@ -48,10 +64,14 @@ export const useDefaultHomePagePath = () => { const view = getFirstView(firstObjectMetadataItem?.id); return { objectMetadataItem: firstObjectMetadataItem, view }; - }, [alphaSortedActiveNonSystemObjectMetadataItems, getFirstView]); + }, [readableAlphaSortedActiveNonSystemObjectMetadataItems, getFirstView]); const defaultObjectPathInfo = useMemo(() => { - if (!isDefined(lastVisitedObjectMetadataItemId)) { + if ( + !isDefined(lastVisitedObjectMetadataItemId) || + !objectPermissionsByObjectMetadataId[lastVisitedObjectMetadataItemId] + ?.canReadObjectRecords + ) { return firstObjectPathInfo; } @@ -72,6 +92,7 @@ export const useDefaultHomePagePath = () => { getActiveObjectMetadataItemMatchingId, getFirstView, lastVisitedObjectMetadataItemId, + objectPermissionsByObjectMetadataId, ]); const defaultHomePagePath = useMemo(() => { @@ -79,6 +100,10 @@ export const useDefaultHomePagePath = () => { return AppPath.SignInUp; } + if (isEmpty(readableAlphaSortedActiveNonSystemObjectMetadataItems)) { + return `${AppPath.Settings}/${SettingsPath.ProfilePage}`; + } + if (!isDefined(defaultObjectPathInfo)) { return AppPath.NotFound; } @@ -91,7 +116,11 @@ export const useDefaultHomePagePath = () => { { objectNamePlural: namePlural }, viewId ? { viewId } : undefined, ); - }, [currentUser, defaultObjectPathInfo]); + }, [ + currentUser, + defaultObjectPathInfo, + readableAlphaSortedActiveNonSystemObjectMetadataItems, + ]); return { defaultHomePagePath }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx index 16150a2bc..40aef77c9 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx @@ -5,6 +5,8 @@ import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionM import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; +import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject'; +import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; @@ -23,8 +25,7 @@ import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewCompon import styled from '@emotion/styled'; import { useRecoilCallback } from 'recoil'; import { capitalize } from 'twenty-shared/utils'; -import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject'; -import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; +import { NotFound } from '~/pages/not-found/NotFound'; const StyledIndexContainer = styled.div` display: flex; @@ -68,7 +69,7 @@ export const RecordIndexContainerGater = () => { const hasObjectReadPermissions = objectPermissions.canReadObjectRecords; if (!hasObjectReadPermissions) { - return <>; + return ; } return ( diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 3d9ac383d..6f174bcee 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -128,6 +128,12 @@ export const mockedUserData: MockedUser = { currentWorkspace: mockCurrentWorkspace, currentUserWorkspace: { settingsPermissions: [SettingPermissionType.WORKSPACE_MEMBERS], + objectPermissions: [ + { + objectMetadataId: '4a45f524-b8cb-40e8-8450-28e402b442cf', + canReadObjectRecords: true, + }, + ], }, locale: 'en', workspaces: [{ workspace: mockCurrentWorkspace }],