Get server listing design working mostly correct
This commit is contained in:
parent
94e3acb9c4
commit
d93e804a31
9 changed files with 170 additions and 188 deletions
|
@ -10,6 +10,7 @@ import FlashMessageRender from '@/components/FlashMessageRender';
|
|||
import { useStoreState } from 'easy-peasy';
|
||||
import { usePersistedState } from '@/plugins/usePersistedState';
|
||||
import Switch from '@/components/elements/Switch';
|
||||
import tw from 'twin.macro';
|
||||
|
||||
export default () => {
|
||||
const { addError, clearFlashes } = useFlash();
|
||||
|
@ -37,10 +38,10 @@ export default () => {
|
|||
|
||||
return (
|
||||
<PageContentBlock>
|
||||
<FlashMessageRender className={'mb-4'}/>
|
||||
<FlashMessageRender css={tw`mb-4`}/>
|
||||
{rootAdmin &&
|
||||
<div className={'mb-2 flex justify-end items-center'}>
|
||||
<p className={'uppercase text-xs text-neutral-400 mr-2'}>
|
||||
<div css={tw`mb-2 flex justify-end items-center`}>
|
||||
<p css={tw`uppercase text-xs text-neutral-400 mr-2`}>
|
||||
{showAdmin ? 'Showing all servers' : 'Showing your servers'}
|
||||
</p>
|
||||
<Switch
|
||||
|
@ -51,14 +52,16 @@ export default () => {
|
|||
</div>
|
||||
}
|
||||
{loading ?
|
||||
<Spinner centered={true} size={'large'}/>
|
||||
<Spinner centered size={'large'}/>
|
||||
:
|
||||
servers.length > 0 ?
|
||||
servers.map(server => (
|
||||
<ServerRow key={server.uuid} server={server} className={'mt-2'}/>
|
||||
servers.map((server, index) => (
|
||||
<div key={server.uuid} css={index > 0 ? tw`mt-2` : undefined}>
|
||||
<ServerRow server={server}/>
|
||||
</div>
|
||||
))
|
||||
:
|
||||
<p className={'text-center text-sm text-neutral-400'}>
|
||||
<p css={tw`text-center text-sm text-neutral-400`}>
|
||||
There are no servers associated with your account.
|
||||
</p>
|
||||
}
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ContentBox from '@/components/elements/ContentBox';
|
||||
|
||||
export default class DesignElementsContainer extends React.PureComponent {
|
||||
render () {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={'my-10'}>
|
||||
<div className={'flex'}>
|
||||
<ContentBox
|
||||
className={'flex-1 mr-4'}
|
||||
title={'A Special Announcement'}
|
||||
borderColor={'border-primary-400'}
|
||||
>
|
||||
<p className={'text-neutral-200 text-sm'}>
|
||||
Your demands have been received: Dark Mode will be default in Pterodactyl 0.8!
|
||||
</p>
|
||||
<p><Link to={'/'}>Back</Link></p>
|
||||
</ContentBox>
|
||||
<div className={'ml-4 flex-1'}>
|
||||
<h2 className={'text-neutral-300 mb-2 px-4'}>Form Elements</h2>
|
||||
<div className={'bg-neutral-700 p-4 rounded shadow-lg border-t-4 border-primary-400'}>
|
||||
<label className={'uppercase text-neutral-200'}>Email</label>
|
||||
<input type={'text'} className={'input-dark'}/>
|
||||
<p className={'input-help'}>
|
||||
This is some descriptive helper text to explain how things work.
|
||||
</p>
|
||||
<div className={'mt-6'}/>
|
||||
<label className={'uppercase text-neutral-200'}>Username</label>
|
||||
<input type={'text'} className={'input-dark error'}/>
|
||||
<p className={'input-help'}>
|
||||
This field has an error.
|
||||
</p>
|
||||
<div className={'mt-6'}/>
|
||||
<label className={'uppercase text-neutral-200'}>Disabled Field</label>
|
||||
<input type={'text'} className={'input-dark'} disabled={true}/>
|
||||
<div className={'mt-6'}/>
|
||||
<label className={'uppercase text-neutral-200'}>Select</label>
|
||||
<select className={'input-dark'}>
|
||||
<option>Option 1</option>
|
||||
<option>Option 2</option>
|
||||
<option>Option 3</option>
|
||||
</select>
|
||||
<div className={'mt-6'}/>
|
||||
<label className={'uppercase text-neutral-200'}>Textarea</label>
|
||||
<textarea className={'input-dark h-32'}></textarea>
|
||||
<div className={'mt-6'}/>
|
||||
<button className={'btn btn-primary btn-sm'}>
|
||||
Blue
|
||||
</button>
|
||||
<button className={'btn btn-grey btn-sm ml-2'}>
|
||||
Grey
|
||||
</button>
|
||||
<button className={'btn btn-green btn-sm ml-2'}>
|
||||
Green
|
||||
</button>
|
||||
<button className={'btn btn-red btn-sm ml-2'}>
|
||||
Red
|
||||
</button>
|
||||
<div className={'mt-6'}/>
|
||||
<button className={'btn btn-secondary btn-sm'}>
|
||||
Secondary
|
||||
</button>
|
||||
<button className={'btn btn-secondary btn-red btn-sm ml-2'}>
|
||||
Secondary Danger
|
||||
</button>
|
||||
<div className={'mt-6'}/>
|
||||
<button className={'btn btn-primary btn-lg'}>
|
||||
Large
|
||||
</button>
|
||||
<button className={'btn btn-primary btn-xs ml-2'}>
|
||||
Tiny
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@ import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
|||
import getServerResourceUsage, { ServerStats } from '@/api/server/getServerResourceUsage';
|
||||
import { bytesToHuman } from '@/helpers';
|
||||
import classNames from 'classnames';
|
||||
import tw from 'twin.macro';
|
||||
import GreyRowBox from '@/components/elements/GreyRowBox';
|
||||
|
||||
// Determines if the current value is in an alarm threshold so we can show it in red rather
|
||||
// than the more faded default style.
|
||||
|
@ -20,7 +22,7 @@ const isAlarmState = (current: number, limit: number): boolean => {
|
|||
return current / limitInBytes >= 0.90;
|
||||
};
|
||||
|
||||
export default ({ server, className }: { server: Server; className: string | undefined }) => {
|
||||
export default ({ server }: { server: Server }) => {
|
||||
const interval = useRef<number>(null);
|
||||
const [ stats, setStats ] = useState<ServerStats | null>(null);
|
||||
const [ statsError, setStatsError ] = useState(false);
|
||||
|
@ -37,7 +39,6 @@ export default ({ server, className }: { server: Server; className: string | und
|
|||
|
||||
useEffect(() => {
|
||||
getStats().then(() => {
|
||||
// @ts-ignore
|
||||
interval.current = setInterval(() => getStats(), 20000);
|
||||
});
|
||||
|
||||
|
@ -52,21 +53,21 @@ export default ({ server, className }: { server: Server; className: string | und
|
|||
alarms.memory = isAlarmState(stats.memoryUsageInBytes, server.limits.memory);
|
||||
alarms.disk = server.limits.disk === 0 ? false : isAlarmState(stats.diskUsageInBytes, server.limits.disk);
|
||||
}
|
||||
const disklimit = server.limits.disk != 0 ? bytesToHuman(server.limits.disk * 1000 * 1000) : "Unlimited";
|
||||
const memorylimit = server.limits.memory != 0 ? bytesToHuman(server.limits.memory * 1000 * 1000) : "Unlimited";
|
||||
const disklimit = server.limits.disk !== 0 ? bytesToHuman(server.limits.disk * 1000 * 1000) : 'Unlimited';
|
||||
const memorylimit = server.limits.memory !== 0 ? bytesToHuman(server.limits.memory * 1000 * 1000) : 'Unlimited';
|
||||
|
||||
return (
|
||||
<Link to={`/server/${server.id}`} className={`grey-row-box cursor-pointer ${className}`}>
|
||||
<GreyRowBox as={Link} to={`/server/${server.id}`}>
|
||||
<div className={'icon'}>
|
||||
<FontAwesomeIcon icon={faServer}/>
|
||||
</div>
|
||||
<div className={'flex-1 ml-4'}>
|
||||
<p className={'text-lg'}>{server.name}</p>
|
||||
<div css={tw`flex-1 ml-4`}>
|
||||
<p css={tw`text-lg`}>{server.name}</p>
|
||||
</div>
|
||||
<div className={'w-1/4 overflow-hidden'}>
|
||||
<div className={'flex ml-4'}>
|
||||
<FontAwesomeIcon icon={faEthernet} className={'text-neutral-500'}/>
|
||||
<p className={'text-sm text-neutral-400 ml-2'}>
|
||||
<div css={tw`w-1/4 overflow-hidden`}>
|
||||
<div css={tw`flex ml-4`}>
|
||||
<FontAwesomeIcon icon={faEthernet} css={tw`text-neutral-500`}/>
|
||||
<p css={tw`text-sm text-neutral-400 ml-2`}>
|
||||
{
|
||||
server.allocations.filter(alloc => alloc.default).map(allocation => (
|
||||
<span key={allocation.ip + allocation.port.toString()}>{allocation.alias || allocation.ip}:{allocation.port}</span>
|
||||
|
@ -75,85 +76,88 @@ export default ({ server, className }: { server: Server; className: string | und
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'w-1/3 flex items-baseline relative'}>
|
||||
<div css={tw`w-1/3 flex items-baseline relative`}>
|
||||
{!stats ?
|
||||
!statsError ?
|
||||
<SpinnerOverlay size={'tiny'} visible={true} backgroundOpacity={0.25}/>
|
||||
:
|
||||
server.isInstalling ?
|
||||
<div className={'flex-1 text-center'}>
|
||||
<span className={'bg-neutral-500 rounded px-2 py-1 text-neutral-100 text-xs'}>
|
||||
<div css={tw`flex-1 text-center`}>
|
||||
<span css={tw`bg-neutral-500 rounded px-2 py-1 text-neutral-100 text-xs`}>
|
||||
Installing
|
||||
</span>
|
||||
</div>
|
||||
:
|
||||
<div className={'flex-1 text-center'}>
|
||||
<span className={'bg-red-500 rounded px-2 py-1 text-red-100 text-xs'}>
|
||||
<div css={tw`flex-1 text-center`}>
|
||||
<span css={tw`bg-red-500 rounded px-2 py-1 text-red-100 text-xs`}>
|
||||
{server.isSuspended ? 'Suspended' : 'Connection Error'}
|
||||
</span>
|
||||
</div>
|
||||
:
|
||||
<React.Fragment>
|
||||
<div className={'flex-1 flex ml-4 justify-center'}>
|
||||
<div css={tw`flex-1 flex ml-4 justify-center`}>
|
||||
<FontAwesomeIcon
|
||||
icon={faMicrochip}
|
||||
className={classNames({
|
||||
'text-neutral-500': !alarms.cpu,
|
||||
'text-red-400': alarms.cpu,
|
||||
})}
|
||||
css={[
|
||||
!alarms.cpu && tw`text-neutral-500`,
|
||||
alarms.cpu && tw`text-red-400`,
|
||||
]}
|
||||
/>
|
||||
<p
|
||||
className={classNames('text-sm ml-2', {
|
||||
'text-neutral-400': !alarms.cpu,
|
||||
'text-white': alarms.cpu,
|
||||
})}
|
||||
css={[
|
||||
tw`text-sm ml-2`,
|
||||
!alarms.cpu && tw`text-neutral-400`,
|
||||
alarms.cpu && tw`text-white`,
|
||||
]}
|
||||
>
|
||||
{stats.cpuUsagePercent} %
|
||||
</p>
|
||||
</div>
|
||||
<div className={'flex-1 ml-4'}>
|
||||
<div className={'flex justify-center'}>
|
||||
<div css={tw`flex-1 ml-4`}>
|
||||
<div css={tw`flex justify-center`}>
|
||||
<FontAwesomeIcon
|
||||
icon={faMemory}
|
||||
className={classNames({
|
||||
'text-neutral-500': !alarms.memory,
|
||||
'text-red-400': alarms.memory,
|
||||
})}
|
||||
css={[
|
||||
!alarms.memory && tw`text-neutral-500`,
|
||||
alarms.memory && tw`text-red-400`,
|
||||
]}
|
||||
/>
|
||||
<p
|
||||
className={classNames('text-sm ml-2', {
|
||||
'text-neutral-400': !alarms.memory,
|
||||
'text-white': alarms.memory,
|
||||
})}
|
||||
css={[
|
||||
tw`text-sm ml-2`,
|
||||
!alarms.memory && tw`text-neutral-400`,
|
||||
alarms.memory && tw`text-white`,
|
||||
]}
|
||||
>
|
||||
{bytesToHuman(stats.memoryUsageInBytes)}
|
||||
</p>
|
||||
</div>
|
||||
<p className={'text-xs text-neutral-600 text-center mt-1'}>of {memorylimit}</p>
|
||||
<p css={tw`text-xs text-neutral-600 text-center mt-1`}>of {memorylimit}</p>
|
||||
</div>
|
||||
<div className={'flex-1 ml-4'}>
|
||||
<div className={'flex justify-center'}>
|
||||
<div css={tw`flex-1 ml-4`}>
|
||||
<div css={tw`flex justify-center`}>
|
||||
<FontAwesomeIcon
|
||||
icon={faHdd}
|
||||
className={classNames({
|
||||
'text-neutral-500': !alarms.disk,
|
||||
'text-red-400': alarms.disk,
|
||||
})}
|
||||
css={[
|
||||
!alarms.disk && tw`text-neutral-500`,
|
||||
alarms.disk && tw`text-red-400`,
|
||||
]}
|
||||
/>
|
||||
<p
|
||||
className={classNames('text-sm ml-2', {
|
||||
'text-neutral-400': !alarms.disk,
|
||||
'text-white': alarms.disk,
|
||||
})}
|
||||
css={[
|
||||
tw`text-sm ml-2`,
|
||||
!alarms.disk && tw`text-neutral-400`,
|
||||
alarms.disk && tw`text-white`,
|
||||
]}
|
||||
>
|
||||
{bytesToHuman(stats.diskUsageInBytes)}
|
||||
</p>
|
||||
</div>
|
||||
<p className={'text-xs text-neutral-600 text-center mt-1'}>of {disklimit}</p>
|
||||
<p css={tw`text-xs text-neutral-600 text-center mt-1`}>of {disklimit}</p>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
}
|
||||
</div>
|
||||
</Link>
|
||||
</GreyRowBox>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue