Make interface mobile responsive (#2273)
This commit is contained in:
parent
9a21584c42
commit
9a4c0d8ba7
20 changed files with 130 additions and 69 deletions
|
@ -11,7 +11,7 @@ import styled from 'styled-components/macro';
|
||||||
import * as config from '@/../../tailwind.config.js';
|
import * as config from '@/../../tailwind.config.js';
|
||||||
|
|
||||||
const Navigation = styled.div`
|
const Navigation = styled.div`
|
||||||
${tw`w-full bg-neutral-900 shadow-md`};
|
${tw`w-full bg-neutral-900 shadow-md overflow-x-auto`};
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
${tw`mx-auto w-full flex items-center`};
|
${tw`mx-auto w-full flex items-center`};
|
||||||
|
|
|
@ -14,8 +14,26 @@ import { httpErrorToHuman } from '@/api/http';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import PageContentBlock from '@/components/elements/PageContentBlock';
|
import PageContentBlock from '@/components/elements/PageContentBlock';
|
||||||
import tw from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
|
import { breakpoint } from '@/theme';
|
||||||
|
import styled from 'styled-components/macro';
|
||||||
import GreyRowBox from '@/components/elements/GreyRowBox';
|
import GreyRowBox from '@/components/elements/GreyRowBox';
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
${tw`flex flex-wrap my-10`};
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
${tw`w-full`};
|
||||||
|
|
||||||
|
${breakpoint('md')`
|
||||||
|
width: calc(50% - 1rem);
|
||||||
|
`}
|
||||||
|
|
||||||
|
${breakpoint('xl')`
|
||||||
|
${tw`w-auto flex-1`};
|
||||||
|
`}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const [ deleteIdentifier, setDeleteIdentifier ] = useState('');
|
const [ deleteIdentifier, setDeleteIdentifier ] = useState('');
|
||||||
const [ keys, setKeys ] = useState<ApiKey[]>([]);
|
const [ keys, setKeys ] = useState<ApiKey[]>([]);
|
||||||
|
@ -50,11 +68,11 @@ export default () => {
|
||||||
return (
|
return (
|
||||||
<PageContentBlock title={'Account API'}>
|
<PageContentBlock title={'Account API'}>
|
||||||
<FlashMessageRender byKey={'account'} css={tw`mb-4`}/>
|
<FlashMessageRender byKey={'account'} css={tw`mb-4`}/>
|
||||||
<div css={tw`flex`}>
|
<Container>
|
||||||
<ContentBox title={'Create API Key'} css={tw`flex-1`}>
|
<ContentBox title={'Create API Key'}>
|
||||||
<CreateApiKeyForm onKeyCreated={key => setKeys(s => ([ ...s!, key ]))}/>
|
<CreateApiKeyForm onKeyCreated={key => setKeys(s => ([ ...s!, key ]))}/>
|
||||||
</ContentBox>
|
</ContentBox>
|
||||||
<ContentBox title={'API Keys'} css={tw`ml-10 flex-1`}>
|
<ContentBox title={'API Keys'} css={tw`mt-8 md:mt-0 md:ml-8`}>
|
||||||
<SpinnerOverlay visible={loading}/>
|
<SpinnerOverlay visible={loading}/>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
visible={!!deleteIdentifier}
|
visible={!!deleteIdentifier}
|
||||||
|
@ -106,7 +124,7 @@ export default () => {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ContentBox>
|
</ContentBox>
|
||||||
</div>
|
</Container>
|
||||||
</PageContentBlock>
|
</PageContentBlock>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,16 +55,16 @@ export default ({ server, className }: { server: Server; className?: string }) =
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GreyRowBox as={Link} to={`/server/${server.id}`} className={className}>
|
<GreyRowBox as={Link} to={`/server/${server.id}`} className={className}>
|
||||||
<div className={'icon'}>
|
<div className={'icon'} css={tw`hidden md:block`}>
|
||||||
<FontAwesomeIcon icon={faServer}/>
|
<FontAwesomeIcon icon={faServer}/>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex-1 ml-4`}>
|
<div css={tw`flex-1 md:ml-4`}>
|
||||||
<p css={tw`text-lg`}>{server.name}</p>
|
<p css={tw`text-lg`}>{server.name}</p>
|
||||||
{!!server.description &&
|
{!!server.description &&
|
||||||
<p css={tw`text-sm text-neutral-300`}>{server.description}</p>
|
<p css={tw`text-sm text-neutral-300`}>{server.description}</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`w-48 overflow-hidden self-start`}>
|
<div css={tw`w-48 overflow-hidden self-start hidden lg:block`}>
|
||||||
<div css={tw`flex ml-4 justify-end`}>
|
<div css={tw`flex ml-4 justify-end`}>
|
||||||
<FontAwesomeIcon icon={faEthernet} css={tw`text-neutral-500`}/>
|
<FontAwesomeIcon icon={faEthernet} css={tw`text-neutral-500`}/>
|
||||||
<p css={tw`text-sm text-neutral-400 ml-2`}>
|
<p css={tw`text-sm text-neutral-400 ml-2`}>
|
||||||
|
@ -76,7 +76,7 @@ export default ({ server, className }: { server: Server; className?: string }) =
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`w-1/3 flex items-baseline justify-center relative`}>
|
<div css={tw`w-1/3 sm:w-1/2 lg:w-1/3 flex items-baseline justify-center relative`}>
|
||||||
{!stats ?
|
{!stats ?
|
||||||
!statsError ?
|
!statsError ?
|
||||||
<Spinner size={'small'}/>
|
<Spinner size={'small'}/>
|
||||||
|
@ -95,7 +95,7 @@ export default ({ server, className }: { server: Server; className?: string }) =
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div css={tw`flex-1 flex ml-4 justify-center`}>
|
<div css={tw`flex-1 flex md:ml-4 sm:flex hidden justify-center`}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faMicrochip}
|
icon={faMicrochip}
|
||||||
css={[
|
css={[
|
||||||
|
@ -113,7 +113,7 @@ export default ({ server, className }: { server: Server; className?: string }) =
|
||||||
{stats.cpuUsagePercent} %
|
{stats.cpuUsagePercent} %
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex-1 ml-4`}>
|
<div css={tw`flex-1 ml-4 sm:block hidden`}>
|
||||||
<div css={tw`flex justify-center`}>
|
<div css={tw`flex justify-center`}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faMemory}
|
icon={faMemory}
|
||||||
|
@ -134,7 +134,7 @@ export default ({ server, className }: { server: Server; className?: string }) =
|
||||||
</div>
|
</div>
|
||||||
<p css={tw`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>
|
||||||
<div css={tw`flex-1 ml-4`}>
|
<div css={tw`flex-1 ml-4 sm:block hidden`}>
|
||||||
<div css={tw`flex justify-center`}>
|
<div css={tw`flex justify-center`}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faHdd}
|
icon={faHdd}
|
||||||
|
@ -155,6 +155,19 @@ export default ({ server, className }: { server: Server; className?: string }) =
|
||||||
</div>
|
</div>
|
||||||
<p css={tw`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>
|
</div>
|
||||||
|
|
||||||
|
<div css={tw`flex-1 flex justify-end sm:hidden`}>
|
||||||
|
<div css={tw`flex items-end text-right`}>
|
||||||
|
<div
|
||||||
|
css={[
|
||||||
|
tw`w-3 h-3 rounded-full`,
|
||||||
|
(!stats?.status || stats?.status === 'offline')
|
||||||
|
? tw`bg-red-500`
|
||||||
|
: (stats?.status === 'running' ? tw`bg-green-500` : tw`bg-yellow-500`),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { faTimes } from '@fortawesome/free-solid-svg-icons';
|
||||||
import Spinner from '@/components/elements/Spinner';
|
import Spinner from '@/components/elements/Spinner';
|
||||||
import tw from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
import styled from 'styled-components/macro';
|
import styled from 'styled-components/macro';
|
||||||
|
import { breakpoint } from '@/theme';
|
||||||
import Fade from '@/components/elements/Fade';
|
import Fade from '@/components/elements/Fade';
|
||||||
|
|
||||||
export interface RequiredModalProps {
|
export interface RequiredModalProps {
|
||||||
|
@ -26,9 +27,16 @@ export const ModalMask = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ModalContainer = styled.div<{ alignTop?: boolean }>`
|
const ModalContainer = styled.div<{ alignTop?: boolean }>`
|
||||||
|
${breakpoint('xs')`
|
||||||
|
max-width: 95%;
|
||||||
|
`};
|
||||||
|
|
||||||
|
${breakpoint('md')`
|
||||||
|
max-width: 50%;
|
||||||
|
`};
|
||||||
|
|
||||||
${tw`relative flex flex-col w-full m-auto`};
|
${tw`relative flex flex-col w-full m-auto`};
|
||||||
max-height: calc(100vh - 8rem);
|
max-height: calc(100vh - 8rem);
|
||||||
max-width: 50%;
|
|
||||||
// @todo max-w-screen-lg perhaps?
|
// @todo max-w-screen-lg perhaps?
|
||||||
${props => props.alignTop && 'margin-top: 10%'};
|
${props => props.alignTop && 'margin-top: 10%'};
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@ import tw from 'twin.macro';
|
||||||
import config from '../../../../tailwind.config';
|
import config from '../../../../tailwind.config';
|
||||||
|
|
||||||
const SubNavigation = styled.div`
|
const SubNavigation = styled.div`
|
||||||
${tw`w-full bg-neutral-700 shadow`};
|
${tw`w-full bg-neutral-700 shadow overflow-x-auto`};
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
${tw`flex items-center text-sm mx-auto px-2`};
|
${tw`flex items-center text-sm mx-auto px-2`};
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
|
|
||||||
& > a, & > div {
|
& > a, & > div {
|
||||||
${tw`inline-block py-3 px-4 text-neutral-300 no-underline transition-all duration-150`};
|
${tw`inline-block py-3 px-4 text-neutral-300 no-underline whitespace-no-wrap transition-all duration-150`};
|
||||||
|
|
||||||
&:not(:first-of-type) {
|
&:not(:first-of-type) {
|
||||||
${tw`ml-2`};
|
${tw`ml-2`};
|
||||||
|
|
|
@ -63,8 +63,8 @@ export default () => {
|
||||||
const memorylimit = limits.memory ? megabytesToHuman(limits.memory) : 'Unlimited';
|
const memorylimit = limits.memory ? megabytesToHuman(limits.memory) : 'Unlimited';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ServerContentBlock title={'Console'} css={tw`flex`}>
|
<ServerContentBlock title={'Console'} css={tw`flex flex-wrap`}>
|
||||||
<div css={tw`w-1/4`}>
|
<div css={tw`w-full md:w-1/4`}>
|
||||||
<TitledGreyBox title={name} icon={faServer}>
|
<TitledGreyBox title={name} icon={faServer}>
|
||||||
<p css={tw`text-xs uppercase`}>
|
<p css={tw`text-xs uppercase`}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
@ -137,7 +137,7 @@ export default () => {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex-1 ml-4`}>
|
<div css={tw`w-full md:flex-1 md:ml-4 mt-4 md:mt-0`}>
|
||||||
<SuspenseSpinner>
|
<SuspenseSpinner>
|
||||||
<ChunkedConsole/>
|
<ChunkedConsole/>
|
||||||
<ChunkedStatGraphs/>
|
<ChunkedStatGraphs/>
|
||||||
|
|
|
@ -141,8 +141,8 @@ export default () => {
|
||||||
}, [ instance, connected, memory, cpu ]);
|
}, [ instance, connected, memory, cpu ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div css={tw`flex mt-4`}>
|
<div css={tw`flex flex-wrap mt-4`}>
|
||||||
<TitledGreyBox title={'Memory usage'} icon={faMemory} css={tw`flex-1 mr-2`}>
|
<TitledGreyBox title={'Memory usage'} icon={faMemory} css={tw`md:flex-1 w-full md:w-1/2 md:mr-2`}>
|
||||||
{status !== 'offline' ?
|
{status !== 'offline' ?
|
||||||
<canvas id={'memory_chart'} ref={memoryRef} aria-label={'Server Memory Usage Graph'} role={'img'}/>
|
<canvas id={'memory_chart'} ref={memoryRef} aria-label={'Server Memory Usage Graph'} role={'img'}/>
|
||||||
:
|
:
|
||||||
|
@ -151,7 +151,7 @@ export default () => {
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
</TitledGreyBox>
|
</TitledGreyBox>
|
||||||
<TitledGreyBox title={'CPU usage'} icon={faMicrochip} css={tw`flex-1 ml-2`}>
|
<TitledGreyBox title={'CPU usage'} icon={faMicrochip} css={tw`md:flex-1 w-full md:w-1/2 md:ml-2 mt-4 md:mt-0`}>
|
||||||
{status !== 'offline' ?
|
{status !== 'offline' ?
|
||||||
<canvas id={'cpu_chart'} ref={cpuRef} aria-label={'Server CPU Usage Graph'} role={'img'}/>
|
<canvas id={'cpu_chart'} ref={cpuRef} aria-label={'Server CPU Usage Graph'} role={'img'}/>
|
||||||
:
|
:
|
||||||
|
|
|
@ -43,7 +43,7 @@ export default ({ backup, className }: Props) => {
|
||||||
<GreyRowBox css={tw`flex items-center`} className={className}>
|
<GreyRowBox css={tw`flex items-center`} className={className}>
|
||||||
<div css={tw`mr-4`}>
|
<div css={tw`mr-4`}>
|
||||||
{backup.completedAt ?
|
{backup.completedAt ?
|
||||||
<FontAwesomeIcon icon={faArchive} css={tw`text-neutral-300`}/>
|
<FontAwesomeIcon icon={faArchive} css={tw`text-neutral-300 hidden md:block`}/>
|
||||||
:
|
:
|
||||||
<Spinner size={'small'}/>
|
<Spinner size={'small'}/>
|
||||||
}
|
}
|
||||||
|
@ -57,10 +57,10 @@ export default ({ backup, className }: Props) => {
|
||||||
}
|
}
|
||||||
{backup.name}
|
{backup.name}
|
||||||
{(backup.completedAt && backup.isSuccessful) &&
|
{(backup.completedAt && backup.isSuccessful) &&
|
||||||
<span css={tw`ml-3 text-neutral-300 text-xs font-thin`}>{bytesToHuman(backup.bytes)}</span>
|
<span css={tw`ml-3 text-neutral-300 text-xs font-thin hidden sm:inline`}>{bytesToHuman(backup.bytes)}</span>
|
||||||
}
|
}
|
||||||
</p>
|
</p>
|
||||||
<p css={tw`text-xs text-neutral-400 font-mono`}>
|
<p css={tw`text-xs text-neutral-400 font-mono hidden md:block`}>
|
||||||
{backup.uuid}
|
{backup.uuid}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,7 +9,7 @@ const ChecksumModal = ({ checksum, ...props }: RequiredModalProps & { checksum:
|
||||||
The checksum of this file is:
|
The checksum of this file is:
|
||||||
</p>
|
</p>
|
||||||
<pre css={tw`mt-2 text-sm p-2 bg-neutral-900 rounded`}>
|
<pre css={tw`mt-2 text-sm p-2 bg-neutral-900 rounded`}>
|
||||||
<code css={tw`block font-mono`}>{checksum}</code>
|
<code css={tw`block font-mono overflow-auto`}>{checksum}</code>
|
||||||
</pre>
|
</pre>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -111,8 +111,20 @@ export default ({ database, className }: Props) => {
|
||||||
<Modal visible={connectionVisible} onDismissed={() => setConnectionVisible(false)}>
|
<Modal visible={connectionVisible} onDismissed={() => setConnectionVisible(false)}>
|
||||||
<FlashMessageRender byKey={'database-connection-modal'} css={tw`mb-6`}/>
|
<FlashMessageRender byKey={'database-connection-modal'} css={tw`mb-6`}/>
|
||||||
<h3 css={tw`mb-6`}>Database connection details</h3>
|
<h3 css={tw`mb-6`}>Database connection details</h3>
|
||||||
|
<div>
|
||||||
|
<Label>Endpoint</Label>
|
||||||
|
<Input type={'text'} readOnly value={database.connectionString} />
|
||||||
|
</div>
|
||||||
|
<div css={tw`mt-6`}>
|
||||||
|
<Label>Connections from</Label>
|
||||||
|
<Input type={'text'} readOnly value={database.allowConnectionsFrom} />
|
||||||
|
</div>
|
||||||
|
<div css={tw`mt-6`}>
|
||||||
|
<Label>Username</Label>
|
||||||
|
<Input type={'text'} readOnly value={database.username} />
|
||||||
|
</div>
|
||||||
<Can action={'database.view_password'}>
|
<Can action={'database.view_password'}>
|
||||||
<div>
|
<div css={tw`mt-6`}>
|
||||||
<Label>Password</Label>
|
<Label>Password</Label>
|
||||||
<Input type={'text'} readOnly value={database.password}/>
|
<Input type={'text'} readOnly value={database.password}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -134,22 +146,22 @@ export default ({ database, className }: Props) => {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
<GreyRowBox $hoverable={false} className={className}>
|
<GreyRowBox $hoverable={false} className={className} css={tw`mb-2`}>
|
||||||
<div>
|
<div css={tw`hidden md:block`}>
|
||||||
<FontAwesomeIcon icon={faDatabase} fixedWidth/>
|
<FontAwesomeIcon icon={faDatabase} fixedWidth/>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex-1 ml-4`}>
|
<div css={tw`flex-1 ml-4`}>
|
||||||
<p css={tw`text-lg`}>{database.name}</p>
|
<p css={tw`text-lg`}>{database.name}</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-8 text-center`}>
|
<div css={tw`ml-8 text-center hidden md:block`}>
|
||||||
<p css={tw`text-sm`}>{database.connectionString}</p>
|
<p css={tw`text-sm`}>{database.connectionString}</p>
|
||||||
<p css={tw`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Endpoint</p>
|
<p css={tw`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Endpoint</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-8 text-center`}>
|
<div css={tw`ml-8 text-center hidden md:block`}>
|
||||||
<p css={tw`text-sm`}>{database.allowConnectionsFrom}</p>
|
<p css={tw`text-sm`}>{database.allowConnectionsFrom}</p>
|
||||||
<p css={tw`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Connections from</p>
|
<p css={tw`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Connections from</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-8 text-center`}>
|
<div css={tw`ml-8 text-center hidden md:block`}>
|
||||||
<p css={tw`text-sm`}>{database.username}</p>
|
<p css={tw`text-sm`}>{database.username}</p>
|
||||||
<p css={tw`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Username</p>
|
<p css={tw`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Username</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -73,12 +73,12 @@ const FileObjectRow = ({ file }: { file: FileObject }) => (
|
||||||
{file.name}
|
{file.name}
|
||||||
</div>
|
</div>
|
||||||
{file.isFile &&
|
{file.isFile &&
|
||||||
<div css={tw`w-1/6 text-right mr-4`}>
|
<div css={tw`w-1/6 text-right mr-4 hidden sm:block`}>
|
||||||
{bytesToHuman(file.size)}
|
{bytesToHuman(file.size)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div
|
<div
|
||||||
css={tw`w-1/5 text-right mr-4`}
|
css={tw`w-1/5 text-right mr-4 hidden md:block`}
|
||||||
title={file.modifiedAt.toString()}
|
title={file.modifiedAt.toString()}
|
||||||
>
|
>
|
||||||
{Math.abs(differenceInHours(file.modifiedAt, new Date())) > 48 ?
|
{Math.abs(differenceInHours(file.modifiedAt, new Date())) > 48 ?
|
||||||
|
|
|
@ -68,8 +68,8 @@ const NetworkContainer = () => {
|
||||||
<Spinner size={'large'} centered/>
|
<Spinner size={'large'} centered/>
|
||||||
:
|
:
|
||||||
data.map(({ id, ip, port, alias, notes, isDefault }, index) => (
|
data.map(({ id, ip, port, alias, notes, isDefault }, index) => (
|
||||||
<GreyRowBox key={`${ip}:${port}`} css={index > 0 ? tw`mt-2` : undefined} $hoverable={false}>
|
<GreyRowBox key={`${ip}:${port}`} css={index > 0 ? tw`mt-2 overflow-x-auto` : tw`overflow-x-auto`} $hoverable={false}>
|
||||||
<div css={tw`pl-4 pr-6 text-neutral-400`}>
|
<div css={tw`hidden md:block pl-4 pr-6 text-neutral-400`}>
|
||||||
<FontAwesomeIcon icon={faNetworkWired}/>
|
<FontAwesomeIcon icon={faNetworkWired}/>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`mr-4`}>
|
<div css={tw`mr-4`}>
|
||||||
|
@ -80,7 +80,7 @@ const NetworkContainer = () => {
|
||||||
<Code>{port}</Code>
|
<Code>{port}</Code>
|
||||||
<Label>Port</Label>
|
<Label>Port</Label>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`px-8 flex-1 self-start`}>
|
<div css={tw`px-8 flex-none sm:flex-1 self-start`}>
|
||||||
<InputSpinner visible={loading === id}>
|
<InputSpinner visible={loading === id}>
|
||||||
<Textarea
|
<Textarea
|
||||||
css={tw`bg-neutral-800 hover:border-neutral-600 border-transparent`}
|
css={tw`bg-neutral-800 hover:border-neutral-600 border-transparent`}
|
||||||
|
@ -90,7 +90,7 @@ const NetworkContainer = () => {
|
||||||
/>
|
/>
|
||||||
</InputSpinner>
|
</InputSpinner>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`w-32 text-right`}>
|
<div css={tw`w-32 text-right mr-2 md:mr-0`}>
|
||||||
{isDefault ?
|
{isDefault ?
|
||||||
<span css={tw`bg-green-500 py-1 px-2 rounded text-green-50 text-xs`}>
|
<span css={tw`bg-green-500 py-1 px-2 rounded text-green-50 text-xs`}>
|
||||||
Primary
|
Primary
|
||||||
|
|
|
@ -52,7 +52,7 @@ export default ({ match, history }: RouteComponentProps) => {
|
||||||
as={'a'}
|
as={'a'}
|
||||||
key={schedule.id}
|
key={schedule.id}
|
||||||
href={`${match.url}/${schedule.id}`}
|
href={`${match.url}/${schedule.id}`}
|
||||||
css={tw`cursor-pointer mb-2`}
|
css={tw`cursor-pointer mb-2 flex-wrap`}
|
||||||
onClick={(e: any) => {
|
onClick={(e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
history.push(`${match.url}/${schedule.id}`, { schedule });
|
history.push(`${match.url}/${schedule.id}`, { schedule });
|
||||||
|
|
|
@ -60,7 +60,7 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
|
||||||
<Spinner size={'large'} centered/>
|
<Spinner size={'large'} centered/>
|
||||||
:
|
:
|
||||||
<>
|
<>
|
||||||
<GreyRowBox>
|
<GreyRowBox css={tw`cursor-pointer mb-2 flex-wrap`}>
|
||||||
<ScheduleRow schedule={schedule}/>
|
<ScheduleRow schedule={schedule}/>
|
||||||
</GreyRowBox>
|
</GreyRowBox>
|
||||||
<EditScheduleModal
|
<EditScheduleModal
|
||||||
|
|
|
@ -7,42 +7,52 @@ import tw from 'twin.macro';
|
||||||
|
|
||||||
export default ({ schedule }: { schedule: Schedule }) => (
|
export default ({ schedule }: { schedule: Schedule }) => (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div css={tw`hidden md:block`}>
|
||||||
<FontAwesomeIcon icon={faCalendarAlt} fixedWidth/>
|
<FontAwesomeIcon icon={faCalendarAlt} fixedWidth/>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex-1 ml-4`}>
|
<div css={tw`flex-1 md:ml-4`}>
|
||||||
<p>{schedule.name}</p>
|
<p>{schedule.name}</p>
|
||||||
<p css={tw`text-xs text-neutral-400`}>
|
<p css={tw`text-xs text-neutral-400`}>
|
||||||
Last run
|
Last run
|
||||||
at: {schedule.lastRunAt ? format(schedule.lastRunAt, 'MMM do \'at\' h:mma') : 'never'}
|
at: {schedule.lastRunAt ? format(schedule.lastRunAt, 'MMM do \'at\' h:mma') : 'never'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex items-center mx-8`}>
|
<div>
|
||||||
<div>
|
<p
|
||||||
<p css={tw`font-medium text-center`}>{schedule.cron.minute}</p>
|
css={[
|
||||||
|
tw`py-1 px-3 rounded text-xs uppercase text-white sm:hidden`,
|
||||||
|
schedule.isActive ? tw`bg-green-600` : tw`bg-neutral-400`,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{schedule.isActive ? 'Active' : 'Inactive'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div css={tw`flex items-center mx-auto sm:mx-8 w-full sm:w-auto mt-4 sm:mt-0`}>
|
||||||
|
<div css={tw`w-1/5 sm:w-auto text-center`}>
|
||||||
|
<p css={tw`font-medium`}>{schedule.cron.minute}</p>
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Minute</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase`}>Minute</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-4`}>
|
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||||
<p css={tw`font-medium text-center`}>{schedule.cron.hour}</p>
|
<p css={tw`font-medium`}>{schedule.cron.hour}</p>
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Hour</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase`}>Hour</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-4`}>
|
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||||
<p css={tw`font-medium text-center`}>{schedule.cron.dayOfMonth}</p>
|
<p css={tw`font-medium`}>{schedule.cron.dayOfMonth}</p>
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Month)</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Month)</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-4`}>
|
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||||
<p css={tw`font-medium text-center`}>*</p>
|
<p css={tw`font-medium`}>*</p>
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Month</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase`}>Month</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-4`}>
|
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||||
<p css={tw`font-medium text-center`}>{schedule.cron.dayOfWeek}</p>
|
<p css={tw`font-medium`}>{schedule.cron.dayOfWeek}</p>
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Week)</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Week)</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p
|
<p
|
||||||
css={[
|
css={[
|
||||||
tw`py-1 px-3 rounded text-xs uppercase text-white`,
|
tw`py-1 px-3 rounded text-xs uppercase text-white hidden sm:block`,
|
||||||
schedule.isActive ? tw`bg-green-600` : tw`bg-neutral-400`,
|
schedule.isActive ? tw`bg-green-600` : tw`bg-neutral-400`,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default ({ schedule, task }: Props) => {
|
||||||
const [ title, icon ] = getActionDetails(task.action);
|
const [ title, icon ] = getActionDetails(task.action);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div css={tw`flex items-center bg-neutral-700 border border-neutral-600 mb-2 px-6 py-4 rounded`}>
|
<div css={tw`flex flex-wrap items-center bg-neutral-700 border border-neutral-600 mb-2 px-6 py-4 rounded`}>
|
||||||
<SpinnerOverlay visible={isLoading} fixed size={'large'}/>
|
<SpinnerOverlay visible={isLoading} fixed size={'large'}/>
|
||||||
{isEditing && <TaskDetailsModal
|
{isEditing && <TaskDetailsModal
|
||||||
schedule={schedule}
|
schedule={schedule}
|
||||||
|
@ -72,13 +72,13 @@ export default ({ schedule, task }: Props) => {
|
||||||
>
|
>
|
||||||
Are you sure you want to delete this task? This action cannot be undone.
|
Are you sure you want to delete this task? This action cannot be undone.
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
<FontAwesomeIcon icon={icon} css={tw`text-lg text-white`}/>
|
<FontAwesomeIcon icon={icon} css={tw`text-lg text-white hidden md:block`}/>
|
||||||
<div css={tw`flex-1`}>
|
<div css={tw`flex-none sm:flex-1 mb-4 sm:mb-0 w-full md:w-auto overflow-x-auto`}>
|
||||||
<p css={tw`ml-6 text-neutral-300 uppercase text-xs`}>
|
<p css={tw`md:ml-6 text-neutral-300 uppercase text-xs`}>
|
||||||
{title}
|
{title}
|
||||||
</p>
|
</p>
|
||||||
{task.payload &&
|
{task.payload &&
|
||||||
<div css={tw`ml-6 mt-2`}>
|
<div css={tw`md:ml-6 mt-2`}>
|
||||||
{task.action === 'backup' &&
|
{task.action === 'backup' &&
|
||||||
<p css={tw`text-xs uppercase text-neutral-400 mb-1`}>Ignoring files & folders:</p>}
|
<p css={tw`text-xs uppercase text-neutral-400 mb-1`}>Ignoring files & folders:</p>}
|
||||||
<div css={tw`font-mono bg-neutral-800 rounded py-1 px-2 text-sm w-auto whitespace-pre inline-block`}>
|
<div css={tw`font-mono bg-neutral-800 rounded py-1 px-2 text-sm w-auto whitespace-pre inline-block`}>
|
||||||
|
@ -101,7 +101,7 @@ export default ({ schedule, task }: Props) => {
|
||||||
<button
|
<button
|
||||||
type={'button'}
|
type={'button'}
|
||||||
aria-label={'Edit scheduled task'}
|
aria-label={'Edit scheduled task'}
|
||||||
css={tw`block text-sm p-2 text-neutral-500 hover:text-neutral-100 transition-colors duration-150 mr-4`}
|
css={tw`block text-sm p-2 text-neutral-500 hover:text-neutral-100 transition-colors duration-150 mr-4 ml-auto sm:ml-0`}
|
||||||
onClick={() => setIsEditing(true)}
|
onClick={() => setIsEditing(true)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faPencilAlt}/>
|
<FontAwesomeIcon icon={faPencilAlt}/>
|
||||||
|
|
|
@ -55,7 +55,7 @@ const StartupContainer = () => {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</TitledGreyBox>
|
</TitledGreyBox>
|
||||||
<div css={tw`grid gap-8 grid-cols-2 mt-10`}>
|
<div css={tw`grid gap-8 md:grid-cols-2 mt-10`}>
|
||||||
{data.variables.map(variable => <VariableBox key={variable.envVariable} variable={variable}/>)}
|
{data.variables.map(variable => <VariableBox key={variable.envVariable} variable={variable}/>)}
|
||||||
</div>
|
</div>
|
||||||
</ServerContentBlock>
|
</ServerContentBlock>
|
||||||
|
|
|
@ -47,13 +47,13 @@ const VariableBox = ({ variable }: Props) => {
|
||||||
title={
|
title={
|
||||||
<p css={tw`text-sm uppercase`}>
|
<p css={tw`text-sm uppercase`}>
|
||||||
{!variable.isEditable &&
|
{!variable.isEditable &&
|
||||||
<span css={tw`bg-neutral-700 text-xs py-1 px-2 rounded-full mr-2`}>Read Only</span>
|
<span css={tw`bg-neutral-700 text-xs py-1 px-2 rounded-full mr-2 mb-1`}>Read Only</span>
|
||||||
}
|
}
|
||||||
{variable.name}
|
{variable.name}
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FlashMessageRender byKey={FLASH_KEY} css={tw`mb-4`}/>
|
<FlashMessageRender byKey={FLASH_KEY} css={tw`mb-2 md:mb-4`}/>
|
||||||
<InputSpinner visible={loading}>
|
<InputSpinner visible={loading}>
|
||||||
<Input
|
<Input
|
||||||
onKeyUp={e => {
|
onKeyUp={e => {
|
||||||
|
|
|
@ -27,11 +27,11 @@ export default ({ subuser }: Props) => {
|
||||||
onDismissed={() => setVisible(false)}
|
onDismissed={() => setVisible(false)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div css={tw`w-10 h-10 rounded-full bg-white border-2 border-neutral-800 overflow-hidden`}>
|
<div css={tw`w-10 h-10 rounded-full bg-white border-2 border-neutral-800 overflow-hidden hidden md:block`}>
|
||||||
<img css={tw`w-full h-full`} src={`${subuser.image}?s=400`}/>
|
<img css={tw`w-full h-full`} src={`${subuser.image}?s=400`}/>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-4 flex-1`}>
|
<div css={tw`ml-4 flex-1`}>
|
||||||
<p css={tw`text-sm`}>{subuser.email}</p>
|
<p css={tw`text-sm truncate`}>{subuser.email}</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-4`}>
|
<div css={tw`ml-4`}>
|
||||||
<p css={tw`font-medium text-center`}>
|
<p css={tw`font-medium text-center`}>
|
||||||
|
@ -43,9 +43,9 @@ export default ({ subuser }: Props) => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>2FA Enabled</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase hidden md:block`}>2FA Enabled</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`ml-4`}>
|
<div css={tw`ml-4 hidden md:block`}>
|
||||||
<p css={tw`font-medium text-center`}>
|
<p css={tw`font-medium text-center`}>
|
||||||
{subuser.permissions.filter(permission => permission !== 'websocket.connect').length}
|
{subuser.permissions.filter(permission => permission !== 'websocket.connect').length}
|
||||||
</p>
|
</p>
|
||||||
|
@ -56,7 +56,7 @@ export default ({ subuser }: Props) => {
|
||||||
<button
|
<button
|
||||||
type={'button'}
|
type={'button'}
|
||||||
aria-label={'Edit subuser'}
|
aria-label={'Edit subuser'}
|
||||||
css={tw`block text-sm p-2 text-neutral-500 hover:text-neutral-100 transition-colors duration-150 mx-4`}
|
css={tw`block text-sm p-1 md:p-2 text-neutral-500 hover:text-neutral-100 transition-colors duration-150 mx-4`}
|
||||||
onClick={() => setVisible(true)}
|
onClick={() => setVisible(true)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faPencilAlt}/>
|
<FontAwesomeIcon icon={faPencilAlt}/>
|
||||||
|
|
|
@ -48,8 +48,8 @@
|
||||||
</tr>
|
</tr>
|
||||||
@foreach ($packs as $pack)
|
@foreach ($packs as $pack)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="middle" data-toggle="tooltip" data-placement="right" title="{{ $pack->uuid }}"><code>{{ $pack->id }}</code></td>
|
<td class="middle"><code>{{ $pack->id }}</code></td>
|
||||||
<td class="middle"><a href="{{ route('admin.packs.view', $pack->id) }}">{{ $pack->name }}</a></td>
|
<td class="middle"><a href="{{ route('admin.packs.view', $pack->id) }}" data-toggle="tooltip" data-placement="right" title="{{ $pack->uuid }}">{{ $pack->name }}</a></td>
|
||||||
<td class="middle"><code>{{ $pack->version }}</code></td>
|
<td class="middle"><code>{{ $pack->version }}</code></td>
|
||||||
<td class="col-md-6">{{ str_limit($pack->description, 150) }}</td>
|
<td class="col-md-6">{{ str_limit($pack->description, 150) }}</td>
|
||||||
<td class="middle"><a href="{{ route('admin.nests.egg.view', $pack->egg->id) }}">{{ $pack->egg->name }}</a></td>
|
<td class="middle"><a href="{{ route('admin.nests.egg.view', $pack->egg->id) }}">{{ $pack->egg->name }}</a></td>
|
||||||
|
|
Loading…
Reference in a new issue