Fix handling of backup tasks; closes #2067

This commit is contained in:
Dane Everitt 2020-06-18 21:00:04 -07:00
parent 364b645b81
commit 693b9eab0c
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
5 changed files with 35 additions and 11 deletions

View file

@ -58,7 +58,7 @@ class ScheduleTaskController extends ClientApiController
'schedule_id' => $schedule->id, 'schedule_id' => $schedule->id,
'sequence_id' => ($lastTask->sequence_id ?? 0) + 1, 'sequence_id' => ($lastTask->sequence_id ?? 0) + 1,
'action' => $request->input('action'), 'action' => $request->input('action'),
'payload' => $request->input('payload'), 'payload' => $request->input('payload') ?? '',
'time_offset' => $request->input('time_offset'), 'time_offset' => $request->input('time_offset'),
]); ]);
@ -87,7 +87,7 @@ class ScheduleTaskController extends ClientApiController
$this->repository->update($task->id, [ $this->repository->update($task->id, [
'action' => $request->input('action'), 'action' => $request->input('action'),
'payload' => $request->input('payload'), 'payload' => $request->input('payload') ?? '',
'time_offset' => $request->input('time_offset'), 'time_offset' => $request->input('time_offset'),
]); ]);

View file

@ -25,7 +25,7 @@ class StoreTaskRequest extends ViewScheduleRequest
{ {
return [ return [
'action' => 'required|in:command,power,backup', 'action' => 'required|in:command,power,backup',
'payload' => 'required_unless:action,backup|string', 'payload' => 'required_unless:action,backup|string|nullable',
'time_offset' => 'required|numeric|min:0|max:900', 'time_offset' => 'required|numeric|min:0|max:900',
'sequence_id' => 'sometimes|required|numeric|min:1', 'sequence_id' => 'sometimes|required|numeric|min:1',
]; ];

View file

@ -90,7 +90,7 @@ class Task extends Model
'schedule_id' => 'required|numeric|exists:schedules,id', 'schedule_id' => 'required|numeric|exists:schedules,id',
'sequence_id' => 'required|numeric|min:1', 'sequence_id' => 'required|numeric|min:1',
'action' => 'required|string', 'action' => 'required|string',
'payload' => 'required|string', 'payload' => 'required_unless:action,backup|string',
'time_offset' => 'required|numeric|between:0,900', 'time_offset' => 'required|numeric|between:0,900',
'is_queued' => 'boolean', 'is_queued' => 'boolean',
]; ];

View file

@ -14,12 +14,26 @@ import Can from '@/components/elements/Can';
import useServer from '@/plugins/useServer'; import useServer from '@/plugins/useServer';
import useFlash from '@/plugins/useFlash'; import useFlash from '@/plugins/useFlash';
import { ServerContext } from '@/state/server'; import { ServerContext } from '@/state/server';
import { faFileArchive } from '@fortawesome/free-solid-svg-icons/faFileArchive';
interface Props { interface Props {
schedule: Schedule; schedule: Schedule;
task: Task; 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) => { export default ({ schedule, task }: Props) => {
const { uuid } = useServer(); const { uuid } = useServer();
const { clearFlashes, addError } = useFlash(); const { clearFlashes, addError } = useFlash();
@ -43,6 +57,8 @@ export default ({ schedule, task }: Props) => {
}); });
}; };
const [ title, icon ] = getActionDetails(task.action);
return ( return (
<div className={'flex items-center bg-neutral-700 border border-neutral-600 mb-2 px-6 py-4 rounded'}> <div className={'flex items-center bg-neutral-700 border border-neutral-600 mb-2 px-6 py-4 rounded'}>
<SpinnerOverlay visible={isLoading} fixed={true} size={'large'}/> <SpinnerOverlay visible={isLoading} fixed={true} size={'large'}/>
@ -56,14 +72,19 @@ export default ({ schedule, task }: Props) => {
onDismissed={() => setVisible(false)} onDismissed={() => setVisible(false)}
onConfirmed={() => onConfirmDeletion()} onConfirmed={() => onConfirmDeletion()}
/> />
<FontAwesomeIcon icon={task.action === 'command' ? faCode : faToggleOn} className={'text-lg text-white'}/> <FontAwesomeIcon icon={icon} className={'text-lg text-white'}/>
<div className={'flex-1'}> <div className={'flex-1'}>
<p className={'ml-6 text-neutral-300 mb-2 uppercase text-xs'}> <p className={'ml-6 text-neutral-300 uppercase text-xs'}>
{task.action === 'command' ? 'Send command' : 'Send power action'} {title}
</p> </p>
<code className={'ml-6 font-mono bg-neutral-800 rounded py-1 px-2 text-sm'}> {task.payload &&
{task.payload} <div className={'ml-6 mt-2'}>
</code> {task.action === 'backup' && <p className={'text-xs uppercase text-neutral-400 mb-1'}>Ignoring files & folders:</p>}
<div className={'font-mono bg-neutral-800 rounded py-1 px-2 text-sm w-auto whitespace-pre inline-block'}>
{task.payload}
</div>
</div>
}
</div> </div>
{task.sequenceId > 1 && {task.sequenceId > 1 &&
<div className={'mr-6'}> <div className={'mr-6'}>

View file

@ -71,7 +71,10 @@ const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => {
: :
<div> <div>
<label className={'input-dark-label'}>Ignored Files</label> <label className={'input-dark-label'}>Ignored Files</label>
<FormikFieldWrapper name={'payload'}> <FormikFieldWrapper
name={'payload'}
description={'Optional. Include the files and folders to be excluded in this backup. By default, the contents of your .pteroignore file will be used.'}
>
<FormikField as={'textarea'} name={'payload'} className={'input-dark h-32'}/> <FormikField as={'textarea'} name={'payload'} className={'input-dark h-32'}/>
</FormikFieldWrapper> </FormikFieldWrapper>
</div> </div>