Show a nicer error message when server is installing

This commit is contained in:
Dane Everitt 2020-04-17 11:07:32 -07:00
parent 1aa3e0fb63
commit e044e8db1c
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
12 changed files with 117 additions and 34 deletions

3
public/.gitignore vendored
View file

@ -1,2 +1,3 @@
assets/* assets/*
!assets/*.svg !assets/svgs
!assets/svgs/*.svg

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -1,44 +1,21 @@
import React from 'react'; import React from 'react';
import { Route } from 'react-router'; import { Route } from 'react-router';
import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { CSSTransition, TransitionGroup } from 'react-transition-group';
import styled from 'styled-components'; import PageContentBlock from '@/components/elements/PageContentBlock';
import { breakpoint } from 'styled-components-breakpoint';
type Props = Readonly<{ type Props = Readonly<{
children: React.ReactNode; children: React.ReactNode;
}>; }>;
const ContentContainer = styled.div`
max-width: 1200px;
${tw`mx-4`};
${breakpoint('xl')`
${tw`mx-auto`};
`};
`;
export default ({ children }: Props) => ( export default ({ children }: Props) => (
<Route <Route
render={({ location }) => ( render={({ location }) => (
<TransitionGroup className={'route-transition-group'}> <TransitionGroup className={'route-transition-group'}>
<CSSTransition key={location.key} timeout={250} in={true} appear={true} classNames={'fade'}> <CSSTransition key={location.key} timeout={250} in={true} appear={true} classNames={'fade'}>
<section> <section>
<ContentContainer> <PageContentBlock>
{children} {children}
</ContentContainer> </PageContentBlock>
<ContentContainer className={'mb-4'}>
<p className={'text-right text-neutral-500 text-xs'}>
&copy; 2015 - 2020&nbsp;
<a
rel={'noopener nofollow'}
href={'https://pterodactyl.io'}
target={'_blank'}
className={'no-underline text-neutral-500 hover:text-neutral-300'}
>
Pterodactyl Software
</a>
</p>
</ContentContainer>
</section> </section>
</CSSTransition> </CSSTransition>
</TransitionGroup> </TransitionGroup>

View file

@ -25,8 +25,10 @@ http.interceptors.response.use(resp => {
} }
return resp; return resp;
}, () => { }, error => {
store.getActions().progress.setComplete(); store.getActions().progress.setComplete();
throw error;
}); });
// If we have a phpdebugbar instance registered at this point in time go // If we have a phpdebugbar instance registered at this point in time go

View file

@ -36,7 +36,7 @@ export default forwardRef<HTMLFormElement, Props>(({ title, ...props }, ref) =>
<Form {...props} ref={ref}> <Form {...props} ref={ref}>
<div className={'md:flex w-full bg-white shadow-lg rounded-lg p-6 md:pl-0 mx-1'}> <div className={'md:flex w-full bg-white shadow-lg rounded-lg p-6 md:pl-0 mx-1'}>
<div className={'flex-none select-none mb-6 md:mb-0 self-center'}> <div className={'flex-none select-none mb-6 md:mb-0 self-center'}>
<img src={'/assets/pterodactyl.svg'} className={'block w-48 md:w-64 mx-auto'}/> <img src={'/assets/svgs/pterodactyl.svg'} className={'block w-48 md:w-64 mx-auto'}/>
</div> </div>
<div className={'flex-1'}> <div className={'flex-1'}>
{props.children} {props.children}

View file

@ -0,0 +1,13 @@
import styled from 'styled-components';
import { breakpoint } from 'styled-components-breakpoint';
const ContentContainer = styled.div`
max-width: 1200px;
${tw`mx-4`};
${breakpoint('xl')`
${tw`mx-auto`};
`};
`;
export default ContentContainer;

View file

@ -0,0 +1,30 @@
import React from 'react';
import ContentContainer from '@/components/elements/ContentContainer';
import { CSSTransition } from 'react-transition-group';
interface Props {
children: React.ReactNode;
}
export default ({ children }: Props) => (
<CSSTransition timeout={250} classNames={'fade'} appear={true} in={true}>
<>
<ContentContainer className={'my-10'}>
{children}
</ContentContainer>
<ContentContainer className={'mb-4'}>
<p className={'text-right text-neutral-500 text-xs'}>
&copy; 2015 - 2020&nbsp;
<a
rel={'noopener nofollow'}
href={'https://pterodactyl.io'}
target={'_blank'}
className={'no-underline text-neutral-500 hover:text-neutral-300'}
>
Pterodactyl Software
</a>
</p>
</ContentContainer>
</>
</CSSTransition>
);

View file

@ -0,0 +1,21 @@
import React from 'react';
import PageContentBlock from '@/components/elements/PageContentBlock';
interface Props {
title?: string;
message: string;
}
export default ({ title, message }: Props) => (
<PageContentBlock>
<div className={'flex justify-center'}>
<div className={'w-full sm:w-3/4 md:w-1/2 p-12 md:p-20 bg-neutral-100 rounded-lg shadow-lg text-center'}>
<img src={'/assets/svgs/server_error.svg'} className={'w-2/3 h-auto select-none'}/>
<h2 className={'mt-6 text-neutral-900 font-bold'}>{ title || 'Something went wrong!' }</h2>
<p className={'text-sm text-neutral-700 mt-2'}>
{message}
</p>
</div>
</div>
</PageContentBlock>
);

View file

@ -0,0 +1,16 @@
import React from 'react';
import PageContentBlock from '@/components/elements/PageContentBlock';
export default () => (
<PageContentBlock>
<div className={'flex justify-center'}>
<div className={'w-full sm:w-3/4 md:w-1/2 p-12 md:p-20 bg-neutral-100 rounded-lg shadow-lg text-center'}>
<img src={'/assets/svgs/server_installing.svg'} className={'w-2/3 h-auto select-none'}/>
<h2 className={'mt-6 text-neutral-900 font-bold'}>Your server is installing.</h2>
<p className={'text-sm text-neutral-700 mt-2'}>
Please check back in a few minutes.
</p>
</div>
</div>
</PageContentBlock>
);

View file

@ -1,4 +1,4 @@
import React, { useEffect } from 'react'; import React, { useEffect, useState } from 'react';
import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom'; import { NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom';
import NavigationBar from '@/components/NavigationBar'; import NavigationBar from '@/components/NavigationBar';
import ServerConsole from '@/components/server/ServerConsole'; import ServerConsole from '@/components/server/ServerConsole';
@ -17,8 +17,13 @@ import UsersContainer from '@/components/server/users/UsersContainer';
import Can from '@/components/elements/Can'; import Can from '@/components/elements/Can';
import BackupContainer from '@/components/server/backups/BackupContainer'; import BackupContainer from '@/components/server/backups/BackupContainer';
import Spinner from '@/components/elements/Spinner'; import Spinner from '@/components/elements/Spinner';
import ServerInstalling from '@/components/screens/ServerInstalling';
import ServerError from '@/components/screens/ServerError';
import { httpErrorToHuman } from '@/api/http';
const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => { const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => {
const [ error, setError ] = useState('');
const [ installing, setInstalling ] = useState(false);
const server = ServerContext.useStoreState(state => state.server.data); const server = ServerContext.useStoreState(state => state.server.data);
const getServer = ServerContext.useStoreActions(actions => actions.server.getServer); const getServer = ServerContext.useStoreActions(actions => actions.server.getServer);
const clearServerState = ServerContext.useStoreActions(actions => actions.clearServerState); const clearServerState = ServerContext.useStoreActions(actions => actions.clearServerState);
@ -28,7 +33,17 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
}, []); }, []);
useEffect(() => { useEffect(() => {
getServer(match.params.id); setError('');
setInstalling(false);
getServer(match.params.id)
.catch(error => {
if (error.response?.status === 409) {
setInstalling(true);
} else {
console.error(error);
setError(httpErrorToHuman(error));
}
});
return () => { return () => {
clearServerState(); clearServerState();
@ -39,10 +54,16 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
<React.Fragment key={'server-router'}> <React.Fragment key={'server-router'}>
<NavigationBar/> <NavigationBar/>
{!server ? {!server ?
!installing ?
error ?
<ServerError message={error}/>
:
<div className={'flex justify-center m-20'}> <div className={'flex justify-center m-20'}>
<Spinner size={'large'}/> <Spinner size={'large'}/>
</div> </div>
: :
<ServerInstalling/>
:
<> <>
<CSSTransition timeout={250} classNames={'fade'} appear={true} in={true}> <CSSTransition timeout={250} classNames={'fade'} appear={true} in={true}>
<div id={'sub-navigation'}> <div id={'sub-navigation'}>