diff --git a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts
index 89fa8ac42..b76e2d51a 100644
--- a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts
+++ b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts
@@ -3,6 +3,8 @@ import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePat
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
import { AppPath } from '@/types/AppPath';
import { useIsWorkspaceActivationStatusSuspended } from '@/workspace/hooks/useIsWorkspaceActivationStatusSuspended';
+import { useParams } from 'react-router-dom';
+import { useRecoilValue } from 'recoil';
import { OnboardingStatus } from '~/generated/graphql';
@@ -47,8 +49,30 @@ jest.mocked(useDefaultHomePagePath).mockReturnValue({
defaultHomePagePath,
});
+jest.mock('react-router-dom');
+const setupMockUseParams = (objectNamePlural?: string) => {
+ jest
+ .mocked(useParams)
+ .mockReturnValueOnce({ objectNamePlural: objectNamePlural ?? '' });
+};
+
+jest.mock('recoil');
+const setupMockRecoil = (objectNamePlural?: string) => {
+ jest
+ .mocked(useRecoilValue)
+ .mockReturnValueOnce([{ namePlural: objectNamePlural ?? '' }]);
+};
+
// prettier-ignore
-const testCases = [
+const testCases: {
+ loc: AppPath;
+ isLoggedIn: boolean;
+ isWorkspaceSuspended: boolean;
+ onboardingStatus: OnboardingStatus | undefined;
+ res: string | undefined;
+ objectNamePluralFromParams?: string;
+ objectNamePluralFromMetadata?: string;
+}[] = [
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' },
{ loc: AppPath.Verify, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
@@ -183,6 +207,8 @@ const testCases = [
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
+ { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined, objectNamePluralFromParams: 'existing-object', objectNamePluralFromMetadata: 'existing-object' },
+ { loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: AppPath.NotFound, objectNamePluralFromParams: 'non-existing-object', objectNamePluralFromMetadata: 'existing-object' },
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: '/settings/billing' },
@@ -248,6 +274,9 @@ describe('usePageChangeEffectNavigateLocation', () => {
testCase.isWorkspaceSuspended,
);
setupMockIsLogged(testCase.isLoggedIn);
+ setupMockUseParams(testCase.objectNamePluralFromParams);
+ setupMockRecoil(testCase.objectNamePluralFromMetadata);
+
expect(usePageChangeEffectNavigateLocation()).toEqual(testCase.res);
});
});
@@ -257,7 +286,9 @@ describe('usePageChangeEffectNavigateLocation', () => {
expect(testCases.length).toEqual(
(Object.keys(AppPath).length - UNTESTED_APP_PATHS.length) *
(Object.keys(OnboardingStatus).length +
- ['isWorkspaceSuspended:true', 'isWorkspaceSuspended:false'].length),
+ ['isWorkspaceSuspended:true', 'isWorkspaceSuspended:false']
+ .length) +
+ ['nonExistingObjectInParam', 'existingObjectInParam:false'].length,
);
});
});
diff --git a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts
index 76858a93e..0ebfd2f2c 100644
--- a/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts
+++ b/packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts
@@ -1,9 +1,13 @@
import { useIsLogged } from '@/auth/hooks/useIsLogged';
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
+import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
import { AppPath } from '@/types/AppPath';
import { SettingsPath } from '@/types/SettingsPath';
import { useIsWorkspaceActivationStatusSuspended } from '@/workspace/hooks/useIsWorkspaceActivationStatusSuspended';
+import { useParams } from 'react-router-dom';
+import { useRecoilValue } from 'recoil';
+import { isDefined } from 'twenty-shared';
import { OnboardingStatus } from '~/generated/graphql';
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
@@ -33,6 +37,12 @@ export const usePageChangeEffectNavigateLocation = () => {
isMatchingLocation(AppPath.PlanRequired) ||
isMatchingLocation(AppPath.PlanRequiredSuccess);
+ const objectNamePlural = useParams().objectNamePlural ?? '';
+ const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
+ const objectMetadataItem = objectMetadataItems.find(
+ (objectMetadataItem) => objectMetadataItem.namePlural === objectNamePlural,
+ );
+
if (isMatchingOpenRoute) {
return;
}
@@ -96,5 +106,12 @@ export const usePageChangeEffectNavigateLocation = () => {
return defaultHomePagePath;
}
+ if (
+ isMatchingLocation(AppPath.RecordIndexPage) &&
+ !isDefined(objectMetadataItem)
+ ) {
+ return AppPath.NotFound;
+ }
+
return;
};
diff --git a/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx b/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx
index f5c45a946..39c0deab2 100644
--- a/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx
+++ b/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx
@@ -61,8 +61,8 @@ export const AppRouterProviders = () => {
+
-