0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

fix(console): catch user interaction errors (#3591)

This commit is contained in:
Xiao Yijun 2023-03-27 12:19:11 +08:00 committed by GitHub
parent 93bc915609
commit 875d94a02a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 36 additions and 28 deletions

View file

@ -1,11 +1,14 @@
import { useLogto } from '@logto/react';
import type { TenantInfo } from '@logto/schemas';
import { conditional, yes } from '@silverhand/essentials';
import { useContext, useEffect } from 'react';
import { HTTPError } from 'ky';
import { useContext, useEffect, useState } from 'react';
import { useHref, useSearchParams } from 'react-router-dom';
import { useCloudApi } from '@/cloud/hooks/use-cloud-api';
import AppError from '@/components/AppError';
import AppLoading from '@/components/AppLoading';
import SessionExpired from '@/components/SessionExpired';
import { searchKeys } from '@/consts';
import { TenantsContext } from '@/contexts/TenantsProvider';
@ -15,11 +18,18 @@ import Tenants from './Tenants';
function Protected() {
const api = useCloudApi();
const { tenants, setTenants, currentTenantId } = useContext(TenantsContext);
const [error, setError] = useState<Error>();
useEffect(() => {
const loadTenants = async () => {
const data = await api.get('/api/tenants').json<TenantInfo[]>();
setTenants(data);
setError(undefined);
try {
const data = await api.get('/api/tenants').json<TenantInfo[]>();
setTenants(data);
} catch (error: unknown) {
setError(error instanceof Error ? error : new Error(String(error)));
}
};
if (!tenants) {
@ -27,6 +37,14 @@ function Protected() {
}
}, [api, setTenants, tenants]);
if (error) {
if (error instanceof HTTPError && error.response.status === 401) {
return <SessionExpired error={error} />;
}
return <AppError errorMessage={error.message} callStack={error.stack} />;
}
if (tenants) {
if (currentTenantId) {
return <Redirect tenants={tenants} toTenantId={currentTenantId} />;

View file

@ -12,7 +12,7 @@ type Props = {
};
function SessionExpired({ callbackHref = '/callback', error }: Props) {
const { signIn, signOut } = useLogto();
const { signIn } = useLogto();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
return (

View file

@ -45,8 +45,8 @@ class ErrorBoundary extends Component<Props, State> {
const { error } = this.state;
if (error) {
if (error instanceof HTTPError && error.response.status === 401) {
return <SessionExpired error={error} />;
if (error instanceof HTTPError) {
return error.response.status === 401 ? <SessionExpired error={error} /> : children;
}
const callStack = conditional(

View file

@ -63,12 +63,8 @@ function SenderTester({ connectorFactoryId, connectorType, className, parse }: P
: { email: sendTo }),
};
try {
await api.post(`api/connectors/${connectorFactoryId}/test`, { json: data }).json();
setShowTooltip(true);
} catch (error: unknown) {
console.error(error);
}
await api.post(`api/connectors/${connectorFactoryId}/test`, { json: data }).json();
setShowTooltip(true);
});
return (

View file

@ -1,15 +1,18 @@
import type { ConnectorResponse } from '@logto/schemas';
import { useEffect, useState } from 'react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import useSWRImmutable from 'swr/immutable';
import Button from '@/components/Button';
import CardTitle from '@/components/CardTitle';
import FormCard from '@/components/FormCard';
import { adminTenantEndpoint, meApi } from '@/consts';
import { isCloud } from '@/consts/cloud';
import type { RequestError } from '@/hooks/use-api';
import { useStaticApi } from '@/hooks/use-api';
import useCurrentUser from '@/hooks/use-current-user';
import useSwrFetcher from '@/hooks/use-swr-fetcher';
import useUserAssetsService from '@/hooks/use-user-assets-service';
import * as resourcesStyles from '@/scss/resources.module.scss';
import { withAppInsights } from '@/utils/app-insights';
@ -26,27 +29,18 @@ function Profile() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const navigate = useNavigate();
const api = useStaticApi({ prefixUrl: adminTenantEndpoint, resourceIndicator: meApi.indicator });
const fetcher = useSwrFetcher<ConnectorResponse[]>(api);
const { data: connectors, error: fetchConnectorsError } = useSWRImmutable<
ConnectorResponse[],
RequestError
>('me/social/connectors', fetcher);
const isLoadingConnectors = !connectors && !fetchConnectorsError;
const { user, reload, isLoading: isLoadingUser } = useCurrentUser();
const { isLoading: isUserAssetServiceLoading } = useUserAssetsService();
const [connectors, setConnectors] = useState<ConnectorResponse[]>();
const [isLoadingConnectors, setIsLoadingConnectors] = useState(false);
const [showDeleteAccountModal, setShowDeleteAccountModal] = useState(false);
const showLoadingSkeleton = isLoadingUser || isLoadingConnectors || isUserAssetServiceLoading;
useEffect(() => {
void reload();
(async () => {
setIsLoadingConnectors(true);
const connectorResponse = await api.get('me/social/connectors').json<ConnectorResponse[]>();
setConnectors(connectorResponse);
setIsLoadingConnectors(false);
})();
}, [api, reload]);
return (
<div className={resourcesStyles.container}>
<div className={resourcesStyles.headline}>