diff --git a/resources/scripts/api/server/schedules/createOrUpdateScheduleTask.ts b/resources/scripts/api/server/schedules/createOrUpdateScheduleTask.ts index c0d7fbbe7..c2bfc807b 100644 --- a/resources/scripts/api/server/schedules/createOrUpdateScheduleTask.ts +++ b/resources/scripts/api/server/schedules/createOrUpdateScheduleTask.ts @@ -5,15 +5,16 @@ interface Data { action: string; payload: string; timeOffset: string | number; + continueOnFailure: boolean; } -export default (uuid: string, schedule: number, task: number | undefined, { timeOffset, ...data }: Data): Promise => { - return new Promise((resolve, reject) => { - http.post(`/api/client/servers/${uuid}/schedules/${schedule}/tasks${task ? `/${task}` : ''}`, { - ...data, - time_offset: timeOffset, - }) - .then(({ data }) => resolve(rawDataToServerTask(data.attributes))) - .catch(reject); +export default async (uuid: string, schedule: number, task: number | undefined, data: Data): Promise => { + const { data: response } = await http.post(`/api/client/servers/${uuid}/schedules/${schedule}/tasks${task ? `/${task}` : ''}`, { + action: data.action, + payload: data.payload, + continue_on_failure: data.continueOnFailure, + time_offset: data.timeOffset, }); + + return rawDataToServerTask(response.attributes); }; diff --git a/resources/scripts/components/server/schedules/EditScheduleModal.tsx b/resources/scripts/components/server/schedules/EditScheduleModal.tsx index 3db483244..e00cef04a 100644 --- a/resources/scripts/components/server/schedules/EditScheduleModal.tsx +++ b/resources/scripts/components/server/schedules/EditScheduleModal.tsx @@ -104,15 +104,15 @@ const EditScheduleModal = ({ schedule }: Props) => {

diff --git a/resources/scripts/components/server/schedules/NewTaskButton.tsx b/resources/scripts/components/server/schedules/NewTaskButton.tsx index 9234f5b42..2ac7b276c 100644 --- a/resources/scripts/components/server/schedules/NewTaskButton.tsx +++ b/resources/scripts/components/server/schedules/NewTaskButton.tsx @@ -13,12 +13,7 @@ export default ({ schedule }: Props) => { return ( <> - {visible && - setVisible(false)} - /> - } + setVisible(false)}/> diff --git a/resources/scripts/components/server/schedules/ScheduleContainer.tsx b/resources/scripts/components/server/schedules/ScheduleContainer.tsx index ddcd0a865..85e6db20d 100644 --- a/resources/scripts/components/server/schedules/ScheduleContainer.tsx +++ b/resources/scripts/components/server/schedules/ScheduleContainer.tsx @@ -67,7 +67,7 @@ export default () => { }
- {visible && setVisible(false)}/>} + setVisible(false)}/> diff --git a/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx b/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx index 60d7ca943..a643d2a54 100644 --- a/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx +++ b/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx @@ -153,7 +153,7 @@ export default () => { }
- +
{ return (
- {isEditing && setIsEditing(false)} - />} + visible={isEditing} + onModalDismissed={() => setIsEditing(false)} + /> { }
+ {task.continueOnFailure && +
+
+ + Continues on Failure +
+
+ } {task.sequenceId > 1 && task.timeOffset > 0 &&
diff --git a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx index 08f33b161..9b30d66fa 100644 --- a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx +++ b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx @@ -1,13 +1,12 @@ -import React, { useEffect } from 'react'; -import Modal from '@/components/elements/Modal'; +import React, { useContext, useEffect } from 'react'; import { Schedule, Task } from '@/api/server/schedules/getServerSchedules'; -import { Field as FormikField, Form, Formik, FormikHelpers, useFormikContext } from 'formik'; +import { Field as FormikField, Form, Formik, FormikHelpers, useField } from 'formik'; 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'; -import { number, object, string } from 'yup'; +import { boolean, number, object, string } from 'yup'; import useFlash from '@/plugins/useFlash'; import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper'; import tw from 'twin.macro'; @@ -15,105 +14,66 @@ import Label from '@/components/elements/Label'; import { Textarea } from '@/components/elements/Input'; import Button from '@/components/elements/Button'; import Select from '@/components/elements/Select'; +import ModalContext from '@/context/ModalContext'; +import asModal from '@/hoc/asModal'; +import FormikSwitch from '@/components/elements/FormikSwitch'; interface Props { schedule: Schedule; // If a task is provided we can assume we're editing it. If not provided, // we are creating a new one. task?: Task; - onDismissed: () => void; } interface Values { action: string; payload: string; timeOffset: string; + continueOnFailure: boolean; } -const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => { - const { values: { action }, initialValues, setFieldValue, setFieldTouched, isSubmitting } = useFormikContext(); +const schema = object().shape({ + 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(), + }), + continueOnFailure: boolean(), + 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.'), +}); + +const ActionListener = () => { + const [ { value }, { initialValue: initialAction } ] = useField('action'); + const [ , { initialValue: initialPayload }, { setValue, setTouched } ] = useField('payload'); useEffect(() => { - if (action !== initialValues.action) { - setFieldValue('payload', action === 'power' ? 'start' : ''); - setFieldTouched('payload', false); + if (value !== initialAction) { + setValue(value === 'power' ? 'start' : ''); + setTouched(false); } else { - setFieldValue('payload', initialValues.payload); - setFieldTouched('payload', false); + setValue(initialPayload || ''); + setTouched(false); } - }, [ action ]); + }, [ value ]); - return ( -
-

{isEditingTask ? 'Edit Task' : 'Create Task'}

-
-
- - - - - - - - -
-
- -
-
-
- {action === 'command' ? -
- - - - -
- : - action === 'power' ? -
- - - - - - - - - -
- : -
- - - - -
- } -
-
- -
-
- ); + return null; }; -export default ({ task, schedule, onDismissed }: Props) => { - const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); +const TaskDetailsModal = ({ schedule, task }: Props) => { + const { dismiss } = useContext(ModalContext); const { clearFlashes, addError } = useFlash(); + + const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule); useEffect(() => { - clearFlashes('schedule:task'); + return () => { + clearFlashes('schedule:task'); + }; }, []); const submit = (values: Values, { setSubmitting }: FormikHelpers) => { @@ -126,7 +86,7 @@ export default ({ task, schedule, onDismissed }: Props) => { } appendSchedule({ ...schedule, tasks }); - onDismissed(); + dismiss(); }) .catch(error => { console.error(error); @@ -138,35 +98,87 @@ export default ({ task, schedule, onDismissed }: Props) => { return ( v !== 'backup', - then: string().required('A task payload must be provided.'), - otherwise: string(), - }), - 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.'), - })} > - {({ isSubmitting }) => ( - onDismissed()} - showSpinnerOverlay={isSubmitting} - > - - - + {({ isSubmitting, values }) => ( +
+ +

{task ? 'Edit Task' : 'Create Task'}

+
+
+ + + + + + + + + +
+
+ +
+
+
+ {values.action === 'command' ? +
+ + + + +
+ : + values.action === 'power' ? +
+ + + + + + + + + +
+ : +
+ + + + +
+ } +
+
+ +
+
+ +
+ )}
); }; + +export default asModal()(TaskDetailsModal);