routeNotFound.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import {useLayoutEffect} from 'react';
  2. import * as Sentry from '@sentry/react';
  3. import NotFound from 'sentry/components/errors/notFound';
  4. import Footer from 'sentry/components/footer';
  5. import * as Layout from 'sentry/components/layouts/thirds';
  6. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  7. import Sidebar from 'sentry/components/sidebar';
  8. import {t} from 'sentry/locale';
  9. import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
  10. import {useLastKnownRoute} from 'sentry/views/lastKnownRouteContextProvider';
  11. type Props = RouteComponentProps<{}, {}>;
  12. function RouteNotFound({router, location}: Props) {
  13. const {pathname, search, hash} = location;
  14. const lastKnownRoute = useLastKnownRoute();
  15. const isMissingSlash = pathname[pathname.length - 1] !== '/';
  16. useLayoutEffect(() => {
  17. // Attempt to fix trailing slashes first
  18. if (isMissingSlash) {
  19. router.replace(`${pathname}/${search}${hash}`);
  20. return;
  21. }
  22. Sentry.withScope(scope => {
  23. scope.setFingerprint(['RouteNotFound']);
  24. scope.setTag('isMissingSlash', isMissingSlash);
  25. scope.setTag('pathname', pathname);
  26. scope.setTag('lastKnownRoute', lastKnownRoute);
  27. Sentry.captureException(new Error('Route not found'));
  28. });
  29. }, [pathname, search, hash, isMissingSlash, router, lastKnownRoute]);
  30. if (isMissingSlash) {
  31. return null;
  32. }
  33. return (
  34. <SentryDocumentTitle title={t('Page Not Found')}>
  35. <div className="app">
  36. <Sidebar />
  37. <Layout.Page withPadding>
  38. <NotFound />
  39. </Layout.Page>
  40. <Footer />
  41. </div>
  42. </SentryDocumentTitle>
  43. );
  44. }
  45. export default RouteNotFound;