Make interface mobile responsive (#2273)
This commit is contained in:
parent
9a21584c42
commit
9a4c0d8ba7
20 changed files with 130 additions and 69 deletions
|
@ -63,8 +63,8 @@ export default () => {
|
|||
const memorylimit = limits.memory ? megabytesToHuman(limits.memory) : 'Unlimited';
|
||||
|
||||
return (
|
||||
<ServerContentBlock title={'Console'} css={tw`flex`}>
|
||||
<div css={tw`w-1/4`}>
|
||||
<ServerContentBlock title={'Console'} css={tw`flex flex-wrap`}>
|
||||
<div css={tw`w-full md:w-1/4`}>
|
||||
<TitledGreyBox title={name} icon={faServer}>
|
||||
<p css={tw`text-xs uppercase`}>
|
||||
<FontAwesomeIcon
|
||||
|
@ -137,7 +137,7 @@ export default () => {
|
|||
</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>
|
||||
<ChunkedConsole/>
|
||||
<ChunkedStatGraphs/>
|
||||
|
|
|
@ -141,8 +141,8 @@ export default () => {
|
|||
}, [ instance, connected, memory, cpu ]);
|
||||
|
||||
return (
|
||||
<div css={tw`flex mt-4`}>
|
||||
<TitledGreyBox title={'Memory usage'} icon={faMemory} css={tw`flex-1 mr-2`}>
|
||||
<div css={tw`flex flex-wrap mt-4`}>
|
||||
<TitledGreyBox title={'Memory usage'} icon={faMemory} css={tw`md:flex-1 w-full md:w-1/2 md:mr-2`}>
|
||||
{status !== 'offline' ?
|
||||
<canvas id={'memory_chart'} ref={memoryRef} aria-label={'Server Memory Usage Graph'} role={'img'}/>
|
||||
:
|
||||
|
@ -151,7 +151,7 @@ export default () => {
|
|||
</p>
|
||||
}
|
||||
</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' ?
|
||||
<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}>
|
||||
<div css={tw`mr-4`}>
|
||||
{backup.completedAt ?
|
||||
<FontAwesomeIcon icon={faArchive} css={tw`text-neutral-300`}/>
|
||||
<FontAwesomeIcon icon={faArchive} css={tw`text-neutral-300 hidden md:block`}/>
|
||||
:
|
||||
<Spinner size={'small'}/>
|
||||
}
|
||||
|
@ -57,10 +57,10 @@ export default ({ backup, className }: Props) => {
|
|||
}
|
||||
{backup.name}
|
||||
{(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 css={tw`text-xs text-neutral-400 font-mono`}>
|
||||
<p css={tw`text-xs text-neutral-400 font-mono hidden md:block`}>
|
||||
{backup.uuid}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@ const ChecksumModal = ({ checksum, ...props }: RequiredModalProps & { checksum:
|
|||
The checksum of this file is:
|
||||
</p>
|
||||
<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>
|
||||
</Modal>
|
||||
);
|
||||
|
|
|
@ -111,8 +111,20 @@ export default ({ database, className }: Props) => {
|
|||
<Modal visible={connectionVisible} onDismissed={() => setConnectionVisible(false)}>
|
||||
<FlashMessageRender byKey={'database-connection-modal'} css={tw`mb-6`}/>
|
||||
<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'}>
|
||||
<div>
|
||||
<div css={tw`mt-6`}>
|
||||
<Label>Password</Label>
|
||||
<Input type={'text'} readOnly value={database.password}/>
|
||||
</div>
|
||||
|
@ -134,22 +146,22 @@ export default ({ database, className }: Props) => {
|
|||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<GreyRowBox $hoverable={false} className={className}>
|
||||
<div>
|
||||
<GreyRowBox $hoverable={false} className={className} css={tw`mb-2`}>
|
||||
<div css={tw`hidden md:block`}>
|
||||
<FontAwesomeIcon icon={faDatabase} fixedWidth/>
|
||||
</div>
|
||||
<div css={tw`flex-1 ml-4`}>
|
||||
<p css={tw`text-lg`}>{database.name}</p>
|
||||
</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`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Endpoint</p>
|
||||
</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`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Connections from</p>
|
||||
</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`mt-1 text-2xs text-neutral-500 uppercase select-none`}>Username</p>
|
||||
</div>
|
||||
|
|
|
@ -73,12 +73,12 @@ const FileObjectRow = ({ file }: { file: FileObject }) => (
|
|||
{file.name}
|
||||
</div>
|
||||
{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)}
|
||||
</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()}
|
||||
>
|
||||
{Math.abs(differenceInHours(file.modifiedAt, new Date())) > 48 ?
|
||||
|
|
|
@ -68,8 +68,8 @@ const NetworkContainer = () => {
|
|||
<Spinner size={'large'} centered/>
|
||||
:
|
||||
data.map(({ id, ip, port, alias, notes, isDefault }, index) => (
|
||||
<GreyRowBox key={`${ip}:${port}`} css={index > 0 ? tw`mt-2` : undefined} $hoverable={false}>
|
||||
<div css={tw`pl-4 pr-6 text-neutral-400`}>
|
||||
<GreyRowBox key={`${ip}:${port}`} css={index > 0 ? tw`mt-2 overflow-x-auto` : tw`overflow-x-auto`} $hoverable={false}>
|
||||
<div css={tw`hidden md:block pl-4 pr-6 text-neutral-400`}>
|
||||
<FontAwesomeIcon icon={faNetworkWired}/>
|
||||
</div>
|
||||
<div css={tw`mr-4`}>
|
||||
|
@ -80,7 +80,7 @@ const NetworkContainer = () => {
|
|||
<Code>{port}</Code>
|
||||
<Label>Port</Label>
|
||||
</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}>
|
||||
<Textarea
|
||||
css={tw`bg-neutral-800 hover:border-neutral-600 border-transparent`}
|
||||
|
@ -90,7 +90,7 @@ const NetworkContainer = () => {
|
|||
/>
|
||||
</InputSpinner>
|
||||
</div>
|
||||
<div css={tw`w-32 text-right`}>
|
||||
<div css={tw`w-32 text-right mr-2 md:mr-0`}>
|
||||
{isDefault ?
|
||||
<span css={tw`bg-green-500 py-1 px-2 rounded text-green-50 text-xs`}>
|
||||
Primary
|
||||
|
|
|
@ -52,7 +52,7 @@ export default ({ match, history }: RouteComponentProps) => {
|
|||
as={'a'}
|
||||
key={schedule.id}
|
||||
href={`${match.url}/${schedule.id}`}
|
||||
css={tw`cursor-pointer mb-2`}
|
||||
css={tw`cursor-pointer mb-2 flex-wrap`}
|
||||
onClick={(e: any) => {
|
||||
e.preventDefault();
|
||||
history.push(`${match.url}/${schedule.id}`, { schedule });
|
||||
|
|
|
@ -60,7 +60,7 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
|
|||
<Spinner size={'large'} centered/>
|
||||
:
|
||||
<>
|
||||
<GreyRowBox>
|
||||
<GreyRowBox css={tw`cursor-pointer mb-2 flex-wrap`}>
|
||||
<ScheduleRow schedule={schedule}/>
|
||||
</GreyRowBox>
|
||||
<EditScheduleModal
|
||||
|
|
|
@ -7,42 +7,52 @@ import tw from 'twin.macro';
|
|||
|
||||
export default ({ schedule }: { schedule: Schedule }) => (
|
||||
<>
|
||||
<div>
|
||||
<div css={tw`hidden md:block`}>
|
||||
<FontAwesomeIcon icon={faCalendarAlt} fixedWidth/>
|
||||
</div>
|
||||
<div css={tw`flex-1 ml-4`}>
|
||||
<div css={tw`flex-1 md:ml-4`}>
|
||||
<p>{schedule.name}</p>
|
||||
<p css={tw`text-xs text-neutral-400`}>
|
||||
Last run
|
||||
at: {schedule.lastRunAt ? format(schedule.lastRunAt, 'MMM do \'at\' h:mma') : 'never'}
|
||||
</p>
|
||||
</div>
|
||||
<div css={tw`flex items-center mx-8`}>
|
||||
<div>
|
||||
<p css={tw`font-medium text-center`}>{schedule.cron.minute}</p>
|
||||
<div>
|
||||
<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>
|
||||
</div>
|
||||
<div css={tw`ml-4`}>
|
||||
<p css={tw`font-medium text-center`}>{schedule.cron.hour}</p>
|
||||
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||
<p css={tw`font-medium`}>{schedule.cron.hour}</p>
|
||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Hour</p>
|
||||
</div>
|
||||
<div css={tw`ml-4`}>
|
||||
<p css={tw`font-medium text-center`}>{schedule.cron.dayOfMonth}</p>
|
||||
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||
<p css={tw`font-medium`}>{schedule.cron.dayOfMonth}</p>
|
||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Month)</p>
|
||||
</div>
|
||||
<div css={tw`ml-4`}>
|
||||
<p css={tw`font-medium text-center`}>*</p>
|
||||
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||
<p css={tw`font-medium`}>*</p>
|
||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Month</p>
|
||||
</div>
|
||||
<div css={tw`ml-4`}>
|
||||
<p css={tw`font-medium text-center`}>{schedule.cron.dayOfWeek}</p>
|
||||
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||
<p css={tw`font-medium`}>{schedule.cron.dayOfWeek}</p>
|
||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Week)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p
|
||||
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`,
|
||||
]}
|
||||
>
|
||||
|
|
|
@ -56,7 +56,7 @@ export default ({ schedule, task }: Props) => {
|
|||
const [ title, icon ] = getActionDetails(task.action);
|
||||
|
||||
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'}/>
|
||||
{isEditing && <TaskDetailsModal
|
||||
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.
|
||||
</ConfirmationModal>
|
||||
<FontAwesomeIcon icon={icon} css={tw`text-lg text-white`}/>
|
||||
<div css={tw`flex-1`}>
|
||||
<p css={tw`ml-6 text-neutral-300 uppercase text-xs`}>
|
||||
<FontAwesomeIcon icon={icon} css={tw`text-lg text-white hidden md:block`}/>
|
||||
<div css={tw`flex-none sm:flex-1 mb-4 sm:mb-0 w-full md:w-auto overflow-x-auto`}>
|
||||
<p css={tw`md:ml-6 text-neutral-300 uppercase text-xs`}>
|
||||
{title}
|
||||
</p>
|
||||
{task.payload &&
|
||||
<div css={tw`ml-6 mt-2`}>
|
||||
<div css={tw`md:ml-6 mt-2`}>
|
||||
{task.action === 'backup' &&
|
||||
<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`}>
|
||||
|
@ -101,7 +101,7 @@ export default ({ schedule, task }: Props) => {
|
|||
<button
|
||||
type={'button'}
|
||||
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)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faPencilAlt}/>
|
||||
|
|
|
@ -55,7 +55,7 @@ const StartupContainer = () => {
|
|||
</p>
|
||||
</div>
|
||||
</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}/>)}
|
||||
</div>
|
||||
</ServerContentBlock>
|
||||
|
|
|
@ -47,13 +47,13 @@ const VariableBox = ({ variable }: Props) => {
|
|||
title={
|
||||
<p css={tw`text-sm uppercase`}>
|
||||
{!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}
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<FlashMessageRender byKey={FLASH_KEY} css={tw`mb-4`}/>
|
||||
<FlashMessageRender byKey={FLASH_KEY} css={tw`mb-2 md:mb-4`}/>
|
||||
<InputSpinner visible={loading}>
|
||||
<Input
|
||||
onKeyUp={e => {
|
||||
|
|
|
@ -27,11 +27,11 @@ export default ({ subuser }: Props) => {
|
|||
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`}/>
|
||||
</div>
|
||||
<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 css={tw`ml-4`}>
|
||||
<p css={tw`font-medium text-center`}>
|
||||
|
@ -43,9 +43,9 @@ export default ({ subuser }: Props) => {
|
|||
/>
|
||||
|
||||
</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 css={tw`ml-4`}>
|
||||
<div css={tw`ml-4 hidden md:block`}>
|
||||
<p css={tw`font-medium text-center`}>
|
||||
{subuser.permissions.filter(permission => permission !== 'websocket.connect').length}
|
||||
</p>
|
||||
|
@ -56,7 +56,7 @@ export default ({ subuser }: Props) => {
|
|||
<button
|
||||
type={'button'}
|
||||
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)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faPencilAlt}/>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue