forked from pterodactyl/panel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScheduleTaskRow.tsx
More file actions
143 lines (137 loc) · 5.88 KB
/
ScheduleTaskRow.tsx
File metadata and controls
143 lines (137 loc) · 5.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import React, { useState } from 'react';
import { Schedule, Task } from '@/api/server/schedules/getServerSchedules';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faArrowCircleDown,
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';
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
import Can from '@/components/elements/Can';
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;
task: Task;
}
const getActionDetails = (action: string): [string, any] => {
switch (action) {
case 'command':
return ['Send Command', faCode];
case 'power':
return ['Send Power Action', faToggleOn];
case 'backup':
return ['Create Backup', faFileArchive];
default:
return ['Unknown Action', faCode];
}
};
export default ({ schedule, task }: Props) => {
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
const { clearFlashes, addError } = useFlash();
const [visible, setVisible] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const appendSchedule = ServerContext.useStoreActions((actions) => actions.schedules.appendSchedule);
const onConfirmDeletion = () => {
setIsLoading(true);
clearFlashes('schedules');
deleteScheduleTask(uuid, schedule.id, task.id)
.then(() =>
appendSchedule({
...schedule,
tasks: schedule.tasks.filter((t) => t.id !== task.id),
})
)
.catch((error) => {
console.error(error);
setIsLoading(false);
addError({ message: httpErrorToHuman(error), key: 'schedules' });
});
};
const [title, icon] = getActionDetails(task.action);
return (
<div css={tw`sm:flex items-center p-3 sm:p-6 border-b border-neutral-800`}>
<SpinnerOverlay visible={isLoading} fixed size={'large'} />
<TaskDetailsModal
schedule={schedule}
task={task}
visible={isEditing}
onModalDismissed={() => setIsEditing(false)}
/>
<ConfirmationModal
title={'Confirm task deletion'}
buttonText={'Delete Task'}
onConfirmed={onConfirmDeletion}
visible={visible}
onModalDismissed={() => setVisible(false)}
>
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 w-full sm:w-auto overflow-x-auto`}>
<p css={tw`md:ml-6 text-neutral-200 uppercase text-sm`}>{title}</p>
{task.payload && (
<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 inline-block whitespace-pre-wrap break-all`}
>
{task.payload}
</div>
</div>
)}
</div>
<div css={tw`mt-3 sm:mt-0 flex items-center w-full sm:w-auto`}>
{task.continueOnFailure && (
<div css={tw`mr-6`}>
<div css={tw`flex items-center px-2 py-1 bg-yellow-500 text-yellow-800 text-sm rounded-full`}>
<Icon icon={faArrowCircleDown} css={tw`w-3 h-3 mr-2`} />
Continues on Failure
</div>
</div>
)}
{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>
</div>
);
};