Show a nicer error message when server is installing
This commit is contained in:
parent
1aa3e0fb63
commit
e044e8db1c
12 changed files with 117 additions and 34 deletions
3
public/.gitignore
vendored
3
public/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
assets/*
|
||||
!assets/*.svg
|
||||
!assets/svgs
|
||||
!assets/svgs/*.svg
|
||||
|
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
1
public/assets/svgs/server_error.svg
Normal file
1
public/assets/svgs/server_error.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.4 KiB |
1
public/assets/svgs/server_installing.svg
Normal file
1
public/assets/svgs/server_installing.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 23 KiB |
|
@ -1,44 +1,21 @@
|
|||
import React from 'react';
|
||||
import { Route } from 'react-router';
|
||||
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
||||
import styled from 'styled-components';
|
||||
import { breakpoint } from 'styled-components-breakpoint';
|
||||
import PageContentBlock from '@/components/elements/PageContentBlock';
|
||||
|
||||
type Props = Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>;
|
||||
|
||||
const ContentContainer = styled.div`
|
||||
max-width: 1200px;
|
||||
${tw`mx-4`};
|
||||
|
||||
${breakpoint('xl')`
|
||||
${tw`mx-auto`};
|
||||
`};
|
||||
`;
|
||||
|
||||
export default ({ children }: Props) => (
|
||||
<Route
|
||||
render={({ location }) => (
|
||||
<TransitionGroup className={'route-transition-group'}>
|
||||
<CSSTransition key={location.key} timeout={250} in={true} appear={true} classNames={'fade'}>
|
||||
<section>
|
||||
<ContentContainer>
|
||||
<PageContentBlock>
|
||||
{children}
|
||||
</ContentContainer>
|
||||
<ContentContainer className={'mb-4'}>
|
||||
<p className={'text-right text-neutral-500 text-xs'}>
|
||||
© 2015 - 2020
|
||||
<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>
|
||||
</PageContentBlock>
|
||||
</section>
|
||||
</CSSTransition>
|
||||
</TransitionGroup>
|
||||
|
|
|
@ -25,8 +25,10 @@ http.interceptors.response.use(resp => {
|
|||
}
|
||||
|
||||
return resp;
|
||||
}, () => {
|
||||
}, error => {
|
||||
store.getActions().progress.setComplete();
|
||||
|
||||
throw error;
|
||||
});
|
||||
|
||||
// If we have a phpdebugbar instance registered at this point in time go
|
||||
|
|
|
@ -36,7 +36,7 @@ export default forwardRef<HTMLFormElement, Props>(({ title, ...props }, 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={'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 className={'flex-1'}>
|
||||
{props.children}
|
||||
|
|
13
resources/scripts/components/elements/ContentContainer.tsx
Normal file
13
resources/scripts/components/elements/ContentContainer.tsx
Normal 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;
|
30
resources/scripts/components/elements/PageContentBlock.tsx
Normal file
30
resources/scripts/components/elements/PageContentBlock.tsx
Normal 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'}>
|
||||
© 2015 - 2020
|
||||
<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>
|
||||
);
|
21
resources/scripts/components/screens/ServerError.tsx
Normal file
21
resources/scripts/components/screens/ServerError.tsx
Normal 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>
|
||||
);
|
16
resources/scripts/components/screens/ServerInstalling.tsx
Normal file
16
resources/scripts/components/screens/ServerInstalling.tsx
Normal 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>
|
||||
);
|
|
@ -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 NavigationBar from '@/components/NavigationBar';
|
||||
import ServerConsole from '@/components/server/ServerConsole';
|
||||
|
@ -17,8 +17,13 @@ import UsersContainer from '@/components/server/users/UsersContainer';
|
|||
import Can from '@/components/elements/Can';
|
||||
import BackupContainer from '@/components/server/backups/BackupContainer';
|
||||
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 [ error, setError ] = useState('');
|
||||
const [ installing, setInstalling ] = useState(false);
|
||||
const server = ServerContext.useStoreState(state => state.server.data);
|
||||
const getServer = ServerContext.useStoreActions(actions => actions.server.getServer);
|
||||
const clearServerState = ServerContext.useStoreActions(actions => actions.clearServerState);
|
||||
|
@ -28,7 +33,17 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
|
|||
}, []);
|
||||
|
||||
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 () => {
|
||||
clearServerState();
|
||||
|
@ -39,9 +54,15 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
|
|||
<React.Fragment key={'server-router'}>
|
||||
<NavigationBar/>
|
||||
{!server ?
|
||||
<div className={'flex justify-center m-20'}>
|
||||
<Spinner size={'large'}/>
|
||||
</div>
|
||||
!installing ?
|
||||
error ?
|
||||
<ServerError message={error}/>
|
||||
:
|
||||
<div className={'flex justify-center m-20'}>
|
||||
<Spinner size={'large'}/>
|
||||
</div>
|
||||
:
|
||||
<ServerInstalling/>
|
||||
:
|
||||
<>
|
||||
<CSSTransition timeout={250} classNames={'fade'} appear={true} in={true}>
|
||||
|
|
Loading…
Reference in a new issue