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:
parent
4a532a358d
commit
5b1039267f
3 changed files with 70 additions and 54 deletions
|
@ -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;
|
||||||
|
|
|
@ -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,28 +62,26 @@ 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(
|
||||||
metadata: guide.metadata,
|
!!guide && {
|
||||||
Logo: guide.Logo,
|
metadata: guide.metadata,
|
||||||
app,
|
Logo: guide.Logo,
|
||||||
endpoint: tenantEndpoint?.toString() ?? '',
|
app,
|
||||||
alternativeEndpoint: conditional(isCustomDomainActive && tenantEndpoint?.toString()),
|
endpoint: tenantEndpoint?.toString() ?? '',
|
||||||
redirectUris: app.oidcClientMetadata.redirectUris,
|
alternativeEndpoint: conditional(isCustomDomainActive && tenantEndpoint?.toString()),
|
||||||
postLogoutRedirectUris: app.oidcClientMetadata.postLogoutRedirectUris,
|
redirectUris: app.oidcClientMetadata.redirectUris,
|
||||||
isCompact: Boolean(isCompact),
|
postLogoutRedirectUris: app.oidcClientMetadata.postLogoutRedirectUris,
|
||||||
sampleUrls: {
|
isCompact: Boolean(isCompact),
|
||||||
origin: 'http://localhost:3001/',
|
sampleUrls: {
|
||||||
callback: 'http://localhost:3001/callback',
|
origin: 'http://localhost:3001/',
|
||||||
},
|
callback: 'http://localhost:3001/callback',
|
||||||
}) satisfies GuideContextType,
|
},
|
||||||
|
}
|
||||||
|
) satisfies GuideContextType | undefined,
|
||||||
[guide, app, tenantEndpoint, isCustomDomainActive, isCompact]
|
[guide, app, tenantEndpoint, isCustomDomainActive, isCompact]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -90,39 +89,43 @@ 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}>
|
||||||
<GuideContext.Provider value={memorizedContext}>
|
{memorizedContext ? (
|
||||||
<MDXProvider
|
<GuideContext.Provider value={memorizedContext}>
|
||||||
components={{
|
<MDXProvider
|
||||||
code: ({ className, children }) => {
|
components={{
|
||||||
const [, language] = /language-(\w+)/.exec(String(className ?? '')) ?? [];
|
code: ({ className, children }) => {
|
||||||
|
const [, language] = /language-(\w+)/.exec(String(className ?? '')) ?? [];
|
||||||
|
|
||||||
return language ? (
|
return language ? (
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
isReadonly
|
isReadonly
|
||||||
// We need to transform `ts` to `typescript` for prismjs, and
|
// We need to transform `ts` to `typescript` for prismjs, and
|
||||||
// it's weird since it worked in the original Guide component.
|
// it's weird since it worked in the original Guide component.
|
||||||
// To be investigated.
|
// To be investigated.
|
||||||
language={language === 'ts' ? 'typescript' : language}
|
language={language === 'ts' ? 'typescript' : language}
|
||||||
value={String(children).trimEnd()}
|
value={String(children).trimEnd()}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<code>{String(children).trimEnd()}</code>
|
<code>{String(children).trimEnd()}</code>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
a: ({ children, ...props }) => (
|
a: ({ children, ...props }) => (
|
||||||
<TextLink {...props} target="_blank" rel="noopener noreferrer">
|
<TextLink {...props} target="_blank" rel="noopener noreferrer">
|
||||||
{children}
|
{children}
|
||||||
</TextLink>
|
</TextLink>
|
||||||
),
|
),
|
||||||
details: DetailsSummary,
|
details: DetailsSummary,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<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
|
||||||
|
|
|
@ -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}>
|
||||||
|
|
Loading…
Reference in a new issue