forked from Alex/Pterodactyl-Panel
Update schedule view UI
This commit is contained in:
parent
33a43de723
commit
f33d0b1d72
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "pterodactyl-panel",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.19",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
||||
"@fortawesome/react-fontawesome": "0.1.4",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.1",
|
||||
"@fortawesome/react-fontawesome": "^0.1.11",
|
||||
"axios": "^0.19.2",
|
||||
"chart.js": "^2.8.0",
|
||||
"codemirror": "^5.57.0",
|
||||
@ -23,9 +23,9 @@
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "npm:@hot-loader/react-dom",
|
||||
"react-fast-compare": "^3.2.0",
|
||||
"react-ga": "^3.1.2",
|
||||
"react-google-recaptcha": "^2.0.1",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-ga": "^3.1.2",
|
||||
"react-hot-loader": "^4.12.21",
|
||||
"react-i18next": "^11.2.1",
|
||||
"react-redux": "^7.1.0",
|
||||
|
@ -57,8 +57,8 @@ const ButtonStyle = styled.button<Omit<Props, 'isLoading'>>`
|
||||
`};
|
||||
`};
|
||||
|
||||
${props => props.size === 'xsmall' && tw`p-2 text-xs`};
|
||||
${props => (!props.size || props.size === 'small') && tw`p-3`};
|
||||
${props => props.size === 'xsmall' && tw`px-2 py-1 text-xs`};
|
||||
${props => (!props.size || props.size === 'small') && tw`px-4 py-2`};
|
||||
${props => props.size === 'large' && tw`p-4 text-sm`};
|
||||
${props => props.size === 'xlarge' && tw`p-4 w-full`};
|
||||
|
||||
|
31
resources/scripts/components/elements/Icon.tsx
Normal file
31
resources/scripts/components/elements/Icon.tsx
Normal 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;
|
@ -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 tw from 'twin.macro';
|
||||
import styled, { css } from 'styled-components/macro';
|
||||
import { breakpoint } from '@/theme';
|
||||
import Fade from '@/components/elements/Fade';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
export interface RequiredModalProps {
|
||||
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;
|
||||
|
@ -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
|
||||
will be terminated.
|
||||
</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
|
||||
</Button>
|
||||
</>
|
||||
|
@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
||||
import { Schedule } from '@/api/server/schedules/getServerSchedules';
|
||||
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
|
||||
import Button from '@/components/elements/Button';
|
||||
import tw from 'twin.macro';
|
||||
|
||||
interface Props {
|
||||
schedule: Schedule;
|
||||
@ -18,7 +19,7 @@ export default ({ schedule }: Props) => {
|
||||
onDismissed={() => setVisible(false)}
|
||||
/>
|
||||
}
|
||||
<Button onClick={() => setVisible(true)}>
|
||||
<Button onClick={() => setVisible(true)} css={tw`flex-1`}>
|
||||
New Task
|
||||
</Button>
|
||||
</>
|
||||
|
@ -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;
|
@ -1,12 +1,10 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { Schedule } from '@/api/server/schedules/getServerSchedules';
|
||||
import getServerSchedule from '@/api/server/schedules/getServerSchedule';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
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 NewTaskButton from '@/components/server/schedules/NewTaskButton';
|
||||
import DeleteScheduleButton from '@/components/server/schedules/DeleteScheduleButton';
|
||||
@ -16,7 +14,10 @@ import { ServerContext } from '@/state/server';
|
||||
import PageContentBlock from '@/components/elements/PageContentBlock';
|
||||
import tw from 'twin.macro';
|
||||
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 {
|
||||
id: string;
|
||||
@ -26,6 +27,24 @@ interface State {
|
||||
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>) => {
|
||||
const id = ServerContext.useStoreState(state => state.server.data!.id);
|
||||
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 [ 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);
|
||||
|
||||
useEffect(() => {
|
||||
@ -53,6 +73,10 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
|
||||
.then(() => setIsLoading(false));
|
||||
}, [ match ]);
|
||||
|
||||
const toggleEditModal = useCallback(() => {
|
||||
setShowEditModal(s => !s);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContentBlock>
|
||||
<FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/>
|
||||
@ -60,52 +84,68 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
|
||||
<Spinner size={'large'} centered/>
|
||||
:
|
||||
<>
|
||||
<GreyRowBox css={tw`cursor-pointer mb-2 flex-wrap`}>
|
||||
<ScheduleRow schedule={schedule}/>
|
||||
</GreyRowBox>
|
||||
<EditScheduleModal
|
||||
visible={showEditModal}
|
||||
schedule={schedule}
|
||||
onDismissed={() => setShowEditModal(false)}
|
||||
/>
|
||||
<div css={tw`flex items-center mt-8 mb-4`}>
|
||||
<div css={tw`flex-1`}>
|
||||
<h2 css={tw`text-2xl`}>Configured Tasks</h2>
|
||||
<ScheduleCronRow cron={schedule.cron} css={tw`sm:hidden bg-neutral-700 rounded mb-4 p-3`}/>
|
||||
<div css={tw`hidden sm:grid grid-cols-5 md:grid-cols-7 gap-4 mb-6`}>
|
||||
<CronBox title={'Minute'} value={schedule.cron.minute}/>
|
||||
<CronBox title={'Hour'} value={schedule.cron.hour}/>
|
||||
<CronBox title={'Day (Month)'} value={schedule.cron.dayOfMonth}/>
|
||||
<CronBox title={'Month'} value={'*'}/>
|
||||
<CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/>
|
||||
</div>
|
||||
<div css={tw`rounded shadow`}>
|
||||
<div css={tw`sm:flex items-center bg-neutral-900 p-3 sm:p-6 border-b-4 border-neutral-600 rounded-t`}>
|
||||
<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:
|
||||
{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>
|
||||
{schedule.tasks.length > 0 ?
|
||||
<>
|
||||
{
|
||||
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`}>
|
||||
<EditScheduleModal visible={showEditModal} schedule={schedule} onDismissed={toggleEditModal}/>
|
||||
<div css={tw`mt-6 flex sm:justify-end`}>
|
||||
<Can action={'schedule.delete'}>
|
||||
<DeleteScheduleButton
|
||||
scheduleId={schedule.id}
|
||||
onDeleted={() => history.push(`/server/${id}/schedules`)}
|
||||
/>
|
||||
</Can>
|
||||
<Can action={'schedule.update'}>
|
||||
<Button css={tw`mr-4`} onClick={() => setShowEditModal(true)}>
|
||||
Edit
|
||||
</Button>
|
||||
<NewTaskButton schedule={schedule}/>
|
||||
</Can>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { format } from 'date-fns';
|
||||
import tw from 'twin.macro';
|
||||
import ScheduleCronRow from '@/components/server/schedules/ScheduleCronRow';
|
||||
|
||||
export default ({ schedule }: { schedule: Schedule }) => (
|
||||
<>
|
||||
@ -27,36 +28,19 @@ export default ({ schedule }: { schedule: Schedule }) => (
|
||||
{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`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>
|
||||
<ScheduleCronRow cron={schedule.cron} css={tw`mx-auto sm:mx-8 w-full sm:w-auto mt-4 sm:mt-0`}/>
|
||||
<div>
|
||||
<p
|
||||
css={[
|
||||
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>
|
||||
</div>
|
||||
</>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Schedule, Task } from '@/api/server/schedules/getServerSchedules';
|
||||
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 { httpErrorToHuman } from '@/api/http';
|
||||
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
||||
@ -11,6 +11,7 @@ import useFlash from '@/plugins/useFlash';
|
||||
import { ServerContext } from '@/state/server';
|
||||
import tw from 'twin.macro';
|
||||
import ConfirmationModal from '@/components/elements/ConfirmationModal';
|
||||
import Icon from '@/components/elements/Icon';
|
||||
|
||||
interface Props {
|
||||
schedule: Schedule;
|
||||
@ -56,7 +57,7 @@ export default ({ schedule, task }: Props) => {
|
||||
const [ title, icon ] = getActionDetails(task.action);
|
||||
|
||||
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'}/>
|
||||
{isEditing && <TaskDetailsModal
|
||||
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.
|
||||
</ConfirmationModal>
|
||||
<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`}>
|
||||
<div css={tw`flex-none sm:flex-1 w-full sm:w-auto overflow-x-auto`}>
|
||||
<p css={tw`md:ml-6 text-neutral-200 uppercase text-sm`}>
|
||||
{title}
|
||||
</p>
|
||||
{task.payload &&
|
||||
@ -87,36 +88,36 @@ export default ({ schedule, task }: Props) => {
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{task.sequenceId > 1 &&
|
||||
<div css={tw`mr-6`}>
|
||||
<p css={tw`text-center mb-1`}>
|
||||
{task.timeOffset}s
|
||||
</p>
|
||||
<p css={tw`text-neutral-300 uppercase text-2xs`}>
|
||||
Delay Run By
|
||||
</p>
|
||||
<div css={tw`mt-3 sm:mt-0 flex items-center w-full sm:w-auto`}>
|
||||
{task.sequenceId > 1 && task.timeOffset > 0 &&
|
||||
<div css={tw`mr-6`}>
|
||||
<div css={tw`flex items-center px-2 py-1 bg-neutral-500 text-sm rounded-full`}>
|
||||
<Icon icon={faClock} css={tw`w-3 h-3 mr-2`}/>
|
||||
{task.timeOffset}s later
|
||||
</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>
|
||||
}
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
@ -3,5 +3,6 @@
|
||||
])
|
||||
|
||||
@section('container')
|
||||
<div id="modal-portal"></div>
|
||||
<div id="app"></div>
|
||||
@endsection
|
||||
|
44
yarn.lock
44
yarn.lock
@ -888,30 +888,31 @@
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@fortawesome/fontawesome-common-types@^0.2.19":
|
||||
version "0.2.19"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.19.tgz#754a0f85e1290858152e1c05700ab502b11197f1"
|
||||
"@fortawesome/fontawesome-common-types@^0.2.32":
|
||||
version "0.2.32"
|
||||
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":
|
||||
version "1.2.19"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.19.tgz#0eca1ce9285c3d99e6e340633ee8f615f9d1a2e0"
|
||||
integrity sha512-D4ICXg9oU08eF9o7Or392gPpjmwwgJu8ecCFusthbID95CLVXOgIyd4mOKD9Nud5Ckz+Ty59pqkNtThDKR0erA==
|
||||
"@fortawesome/fontawesome-svg-core@^1.2.32":
|
||||
version "1.2.32"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz#da092bfc7266aa274be8604de610d7115f9ba6cf"
|
||||
integrity sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.19"
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.32"
|
||||
|
||||
"@fortawesome/free-solid-svg-icons@^5.9.0":
|
||||
version "5.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.9.0.tgz#1c73e7bac17417d23f934d83f7fff5b100a7fda9"
|
||||
"@fortawesome/free-solid-svg-icons@^5.15.1":
|
||||
version "5.15.1"
|
||||
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:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.19"
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.32"
|
||||
|
||||
"@fortawesome/react-fontawesome@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.4.tgz#18d61d9b583ca289a61aa7dccc05bd164d6bc9ad"
|
||||
integrity sha512-GwmxQ+TK7PEdfSwvxtGnMCqrfEm0/HbRHArbUudsYiy9KzVCwndxa2KMcfyTQ8El0vROrq8gOOff09RF1oQe8g==
|
||||
"@fortawesome/react-fontawesome@^0.1.11":
|
||||
version "0.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.11.tgz#c1a95a2bdb6a18fa97b355a563832e248bf6ef4a"
|
||||
integrity sha512-sClfojasRifQKI0OPqTy8Ln8iIhnxR/Pv/hukBhWnBz9kQRmqi6JSH3nghlhAY7SUeIIM7B5/D2G8WjX0iepVg==
|
||||
dependencies:
|
||||
humps "^2.0.1"
|
||||
prop-types "^15.5.10"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@fullhuman/postcss-purgecss@^2.1.2":
|
||||
version "2.3.0"
|
||||
@ -3767,11 +3768,6 @@ https-browserify@^1.0.0:
|
||||
version "1.0.0"
|
||||
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:
|
||||
version "2.0.0"
|
||||
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"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
|
Loading…
Reference in New Issue
Block a user