0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

fix(console): invalid guide url should show 404 not found (#4367)

This commit is contained in:
Charles Zhao 2023-08-20 02:05:29 -05:00 committed by GitHub
parent 4a532a358d
commit 5b1039267f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 54 deletions

View file

@ -55,6 +55,14 @@
margin-top: _.unit(6); margin-top: _.unit(6);
} }
.notFound {
width: 100%;
svg {
margin-top: 10%;
}
}
.actionBar { .actionBar {
position: absolute; position: absolute;
inset: auto 0 0 0; inset: auto 0 0 0;

View file

@ -12,6 +12,7 @@ import CodeEditor from '@/ds-components/CodeEditor';
import TextLink from '@/ds-components/TextLink'; import TextLink from '@/ds-components/TextLink';
import useCustomDomain from '@/hooks/use-custom-domain'; import useCustomDomain from '@/hooks/use-custom-domain';
import DetailsSummary from '@/mdx-components/DetailsSummary'; import DetailsSummary from '@/mdx-components/DetailsSummary';
import NotFound from '@/pages/NotFound';
import GuideHeader from '../GuideHeader'; import GuideHeader from '../GuideHeader';
import StepsSkeleton from '../StepsSkeleton'; import StepsSkeleton from '../StepsSkeleton';
@ -50,7 +51,7 @@ export const GuideContext = createContext<GuideContextType>({
type Props = { type Props = {
className?: string; className?: string;
guideId: string; guideId: string;
app?: ApplicationResponse; app: ApplicationResponse;
isCompact?: boolean; isCompact?: boolean;
onClose: () => void; onClose: () => void;
}; };
@ -61,15 +62,12 @@ function Guide({ className, guideId, app, isCompact, onClose }: Props) {
const isCustomDomainActive = customDomain?.status === DomainStatus.Active; const isCustomDomainActive = customDomain?.status === DomainStatus.Active;
const guide = guides.find(({ id }) => id === guideId); const guide = guides.find(({ id }) => id === guideId);
if (!app || !guide) { const GuideComponent = guide?.Component;
throw new Error('Invalid app or guide');
}
const GuideComponent = guide.Component;
const memorizedContext = useMemo( const memorizedContext = useMemo(
() => () =>
({ conditional(
!!guide && {
metadata: guide.metadata, metadata: guide.metadata,
Logo: guide.Logo, Logo: guide.Logo,
app, app,
@ -82,7 +80,8 @@ function Guide({ className, guideId, app, isCompact, onClose }: Props) {
origin: 'http://localhost:3001/', origin: 'http://localhost:3001/',
callback: 'http://localhost:3001/callback', callback: 'http://localhost:3001/callback',
}, },
}) satisfies GuideContextType, }
) satisfies GuideContextType | undefined,
[guide, app, tenantEndpoint, isCustomDomainActive, isCompact] [guide, app, tenantEndpoint, isCustomDomainActive, isCompact]
); );
@ -90,6 +89,7 @@ function Guide({ className, guideId, app, isCompact, onClose }: Props) {
<div className={classNames(styles.container, className)}> <div className={classNames(styles.container, className)}>
{!isCompact && <GuideHeader onClose={onClose} />} {!isCompact && <GuideHeader onClose={onClose} />}
<div className={styles.content}> <div className={styles.content}>
{memorizedContext ? (
<GuideContext.Provider value={memorizedContext}> <GuideContext.Provider value={memorizedContext}>
<MDXProvider <MDXProvider
components={{ components={{
@ -118,11 +118,14 @@ function Guide({ className, guideId, app, isCompact, onClose }: Props) {
}} }}
> >
<Suspense fallback={<StepsSkeleton />}> <Suspense fallback={<StepsSkeleton />}>
{tenantEndpoint && <GuideComponent {...memorizedContext} />} {tenantEndpoint && GuideComponent && <GuideComponent {...memorizedContext} />}
</Suspense> </Suspense>
</MDXProvider> </MDXProvider>
</GuideContext.Provider> </GuideContext.Provider>
{!isCompact && ( ) : (
<NotFound className={styles.notFound} />
)}
{!isCompact && memorizedContext && (
<nav className={styles.actionBar}> <nav className={styles.actionBar}>
<div className={styles.layout}> <div className={styles.layout}>
<Button <Button

View file

@ -1,4 +1,5 @@
import { Theme } from '@logto/schemas'; import { Theme } from '@logto/schemas';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
@ -10,13 +11,17 @@ import useTheme from '@/hooks/use-theme';
import * as styles from './index.module.scss'; import * as styles from './index.module.scss';
function NotFound() { type Props = {
className?: string;
};
function NotFound({ className }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const theme = useTheme(); const theme = useTheme();
const location = useLocation(); const location = useLocation();
return ( return (
<div className={styles.container}> <div className={classNames(styles.container, className)}>
{/* Don't track "not found" for the root path as it will be redirected. */} {/* Don't track "not found" for the root path as it will be redirected. */}
<PageMeta titleKey="errors.page_not_found" trackPageView={location.pathname !== '/'} /> <PageMeta titleKey="errors.page_not_found" trackPageView={location.pathname !== '/'} />
<Card className={styles.content}> <Card className={styles.content}>