fix: settings error layout (#7674)
Fixes: #7460  **Changes & Why** Since all the settings pages lie in the Outlet of DefaultLayout, there was no way to handle it apart from creating a separate errorFallback for the settings route. So, I created a settingsErrorFallback component that uses the same styling of settings pages. Created ErrorBoundaryWrapper that checks if its settings route then show SettingsErrorFallback else show GenericErrorFallback. Now, for the breadcrumb part. I found that all the settings pages use hardcoded title. So, I created generateBreadcrumbLinks function that will provide different title and links based on how it's respective settings page has them. If this approach looks fine, I will add the other remaining titles and links to the generateBreadcrumbLinks function and move that whole function to its separate file. And will fix linting errors. If there is any different approach to handle it, lemme know. I'm happy to implement it.
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { ErrorInfo, ReactNode } from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import * as Sentry from '@sentry/react';
|
||||
|
||||
import { GenericErrorFallback } from '@/error-handler/components/GenericErrorFallback';
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { ThemeProvider, useTheme } from '@emotion/react';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||
import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FallbackProps } from 'react-error-boundary';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
@ -11,7 +12,6 @@ import {
|
||||
AnimatedPlaceholderEmptyTitle,
|
||||
Button,
|
||||
IconRefresh,
|
||||
THEME_LIGHT,
|
||||
} from 'twenty-ui';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
@ -31,27 +31,28 @@ export const GenericErrorFallback = ({
|
||||
}
|
||||
}, [previousLocation, location, resetErrorBoundary]);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={isEmpty(theme) ? THEME_LIGHT : theme}>
|
||||
<AnimatedPlaceholderEmptyContainer>
|
||||
<AnimatedPlaceholder type="errorIndex" />
|
||||
<AnimatedPlaceholderEmptyTextContainer>
|
||||
<AnimatedPlaceholderEmptyTitle>
|
||||
Server’s on a coffee break
|
||||
</AnimatedPlaceholderEmptyTitle>
|
||||
<AnimatedPlaceholderEmptySubTitle>
|
||||
{error.message}
|
||||
</AnimatedPlaceholderEmptySubTitle>
|
||||
</AnimatedPlaceholderEmptyTextContainer>
|
||||
<Button
|
||||
Icon={IconRefresh}
|
||||
title="Reload"
|
||||
variant={'secondary'}
|
||||
onClick={() => resetErrorBoundary()}
|
||||
/>
|
||||
</AnimatedPlaceholderEmptyContainer>
|
||||
</ThemeProvider>
|
||||
<PageContainer>
|
||||
<PageHeader />
|
||||
<PageBody>
|
||||
<AnimatedPlaceholderEmptyContainer>
|
||||
<AnimatedPlaceholder type="errorIndex" />
|
||||
<AnimatedPlaceholderEmptyTextContainer>
|
||||
<AnimatedPlaceholderEmptyTitle>
|
||||
Server’s on a coffee break
|
||||
</AnimatedPlaceholderEmptyTitle>
|
||||
<AnimatedPlaceholderEmptySubTitle>
|
||||
{error.message}
|
||||
</AnimatedPlaceholderEmptySubTitle>
|
||||
</AnimatedPlaceholderEmptyTextContainer>
|
||||
<Button
|
||||
Icon={IconRefresh}
|
||||
title="Reload"
|
||||
variant={'secondary'}
|
||||
onClick={() => resetErrorBoundary()}
|
||||
/>
|
||||
</AnimatedPlaceholderEmptyContainer>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -10,11 +10,11 @@ import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/S
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useScreenSize } from 'twenty-ui';
|
||||
import { css, Global, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { AnimatePresence, LayoutGroup, motion } from 'framer-motion';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { useScreenSize } from 'twenty-ui';
|
||||
|
||||
const StyledLayout = styled.div`
|
||||
background: ${({ theme }) => theme.background.noisy};
|
||||
|
||||
@ -80,7 +80,7 @@ const StyledTopBarButtonContainer = styled.div`
|
||||
`;
|
||||
|
||||
type PageHeaderProps = {
|
||||
title: ReactNode;
|
||||
title?: ReactNode;
|
||||
hasClosePageButton?: boolean;
|
||||
onClosePage?: () => void;
|
||||
hasPaginationButtons?: boolean;
|
||||
@ -147,13 +147,15 @@ export const PageHeader = ({
|
||||
</>
|
||||
)}
|
||||
{Icon && <Icon size={theme.icon.size.md} />}
|
||||
<StyledTitleContainer data-testid="top-bar-title">
|
||||
{typeof title === 'string' ? (
|
||||
<OverflowingTextWithTooltip text={title} />
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
</StyledTitleContainer>
|
||||
{title && (
|
||||
<StyledTitleContainer data-testid="top-bar-title">
|
||||
{typeof title === 'string' ? (
|
||||
<OverflowingTextWithTooltip text={title} />
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
</StyledTitleContainer>
|
||||
)}
|
||||
</StyledTopBarIconStyledTitleContainer>
|
||||
</StyledLeftContainer>
|
||||
<StyledPageActionContainer>{children}</StyledPageActionContainer>
|
||||
|
||||
Reference in New Issue
Block a user