Show banner on server errors.

This commit is contained in:
quthla 2019-10-24 21:35:36 +02:00 committed by Jannis Mattheis
parent ed254547db
commit 9715ecaeb1
5 changed files with 33 additions and 19 deletions

View File

@ -11,7 +11,7 @@ const tokenKey = 'gotify-login-key';
export class CurrentUser { export class CurrentUser {
private tokenCache: string | null = null; private tokenCache: string | null = null;
private reconnectTimeoutId: number | null = null; private reconnectTimeoutId: number | null = null;
private readonly reconnectTime: number = 3000; private reconnectTime = 7500;
@observable @observable
public loggedIn = false; public loggedIn = false;
@observable @observable
@ -19,7 +19,7 @@ export class CurrentUser {
@observable @observable
public user: IUser = {name: 'unknown', admin: false, id: -1}; public user: IUser = {name: 'unknown', admin: false, id: -1};
@observable @observable
public hasNetwork = true; public connectionErrorMessage: string | null = null;
public constructor(private readonly snack: SnackReporter) {} public constructor(private readonly snack: SnackReporter) {}
@ -87,16 +87,24 @@ export class CurrentUser {
.then((passThrough) => { .then((passThrough) => {
this.user = passThrough.data; this.user = passThrough.data;
this.loggedIn = true; this.loggedIn = true;
this.hasNetwork = true; this.connectionErrorMessage = null;
this.reconnectTime = 7500;
return passThrough; return passThrough;
}) })
.catch((error: AxiosError) => { .catch((error: AxiosError) => {
if (!error || !error.response) { if (!error || !error.response) {
this.lostNetwork(); this.connectionError('No network connection or server unavailable.');
return Promise.reject(error); return Promise.reject(error);
} }
this.hasNetwork = true; if (error.response.status >= 500) {
this.connectionError(
`${error.response.statusText} (code: ${error.response.status}).`
);
return Promise.reject(error);
}
this.connectionErrorMessage = null;
if (error.response.status >= 400 && error.response.status < 500) { if (error.response.status >= 400 && error.response.status < 500) {
this.logout(); this.logout();
@ -135,8 +143,8 @@ export class CurrentUser {
}); });
}; };
private lostNetwork = () => { private connectionError = (message: string) => {
this.hasNetwork = false; this.connectionErrorMessage = message;
if (this.reconnectTimeoutId !== null) { if (this.reconnectTimeoutId !== null) {
window.clearTimeout(this.reconnectTimeoutId); window.clearTimeout(this.reconnectTimeoutId);
} }
@ -144,5 +152,6 @@ export class CurrentUser {
() => this.tryReconnect(true), () => this.tryReconnect(true),
this.reconnectTime this.reconnectTime
); );
this.reconnectTime = Math.min(this.reconnectTime * 2, 120000);
}; };
} }

View File

@ -2,12 +2,13 @@ import React from 'react';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
interface NetworkLostBannerProps { interface ConnectionErrorBannerProps {
height: number; height: number;
retry: () => void; retry: () => void;
message: string;
} }
export const NetworkLostBanner = ({height, retry}: NetworkLostBannerProps) => { export const ConnectionErrorBanner = ({height, retry, message}: ConnectionErrorBannerProps) => {
return ( return (
<div <div
style={{ style={{
@ -18,7 +19,7 @@ export const NetworkLostBanner = ({height, retry}: NetworkLostBannerProps) => {
position: 'relative', position: 'relative',
}}> }}>
<Typography align="center" variant="h6" style={{lineHeight: `${height}px`}}> <Typography align="center" variant="h6" style={{lineHeight: `${height}px`}}>
No network connection.{' '} {message}{' '}
<Button variant="outlined" onClick={retry}> <Button variant="outlined" onClick={retry}>
Retry Retry
</Button> </Button>

View File

@ -20,7 +20,7 @@ import Users from '../user/Users';
import {observer} from 'mobx-react'; import {observer} from 'mobx-react';
import {observable} from 'mobx'; import {observable} from 'mobx';
import {inject, Stores} from '../inject'; import {inject, Stores} from '../inject';
import {NetworkLostBanner} from '../common/NetworkLostBanner'; import {ConnectionErrorBanner} from '../common/ConnectionErrorBanner';
import {IVersion} from '../types'; import {IVersion} from '../types';
const styles = (theme: Theme) => ({ const styles = (theme: Theme) => ({
@ -88,8 +88,8 @@ class Layout extends React.Component<
authenticating, authenticating,
user: {name, admin}, user: {name, admin},
logout, logout,
hasNetwork,
tryReconnect, tryReconnect,
connectionErrorMessage,
}, },
} = this.props; } = this.props;
const theme = themeMap[currentTheme]; const theme = themeMap[currentTheme];
@ -98,13 +98,17 @@ class Layout extends React.Component<
<MuiThemeProvider theme={theme}> <MuiThemeProvider theme={theme}>
<HashRouter> <HashRouter>
<div> <div>
{hasNetwork ? null : ( {!connectionErrorMessage ? null : (
<NetworkLostBanner height={64} retry={() => tryReconnect()} /> <ConnectionErrorBanner
height={64}
retry={() => tryReconnect()}
message={connectionErrorMessage}
/>
)} )}
<div style={{display: 'flex'}}> <div style={{display: 'flex'}}>
<CssBaseline /> <CssBaseline />
<Header <Header
style={{top: hasNetwork ? 0 : 64}} style={{top: !connectionErrorMessage ? 0 : 64}}
admin={admin} admin={admin}
name={name} name={name}
version={version} version={version}

View File

@ -30,9 +30,9 @@ export const registerReactions = (stores: StoreMapping) => {
); );
reaction( reaction(
() => stores.currentUser.hasNetwork, () => stores.currentUser.connectionErrorMessage,
(hasNetwork) => { (connectionErrorMessage) => {
if (hasNetwork) { if (!connectionErrorMessage) {
clearAll(); clearAll();
loadAll(); loadAll();
} }

View File

@ -44,7 +44,7 @@ class Login extends Component<Stores<'currentUser'>> {
size="large" size="large"
className="login" className="login"
color="primary" color="primary"
disabled={!this.props.currentUser.hasNetwork} disabled={!!this.props.currentUser.connectionErrorMessage}
style={{marginTop: 15, marginBottom: 5}} style={{marginTop: 15, marginBottom: 5}}
onClick={this.login}> onClick={this.login}>
Login Login