import React, { useContext, useEffect } from 'react'; import { Schedule, Task } from '@/api/server/schedules/getServerSchedules'; 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 { boolean, number, object, string } from 'yup'; import useFlash from '@/plugins/useFlash'; import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper'; import tw from 'twin.macro'; import Label from '@/components/elements/Label'; import { Textarea } from '@/components/elements/Input'; import { Button } from '@/components/elements/button/index'; 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; } interface Values { action: string; payload: string; timeOffset: string; continueOnFailure: boolean; } 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 (value !== initialAction) { setValue(value === 'power' ? 'start' : ''); setTouched(false); } else { setValue(initialPayload || ''); setTouched(false); } }, [value]); return null; }; 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); const backupLimit = ServerContext.useStoreState((state) => state.server.data!.featureLimits.backups); useEffect(() => { return () => { clearFlashes('schedule:task'); }; }, []); const submit = (values: Values, { setSubmitting }: FormikHelpers) => { clearFlashes('schedule:task'); if (backupLimit === 0 && values.action === 'backup') { setSubmitting(false); addError({ message: "A backup task cannot be created when the server's backup limit is set to 0.", key: 'schedule:task', }); } else { 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 }); dismiss(); }) .catch((error) => { console.error(error); setSubmitting(false); addError({ message: httpErrorToHuman(error), key: 'schedule:task' }); }); } }; return ( {({ isSubmitting, values }) => (

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

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