Update schedule view UI

This commit is contained in:
Dane Everitt 2020-10-14 20:13:36 -07:00
parent 33a43de723
commit f33d0b1d72
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
12 changed files with 230 additions and 134 deletions

View file

@ -1,9 +1,9 @@
{ {
"name": "pterodactyl-panel", "name": "pterodactyl-panel",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.19", "@fortawesome/fontawesome-svg-core": "^1.2.32",
"@fortawesome/free-solid-svg-icons": "^5.9.0", "@fortawesome/free-solid-svg-icons": "^5.15.1",
"@fortawesome/react-fontawesome": "0.1.4", "@fortawesome/react-fontawesome": "^0.1.11",
"axios": "^0.19.2", "axios": "^0.19.2",
"chart.js": "^2.8.0", "chart.js": "^2.8.0",
"codemirror": "^5.57.0", "codemirror": "^5.57.0",
@ -23,9 +23,9 @@
"react": "^16.13.1", "react": "^16.13.1",
"react-dom": "npm:@hot-loader/react-dom", "react-dom": "npm:@hot-loader/react-dom",
"react-fast-compare": "^3.2.0", "react-fast-compare": "^3.2.0",
"react-ga": "^3.1.2",
"react-google-recaptcha": "^2.0.1", "react-google-recaptcha": "^2.0.1",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-ga": "^3.1.2",
"react-hot-loader": "^4.12.21", "react-hot-loader": "^4.12.21",
"react-i18next": "^11.2.1", "react-i18next": "^11.2.1",
"react-redux": "^7.1.0", "react-redux": "^7.1.0",

View file

@ -57,8 +57,8 @@ const ButtonStyle = styled.button<Omit<Props, 'isLoading'>>`
`}; `};
`}; `};
${props => props.size === 'xsmall' && tw`p-2 text-xs`}; ${props => props.size === 'xsmall' && tw`px-2 py-1 text-xs`};
${props => (!props.size || props.size === 'small') && tw`p-3`}; ${props => (!props.size || props.size === 'small') && tw`px-4 py-2`};
${props => props.size === 'large' && tw`p-4 text-sm`}; ${props => props.size === 'large' && tw`p-4 text-sm`};
${props => props.size === 'xlarge' && tw`p-4 w-full`}; ${props => props.size === 'xlarge' && tw`p-4 w-full`};

View file

@ -0,0 +1,31 @@
import React, { CSSProperties } from 'react';
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
import tw from 'twin.macro';
interface Props {
icon: IconDefinition;
className?: string;
style?: CSSProperties;
}
const Icon = ({ icon, className, style }: Props) => {
let [ width, height, , , paths ] = icon.icon;
paths = Array.isArray(paths) ? paths : [ paths ];
return (
<svg
xmlns={'http://www.w3.org/2000/svg'}
viewBox={`0 0 ${width} ${height}`}
css={tw`fill-current inline-block`}
className={className}
style={style}
>
{paths.map((path, index) => (
<path key={`svg_path_${index}`} d={path}/>
))}
</svg>
);
};
export default Icon;

View file

@ -1,9 +1,10 @@
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
import Spinner from '@/components/elements/Spinner'; import Spinner from '@/components/elements/Spinner';
import tw from 'twin.macro'; import tw from 'twin.macro';
import styled, { css } from 'styled-components/macro'; import styled, { css } from 'styled-components/macro';
import { breakpoint } from '@/theme'; import { breakpoint } from '@/theme';
import Fade from '@/components/elements/Fade'; import Fade from '@/components/elements/Fade';
import { createPortal } from 'react-dom';
export interface RequiredModalProps { export interface RequiredModalProps {
visible: boolean; visible: boolean;
@ -124,4 +125,10 @@ const Modal: React.FC<ModalProps> = ({ visible, appear, dismissable, showSpinner
); );
}; };
export default Modal; const PortaledModal: React.FC<ModalProps> = ({ children, ...props }) => {
const element = useRef(document.getElementById('modal-portal'));
return createPortal(<Modal {...props}>{children}</Modal>, element.current!);
};
export default PortaledModal;

View file

@ -49,7 +49,7 @@ export default ({ scheduleId, onDeleted }: Props) => {
Are you sure you want to delete this schedule? All tasks will be removed and any running processes Are you sure you want to delete this schedule? All tasks will be removed and any running processes
will be terminated. will be terminated.
</ConfirmationModal> </ConfirmationModal>
<Button css={tw`mr-4`} color={'red'} isSecondary onClick={() => setVisible(true)}> <Button css={tw`flex-1 sm:flex-none mr-4 border-transparent`} color={'red'} isSecondary onClick={() => setVisible(true)}>
Delete Delete
</Button> </Button>
</> </>

View file

@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { Schedule } from '@/api/server/schedules/getServerSchedules'; import { Schedule } from '@/api/server/schedules/getServerSchedules';
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal'; import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
import Button from '@/components/elements/Button'; import Button from '@/components/elements/Button';
import tw from 'twin.macro';
interface Props { interface Props {
schedule: Schedule; schedule: Schedule;
@ -18,7 +19,7 @@ export default ({ schedule }: Props) => {
onDismissed={() => setVisible(false)} onDismissed={() => setVisible(false)}
/> />
} }
<Button onClick={() => setVisible(true)}> <Button onClick={() => setVisible(true)} css={tw`flex-1`}>
New Task New Task
</Button> </Button>
</> </>

View file

@ -0,0 +1,35 @@
import React from 'react';
import tw from 'twin.macro';
import { Schedule } from '@/api/server/schedules/getServerSchedules';
interface Props {
cron: Schedule['cron'];
className?: string;
}
const ScheduleCronRow = ({ cron, className }: Props) => (
<div css={tw`flex`} className={className}>
<div css={tw`w-1/5 sm:w-auto text-center`}>
<p css={tw`font-medium`}>{cron.minute}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>Minute</p>
</div>
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
<p css={tw`font-medium`}>{cron.hour}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>Hour</p>
</div>
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
<p css={tw`font-medium`}>{cron.dayOfMonth}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Month)</p>
</div>
<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`w-1/5 sm:w-auto text-center ml-4`}>
<p css={tw`font-medium`}>{cron.dayOfWeek}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Week)</p>
</div>
</div>
);
export default ScheduleCronRow;

View file

@ -1,12 +1,10 @@
import React, { useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
import { Schedule } from '@/api/server/schedules/getServerSchedules'; import { Schedule } from '@/api/server/schedules/getServerSchedules';
import getServerSchedule from '@/api/server/schedules/getServerSchedule'; import getServerSchedule from '@/api/server/schedules/getServerSchedule';
import Spinner from '@/components/elements/Spinner'; import Spinner from '@/components/elements/Spinner';
import FlashMessageRender from '@/components/FlashMessageRender'; import FlashMessageRender from '@/components/FlashMessageRender';
import { httpErrorToHuman } from '@/api/http'; import { httpErrorToHuman } from '@/api/http';
import ScheduleRow from '@/components/server/schedules/ScheduleRow';
import ScheduleTaskRow from '@/components/server/schedules/ScheduleTaskRow';
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal'; import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
import NewTaskButton from '@/components/server/schedules/NewTaskButton'; import NewTaskButton from '@/components/server/schedules/NewTaskButton';
import DeleteScheduleButton from '@/components/server/schedules/DeleteScheduleButton'; import DeleteScheduleButton from '@/components/server/schedules/DeleteScheduleButton';
@ -16,7 +14,10 @@ import { ServerContext } from '@/state/server';
import PageContentBlock from '@/components/elements/PageContentBlock'; import PageContentBlock from '@/components/elements/PageContentBlock';
import tw from 'twin.macro'; import tw from 'twin.macro';
import Button from '@/components/elements/Button'; import Button from '@/components/elements/Button';
import GreyRowBox from '@/components/elements/GreyRowBox'; import ScheduleTaskRow from '@/components/server/schedules/ScheduleTaskRow';
import isEqual from 'react-fast-compare';
import { format } from 'date-fns';
import ScheduleCronRow from '@/components/server/schedules/ScheduleCronRow';
interface Params { interface Params {
id: string; id: string;
@ -26,6 +27,24 @@ interface State {
schedule?: Schedule; schedule?: Schedule;
} }
const CronBox = ({ title, value }: { title: string; value: string }) => (
<div css={tw`bg-neutral-700 rounded p-4`}>
<p css={tw`text-neutral-300 text-sm`}>{title}</p>
<p css={tw`text-2xl font-medium text-neutral-100`}>{value}</p>
</div>
);
const ActivePill = ({ active }: { active: boolean }) => (
<span
css={[
tw`rounded-full px-2 py-px text-xs ml-4 uppercase`,
active ? tw`bg-green-600 text-green-100` : tw`bg-red-600 text-red-100`,
]}
>
{active ? 'Active' : 'Inactive'}
</span>
);
export default ({ match, history, location: { state } }: RouteComponentProps<Params, Record<string, unknown>, State>) => { export default ({ match, history, location: { state } }: RouteComponentProps<Params, Record<string, unknown>, State>) => {
const id = ServerContext.useStoreState(state => state.server.data!.id); const id = ServerContext.useStoreState(state => state.server.data!.id);
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
@ -34,7 +53,8 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
const [ isLoading, setIsLoading ] = useState(true); const [ isLoading, setIsLoading ] = useState(true);
const [ showEditModal, setShowEditModal ] = useState(false); const [ showEditModal, setShowEditModal ] = useState(false);
const schedule = ServerContext.useStoreState(st => st.schedules.data.find(s => s.id === state.schedule?.id), [ match ]); // @ts-ignore
const schedule: Schedule | undefined = ServerContext.useStoreState(st => st.schedules.data.find(s => s.id === state.schedule?.id), isEqual);
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule); const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
useEffect(() => { useEffect(() => {
@ -53,6 +73,10 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
.then(() => setIsLoading(false)); .then(() => setIsLoading(false));
}, [ match ]); }, [ match ]);
const toggleEditModal = useCallback(() => {
setShowEditModal(s => !s);
}, []);
return ( return (
<PageContentBlock> <PageContentBlock>
<FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/> <FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/>
@ -60,52 +84,68 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
<Spinner size={'large'} centered/> <Spinner size={'large'} centered/>
: :
<> <>
<GreyRowBox css={tw`cursor-pointer mb-2 flex-wrap`}> <ScheduleCronRow cron={schedule.cron} css={tw`sm:hidden bg-neutral-700 rounded mb-4 p-3`}/>
<ScheduleRow schedule={schedule}/> <div css={tw`hidden sm:grid grid-cols-5 md:grid-cols-7 gap-4 mb-6`}>
</GreyRowBox> <CronBox title={'Minute'} value={schedule.cron.minute}/>
<EditScheduleModal <CronBox title={'Hour'} value={schedule.cron.hour}/>
visible={showEditModal} <CronBox title={'Day (Month)'} value={schedule.cron.dayOfMonth}/>
schedule={schedule} <CronBox title={'Month'} value={'*'}/>
onDismissed={() => setShowEditModal(false)} <CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/>
/> </div>
<div css={tw`flex items-center mt-8 mb-4`}> <div css={tw`rounded shadow`}>
<div css={tw`flex-1`}> <div css={tw`sm:flex items-center bg-neutral-900 p-3 sm:p-6 border-b-4 border-neutral-600 rounded-t`}>
<h2 css={tw`text-2xl`}>Configured Tasks</h2> <div css={tw`flex-1`}>
<h3 css={tw`flex items-center text-neutral-100 text-2xl`}>
{schedule.name}
{schedule.isProcessing ?
<span
css={tw`flex items-center rounded-full px-2 py-px text-xs ml-4 uppercase bg-neutral-600 text-white`}
>
<Spinner css={tw`w-3! h-3! mr-2`}/>
Processing
</span>
:
<ActivePill active={schedule.isActive}/>
}
</h3>
<p css={tw`mt-1 text-sm text-neutral-300`}>
Last run at:&nbsp;
{schedule.lastRunAt ? format(schedule.lastRunAt, 'MMM do \'at\' h:mma') : 'never'}
</p>
</div>
<div css={tw`flex sm:block mt-3 sm:mt-0`}>
<Can action={'schedule.update'}>
<Button
isSecondary
color={'grey'}
size={'small'}
css={tw`flex-1 mr-4 border-transparent`}
onClick={toggleEditModal}
>
Edit
</Button>
<NewTaskButton schedule={schedule}/>
</Can>
</div>
</div>
<div css={tw`bg-neutral-700 rounded-b`}>
{schedule.tasks.length > 0 ?
schedule.tasks.map(task => (
<ScheduleTaskRow key={`${schedule.id}_${task.id}`} task={task} schedule={schedule}/>
))
:
null
}
</div> </div>
</div> </div>
{schedule.tasks.length > 0 ? <EditScheduleModal visible={showEditModal} schedule={schedule} onDismissed={toggleEditModal}/>
<> <div css={tw`mt-6 flex sm:justify-end`}>
{
schedule.tasks
.sort((a, b) => a.sequenceId - b.sequenceId)
.map(task => (
<ScheduleTaskRow key={task.id} task={task} schedule={schedule}/>
))
}
{schedule.tasks.length > 1 &&
<p css={tw`text-xs text-neutral-400`}>
Task delays are relative to the previous task in the listing.
</p>
}
</>
:
<p css={tw`text-sm text-neutral-400`}>
There are no tasks configured for this schedule.
</p>
}
<div css={tw`mt-8 flex justify-end`}>
<Can action={'schedule.delete'}> <Can action={'schedule.delete'}>
<DeleteScheduleButton <DeleteScheduleButton
scheduleId={schedule.id} scheduleId={schedule.id}
onDeleted={() => history.push(`/server/${id}/schedules`)} onDeleted={() => history.push(`/server/${id}/schedules`)}
/> />
</Can> </Can>
<Can action={'schedule.update'}>
<Button css={tw`mr-4`} onClick={() => setShowEditModal(true)}>
Edit
</Button>
<NewTaskButton schedule={schedule}/>
</Can>
</div> </div>
</> </>
} }

View file

@ -4,6 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons'; import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons';
import { format } from 'date-fns'; import { format } from 'date-fns';
import tw from 'twin.macro'; import tw from 'twin.macro';
import ScheduleCronRow from '@/components/server/schedules/ScheduleCronRow';
export default ({ schedule }: { schedule: Schedule }) => ( export default ({ schedule }: { schedule: Schedule }) => (
<> <>
@ -27,36 +28,19 @@ export default ({ schedule }: { schedule: Schedule }) => (
{schedule.isActive ? 'Active' : 'Inactive'} {schedule.isActive ? 'Active' : 'Inactive'}
</p> </p>
</div> </div>
<div css={tw`flex items-center mx-auto sm:mx-8 w-full sm:w-auto mt-4 sm:mt-0`}> <ScheduleCronRow cron={schedule.cron} css={tw`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`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`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`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`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> <div>
<p <p
css={[ css={[
tw`py-1 px-3 rounded text-xs uppercase text-white hidden sm:block`, 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 && !schedule.isProcessing ? tw`bg-green-600` : tw`bg-neutral-400`,
]} ]}
> >
{schedule.isActive ? 'Active' : 'Inactive'} {schedule.isProcessing ?
'Processing'
:
schedule.isActive ? 'Active' : 'Inactive'
}
</p> </p>
</div> </div>
</> </>

View file

@ -1,7 +1,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Schedule, Task } from '@/api/server/schedules/getServerSchedules'; import { Schedule, Task } from '@/api/server/schedules/getServerSchedules';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCode, faFileArchive, faPencilAlt, faToggleOn, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { faClock, faCode, faFileArchive, faPencilAlt, faToggleOn, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import deleteScheduleTask from '@/api/server/schedules/deleteScheduleTask'; import deleteScheduleTask from '@/api/server/schedules/deleteScheduleTask';
import { httpErrorToHuman } from '@/api/http'; import { httpErrorToHuman } from '@/api/http';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
@ -11,6 +11,7 @@ import useFlash from '@/plugins/useFlash';
import { ServerContext } from '@/state/server'; import { ServerContext } from '@/state/server';
import tw from 'twin.macro'; import tw from 'twin.macro';
import ConfirmationModal from '@/components/elements/ConfirmationModal'; import ConfirmationModal from '@/components/elements/ConfirmationModal';
import Icon from '@/components/elements/Icon';
interface Props { interface Props {
schedule: Schedule; schedule: Schedule;
@ -56,7 +57,7 @@ export default ({ schedule, task }: Props) => {
const [ title, icon ] = getActionDetails(task.action); const [ title, icon ] = getActionDetails(task.action);
return ( return (
<div css={tw`flex flex-wrap items-center bg-neutral-700 border border-neutral-600 mb-2 px-6 py-4 rounded`}> <div css={tw`sm:flex items-center p-3 sm:p-6 border-b border-neutral-800`}>
<SpinnerOverlay visible={isLoading} fixed size={'large'}/> <SpinnerOverlay visible={isLoading} fixed size={'large'}/>
{isEditing && <TaskDetailsModal {isEditing && <TaskDetailsModal
schedule={schedule} schedule={schedule}
@ -73,8 +74,8 @@ 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 hidden md:block`}/> <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`}> <div css={tw`flex-none sm:flex-1 w-full sm:w-auto overflow-x-auto`}>
<p css={tw`md:ml-6 text-neutral-300 uppercase text-xs`}> <p css={tw`md:ml-6 text-neutral-200 uppercase text-sm`}>
{title} {title}
</p> </p>
{task.payload && {task.payload &&
@ -87,36 +88,36 @@ export default ({ schedule, task }: Props) => {
</div> </div>
} }
</div> </div>
{task.sequenceId > 1 && <div css={tw`mt-3 sm:mt-0 flex items-center w-full sm:w-auto`}>
<div css={tw`mr-6`}> {task.sequenceId > 1 && task.timeOffset > 0 &&
<p css={tw`text-center mb-1`}> <div css={tw`mr-6`}>
{task.timeOffset}s <div css={tw`flex items-center px-2 py-1 bg-neutral-500 text-sm rounded-full`}>
</p> <Icon icon={faClock} css={tw`w-3 h-3 mr-2`}/>
<p css={tw`text-neutral-300 uppercase text-2xs`}> {task.timeOffset}s later
Delay Run By </div>
</p> </div>
}
<Can action={'schedule.update'}>
<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 ml-auto sm:ml-0`}
onClick={() => setIsEditing(true)}
>
<FontAwesomeIcon icon={faPencilAlt}/>
</button>
</Can>
<Can action={'schedule.update'}>
<button
type={'button'}
aria-label={'Delete scheduled task'}
css={tw`block text-sm p-2 text-neutral-500 hover:text-red-600 transition-colors duration-150`}
onClick={() => setVisible(true)}
>
<FontAwesomeIcon icon={faTrashAlt}/>
</button>
</Can>
</div> </div>
}
<Can action={'schedule.update'}>
<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 ml-auto sm:ml-0`}
onClick={() => setIsEditing(true)}
>
<FontAwesomeIcon icon={faPencilAlt}/>
</button>
</Can>
<Can action={'schedule.update'}>
<button
type={'button'}
aria-label={'Delete scheduled task'}
css={tw`block text-sm p-2 text-neutral-500 hover:text-red-600 transition-colors duration-150`}
onClick={() => setVisible(true)}
>
<FontAwesomeIcon icon={faTrashAlt}/>
</button>
</Can>
</div> </div>
); );
}; };

View file

@ -3,5 +3,6 @@
]) ])
@section('container') @section('container')
<div id="modal-portal"></div>
<div id="app"></div> <div id="app"></div>
@endsection @endsection

View file

@ -888,30 +888,31 @@
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@fortawesome/fontawesome-common-types@^0.2.19": "@fortawesome/fontawesome-common-types@^0.2.32":
version "0.2.19" version "0.2.32"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.19.tgz#754a0f85e1290858152e1c05700ab502b11197f1" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz#3436795d5684f22742989bfa08f46f50f516f259"
integrity sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w==
"@fortawesome/fontawesome-svg-core@1.2.19": "@fortawesome/fontawesome-svg-core@^1.2.32":
version "1.2.19" version "1.2.32"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.19.tgz#0eca1ce9285c3d99e6e340633ee8f615f9d1a2e0" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz#da092bfc7266aa274be8604de610d7115f9ba6cf"
integrity sha512-D4ICXg9oU08eF9o7Or392gPpjmwwgJu8ecCFusthbID95CLVXOgIyd4mOKD9Nud5Ckz+Ty59pqkNtThDKR0erA== integrity sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ==
dependencies: dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.19" "@fortawesome/fontawesome-common-types" "^0.2.32"
"@fortawesome/free-solid-svg-icons@^5.9.0": "@fortawesome/free-solid-svg-icons@^5.15.1":
version "5.9.0" version "5.15.1"
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.9.0.tgz#1c73e7bac17417d23f934d83f7fff5b100a7fda9" resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.1.tgz#e1432676ddd43108b41197fee9f86d910ad458ef"
integrity sha512-EFMuKtzRMNbvjab/SvJBaOOpaqJfdSap/Nl6hst7CgrJxwfORR1drdTV6q1Ib/JVzq4xObdTDcT6sqTaXMqfdg==
dependencies: dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.19" "@fortawesome/fontawesome-common-types" "^0.2.32"
"@fortawesome/react-fontawesome@0.1.4": "@fortawesome/react-fontawesome@^0.1.11":
version "0.1.4" version "0.1.11"
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.4.tgz#18d61d9b583ca289a61aa7dccc05bd164d6bc9ad" resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.11.tgz#c1a95a2bdb6a18fa97b355a563832e248bf6ef4a"
integrity sha512-GwmxQ+TK7PEdfSwvxtGnMCqrfEm0/HbRHArbUudsYiy9KzVCwndxa2KMcfyTQ8El0vROrq8gOOff09RF1oQe8g== integrity sha512-sClfojasRifQKI0OPqTy8Ln8iIhnxR/Pv/hukBhWnBz9kQRmqi6JSH3nghlhAY7SUeIIM7B5/D2G8WjX0iepVg==
dependencies: dependencies:
humps "^2.0.1" prop-types "^15.7.2"
prop-types "^15.5.10"
"@fullhuman/postcss-purgecss@^2.1.2": "@fullhuman/postcss-purgecss@^2.1.2":
version "2.3.0" version "2.3.0"
@ -3767,11 +3768,6 @@ https-browserify@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
humps@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.1.tgz#dd02ea6081bd0568dc5d073184463957ba9ef9aa"
integrity sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao=
i18next-chained-backend@^2.0.0: i18next-chained-backend@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/i18next-chained-backend/-/i18next-chained-backend-2.0.0.tgz#faf2e8b5f081a01e74fbec1fe580c184bc64e25b" resolved "https://registry.yarnpkg.com/i18next-chained-backend/-/i18next-chained-backend-2.0.0.tgz#faf2e8b5f081a01e74fbec1fe580c184bc64e25b"
@ -5416,7 +5412,7 @@ promise-inflight@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: prop-types@^15.5.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==