2020-03-19 05:28:32 +00:00
import React , { useEffect } from 'react' ;
import Modal from '@/components/elements/Modal' ;
2020-04-10 17:46:00 +00:00
import { Schedule , Task } from '@/api/server/schedules/getServerSchedules' ;
2020-03-22 21:11:26 +00:00
import { Field as FormikField , Form , Formik , FormikHelpers , useFormikContext } from 'formik' ;
2020-03-19 05:28:32 +00:00
import { ServerContext } from '@/state/server' ;
import createOrUpdateScheduleTask from '@/api/server/schedules/createOrUpdateScheduleTask' ;
import { httpErrorToHuman } from '@/api/http' ;
import Field from '@/components/elements/Field' ;
import FlashMessageRender from '@/components/FlashMessageRender' ;
2020-03-19 05:36:19 +00:00
import { number , object , string } from 'yup' ;
2020-04-10 17:46:00 +00:00
import useFlash from '@/plugins/useFlash' ;
import useServer from '@/plugins/useServer' ;
2020-04-19 19:15:10 +00:00
import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper' ;
2020-03-19 05:28:32 +00:00
interface Props {
2020-04-10 17:46:00 +00:00
schedule : Schedule ;
2020-03-19 05:28:32 +00:00
// If a task is provided we can assume we're editing it. If not provided,
// we are creating a new one.
task? : Task ;
2020-04-10 17:46:00 +00:00
onDismissed : ( ) = > void ;
2020-03-19 05:28:32 +00:00
}
interface Values {
action : string ;
payload : string ;
timeOffset : string ;
}
2020-03-22 21:11:26 +00:00
const TaskDetailsForm = ( { isEditingTask } : { isEditingTask : boolean } ) = > {
const { values : { action } , setFieldValue , setFieldTouched } = useFormikContext < Values > ( ) ;
useEffect ( ( ) = > {
2020-04-19 19:15:10 +00:00
setFieldValue ( 'payload' , action === 'power' ? 'start' : '' ) ;
setFieldTouched ( 'payload' , false ) ;
2020-04-10 17:46:00 +00:00
} , [ action ] ) ;
2020-03-22 21:11:26 +00:00
return (
< Form className = { 'm-0' } >
2020-04-20 02:43:41 +00:00
< h3 className = { 'mb-6' } > { isEditingTask ? 'Edit Task' : 'Create Task' } < / h3 >
2020-03-22 21:11:26 +00:00
< div className = { 'flex' } >
2020-04-20 02:43:41 +00:00
< div className = { 'mr-2 w-1/3' } >
2020-03-22 21:11:26 +00:00
< label className = { 'input-dark-label' } > Action < / label >
2020-04-20 02:43:41 +00:00
< FormikFieldWrapper name = { 'action' } >
< FormikField as = { 'select' } name = { 'action' } className = { 'input-dark' } >
< option value = { 'command' } > Send command < / option >
< option value = { 'power' } > Send power action < / option >
< option value = { 'backup' } > Create backup < / option >
< / FormikField >
< / FormikFieldWrapper >
2020-03-22 21:11:26 +00:00
< / div >
< div className = { 'flex-1' } >
{ action === 'command' ?
< Field
name = { 'payload' }
label = { 'Payload' }
description = { 'The command to send to the server when this task executes.' }
/ >
:
2020-04-20 02:43:41 +00:00
action === 'power' ?
< div >
< label className = { 'input-dark-label' } > Payload < / label >
< FormikFieldWrapper name = { 'payload' } >
< FormikField as = { 'select' } name = { 'payload' } className = { 'input-dark' } >
< option value = { 'start' } > Start the server < / option >
< option value = { 'restart' } > Restart the server < / option >
< option value = { 'stop' } > Stop the server < / option >
< option value = { 'kill' } > Terminate the server < / option >
< / FormikField >
< / FormikFieldWrapper >
< / div >
:
< div >
< label className = { 'input-dark-label' } > Ignored Files < / label >
2020-06-19 04:00:04 +00:00
< 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.' }
>
2020-04-20 02:43:41 +00:00
< FormikField as = { 'textarea' } name = { 'payload' } className = { 'input-dark h-32' } / >
< / FormikFieldWrapper >
< / div >
2020-03-22 21:11:26 +00:00
}
< / div >
< / div >
< div className = { 'mt-6' } >
< Field
name = { 'timeOffset' }
label = { 'Time offset (in seconds)' }
description = { 'The amount of time to wait after the previous task executes before running this one. If this is the first task on a schedule this will not be applied.' }
/ >
< / div >
< div className = { 'flex justify-end mt-6' } >
< button type = { 'submit' } className = { 'btn btn-primary btn-sm' } >
{ isEditingTask ? 'Save Changes' : 'Create Task' }
< / button >
< / div >
< / Form >
) ;
} ;
2020-04-10 17:46:00 +00:00
export default ( { task , schedule , onDismissed } : Props ) = > {
const { uuid } = useServer ( ) ;
const { clearFlashes , addError } = useFlash ( ) ;
const appendSchedule = ServerContext . useStoreActions ( actions = > actions . schedules . appendSchedule ) ;
2020-03-19 05:28:32 +00:00
useEffect ( ( ) = > {
clearFlashes ( 'schedule:task' ) ;
} , [ ] ) ;
const submit = ( values : Values , { setSubmitting } : FormikHelpers < Values > ) = > {
clearFlashes ( 'schedule:task' ) ;
2020-04-10 17:46:00 +00:00
createOrUpdateScheduleTask ( uuid , schedule . id , task ? . id , values )
. then ( task = > {
let tasks = schedule . tasks . map ( t = > t . id === task . id ? task : t ) ;
if ( ! schedule . tasks . find ( t = > t . id === task . id ) ) {
tasks = [ . . . tasks , task ] ;
}
appendSchedule ( { . . . schedule , tasks } ) ;
onDismissed ( ) ;
} )
2020-03-19 05:28:32 +00:00
. catch ( error = > {
console . error ( error ) ;
setSubmitting ( false ) ;
addError ( { message : httpErrorToHuman ( error ) , key : 'schedule:task' } ) ;
} ) ;
} ;
return (
< Formik
onSubmit = { submit }
initialValues = { {
action : task?.action || 'command' ,
payload : task?.payload || '' ,
timeOffset : task?.timeOffset.toString ( ) || '0' ,
} }
2020-03-19 05:36:19 +00:00
validationSchema = { object ( ) . shape ( {
2020-04-20 02:43:41 +00:00
action : string ( ) . required ( ) . oneOf ( [ 'command' , 'power' , 'backup' ] ) ,
payload : string ( ) . when ( 'action' , {
is : v = > v !== 'backup' ,
then : string ( ) . required ( 'A task payload must be provided.' ) ,
otherwise : string ( ) ,
} ) ,
2020-03-19 05:36:19 +00:00
timeOffset : number ( ) . typeError ( 'The time offset must be a valid number between 0 and 900.' )
. required ( 'A time offset value must be provided.' )
. min ( 0 , 'The time offset must be at least 0 seconds.' )
. max ( 900 , 'The time offset must be less than 900 seconds.' ) ,
} ) }
2020-03-19 05:28:32 +00:00
>
2020-03-22 21:11:26 +00:00
{ ( { isSubmitting } ) = > (
2020-03-19 05:28:32 +00:00
< Modal
visible = { true }
appear = { true }
onDismissed = { ( ) = > onDismissed ( ) }
showSpinnerOverlay = { isSubmitting }
>
< FlashMessageRender byKey = { 'schedule:task' } className = { 'mb-4' } / >
2020-03-22 21:11:26 +00:00
< TaskDetailsForm isEditingTask = { typeof task !== 'undefined' } / >
2020-03-19 05:28:32 +00:00
< / Modal >
) }
< / Formik >
) ;
} ;