diff --git a/resources/scripts/api/definitions/user/models.d.ts b/resources/scripts/api/definitions/user/models.d.ts index a721b2a66..001660912 100644 --- a/resources/scripts/api/definitions/user/models.d.ts +++ b/resources/scripts/api/definitions/user/models.d.ts @@ -115,3 +115,35 @@ interface Subuser extends Model { can (permission: SubuserPermission): boolean; } + +interface Schedule extends Model { + id: number; + name: string; + cron: { + dayOfWeek: string; + month: string; + dayOfMonth: string; + hour: string; + minute: string; + }; + isActive: boolean; + isProcessing: boolean; + onlyWhenOnline: boolean; + lastRunAt: Date | null; + nextRunAt: Date | null; + createdAt: Date; + updatedAt: Date; + tasks: Task[]; +} + +interface Task extends Model { + id: number; + sequenceId: number; + action: string; + payload: string; + timeOffset: number; + isQueued: boolean; + continueOnFailure: boolean; + createdAt: Date; + updatedAt: Date; +} diff --git a/resources/scripts/api/definitions/user/transformers.ts b/resources/scripts/api/definitions/user/transformers.ts index 9e2d6cb15..69799c6db 100644 --- a/resources/scripts/api/definitions/user/transformers.ts +++ b/resources/scripts/api/definitions/user/transformers.ts @@ -109,4 +109,41 @@ export default class Transformers { can: permission => (attributes.permissions || []).indexOf(permission) >= 0, }; } + + static toServerTask ({ attributes }: FractalResponseData): Models.Task { + return { + id: attributes.id, + sequenceId: attributes.sequence_id, + action: attributes.action, + payload: attributes.payload, + timeOffset: attributes.time_offset, + isQueued: attributes.is_queued, + continueOnFailure: attributes.continue_on_failure, + createdAt: new Date(attributes.created_at), + updatedAt: new Date(attributes.updated_at), + }; + } + + static toServerSchedule ({ attributes }: FractalResponseData): Models.Schedule { + return { + id: attributes.id, + name: attributes.name, + cron: { + dayOfWeek: attributes.cron.day_of_week, + month: attributes.cron.month, + dayOfMonth: attributes.cron.day_of_month, + hour: attributes.cron.hour, + minute: attributes.cron.minute, + }, + isActive: attributes.is_active, + isProcessing: attributes.is_processing, + onlyWhenOnline: attributes.only_when_online, + lastRunAt: attributes.last_run_at ? new Date(attributes.last_run_at) : null, + nextRunAt: attributes.next_run_at ? new Date(attributes.next_run_at) : null, + createdAt: new Date(attributes.created_at), + updatedAt: new Date(attributes.updated_at), + // @ts-expect-error + tasks: (attributes.relationships?.tasks?.data || []).map((row: any) => this.toServerTask(row.attributes)), + }; + } } diff --git a/resources/scripts/api/server/schedules.ts b/resources/scripts/api/server/schedules.ts new file mode 100644 index 000000000..4d72399fa --- /dev/null +++ b/resources/scripts/api/server/schedules.ts @@ -0,0 +1,88 @@ +import http from '@/api/http'; +import { Schedule, Task, Transformers } from '@definitions/user'; + +type CreateScheduleData = Pick & { id?: number } + +interface CreateTaskData { + action: string; + payload: string; + timeOffset: string | number; + continueOnFailure: boolean; +} + +const createOrUpdateSchedule = async (uuid: string, schedule: CreateScheduleData): Promise => { + const { data } = await http.post(`/api/client/servers/${uuid}/schedules${schedule.id ? `/${schedule.id}` : ''}`, { + is_active: schedule.isActive, + only_when_online: schedule.onlyWhenOnline, + name: schedule.name, + minute: schedule.cron.minute, + hour: schedule.cron.hour, + day_of_month: schedule.cron.dayOfMonth, + month: schedule.cron.month, + day_of_week: schedule.cron.dayOfWeek, + }); + + return Transformers.toServerSchedule(data); +}; + +const createOrUpdateScheduleTask = async (uuid: string, schedule: number, task: number | undefined, data: CreateTaskData): 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 Transformers.toServerTask(response); +}; + +const deleteSchedule = (uuid: string, schedule: number): Promise => { + return new Promise((resolve, reject) => { + http.delete(`/api/client/servers/${uuid}/schedules/${schedule}`) + .then(() => resolve()) + .catch(reject); + }); +}; + +const deleteScheduleTask = (uuid: string, scheduleId: number, taskId: number): Promise => { + return new Promise((resolve, reject) => { + http.delete(`/api/client/servers/${uuid}/schedules/${scheduleId}/tasks/${taskId}`) + .then(() => resolve()) + .catch(reject); + }); +}; + +const getServerSchedule = (uuid: string, schedule: number): Promise => { + return new Promise((resolve, reject) => { + http.get(`/api/client/servers/${uuid}/schedules/${schedule}`, { + params: { + include: [ 'tasks' ], + }, + }) + .then(({ data }) => resolve(Transformers.toServerSchedule(data))) + .catch(reject); + }); +}; + +const getServerSchedules = async (uuid: string): Promise => { + const { data } = await http.get(`/api/client/servers/${uuid}/schedules`, { + params: { + include: [ 'tasks' ], + }, + }); + + return (data.data || []).map(Transformers.toServerSchedule); +}; + +const triggerScheduleExecution = async (server: string, schedule: number): Promise => + await http.post(`/api/client/servers/${server}/schedules/${schedule}/execute`); + +export { + deleteSchedule, + deleteScheduleTask, + createOrUpdateSchedule, + createOrUpdateScheduleTask, + getServerSchedule, + getServerSchedules, + triggerScheduleExecution, +}; diff --git a/resources/scripts/api/server/schedules/createOrUpdateSchedule.ts b/resources/scripts/api/server/schedules/createOrUpdateSchedule.ts deleted file mode 100644 index de1bc075b..000000000 --- a/resources/scripts/api/server/schedules/createOrUpdateSchedule.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { rawDataToServerSchedule, Schedule } from '@/api/server/schedules/getServerSchedules'; -import http from '@/api/http'; - -type Data = Pick & { id?: number } - -export default async (uuid: string, schedule: Data): Promise => { - const { data } = await http.post(`/api/client/servers/${uuid}/schedules${schedule.id ? `/${schedule.id}` : ''}`, { - is_active: schedule.isActive, - only_when_online: schedule.onlyWhenOnline, - name: schedule.name, - minute: schedule.cron.minute, - hour: schedule.cron.hour, - day_of_month: schedule.cron.dayOfMonth, - month: schedule.cron.month, - day_of_week: schedule.cron.dayOfWeek, - }); - - return rawDataToServerSchedule(data.attributes); -}; diff --git a/resources/scripts/api/server/schedules/createOrUpdateScheduleTask.ts b/resources/scripts/api/server/schedules/createOrUpdateScheduleTask.ts deleted file mode 100644 index c2bfc807b..000000000 --- a/resources/scripts/api/server/schedules/createOrUpdateScheduleTask.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { rawDataToServerTask, Task } from '@/api/server/schedules/getServerSchedules'; -import http from '@/api/http'; - -interface Data { - action: string; - payload: string; - timeOffset: string | number; - continueOnFailure: boolean; -} - -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/api/server/schedules/deleteSchedule.ts b/resources/scripts/api/server/schedules/deleteSchedule.ts deleted file mode 100644 index c3669988d..000000000 --- a/resources/scripts/api/server/schedules/deleteSchedule.ts +++ /dev/null @@ -1,9 +0,0 @@ -import http from '@/api/http'; - -export default (uuid: string, schedule: number): Promise => { - return new Promise((resolve, reject) => { - http.delete(`/api/client/servers/${uuid}/schedules/${schedule}`) - .then(() => resolve()) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/server/schedules/deleteScheduleTask.ts b/resources/scripts/api/server/schedules/deleteScheduleTask.ts deleted file mode 100644 index 8867677b2..000000000 --- a/resources/scripts/api/server/schedules/deleteScheduleTask.ts +++ /dev/null @@ -1,9 +0,0 @@ -import http from '@/api/http'; - -export default (uuid: string, scheduleId: number, taskId: number): Promise => { - return new Promise((resolve, reject) => { - http.delete(`/api/client/servers/${uuid}/schedules/${scheduleId}/tasks/${taskId}`) - .then(() => resolve()) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/server/schedules/getServerSchedule.ts b/resources/scripts/api/server/schedules/getServerSchedule.ts deleted file mode 100644 index 63e3d6f98..000000000 --- a/resources/scripts/api/server/schedules/getServerSchedule.ts +++ /dev/null @@ -1,14 +0,0 @@ -import http from '@/api/http'; -import { rawDataToServerSchedule, Schedule } from '@/api/server/schedules/getServerSchedules'; - -export default (uuid: string, schedule: number): Promise => { - return new Promise((resolve, reject) => { - http.get(`/api/client/servers/${uuid}/schedules/${schedule}`, { - params: { - include: [ 'tasks' ], - }, - }) - .then(({ data }) => resolve(rawDataToServerSchedule(data.attributes))) - .catch(reject); - }); -}; diff --git a/resources/scripts/api/server/schedules/getServerSchedules.ts b/resources/scripts/api/server/schedules/getServerSchedules.ts deleted file mode 100644 index c052e7a3c..000000000 --- a/resources/scripts/api/server/schedules/getServerSchedules.ts +++ /dev/null @@ -1,77 +0,0 @@ -import http from '@/api/http'; - -export interface Schedule { - id: number; - name: string; - cron: { - dayOfWeek: string; - month: string; - dayOfMonth: string; - hour: string; - minute: string; - }; - isActive: boolean; - isProcessing: boolean; - onlyWhenOnline: boolean; - lastRunAt: Date | null; - nextRunAt: Date | null; - createdAt: Date; - updatedAt: Date; - - tasks: Task[]; -} - -export interface Task { - id: number; - sequenceId: number; - action: string; - payload: string; - timeOffset: number; - isQueued: boolean; - continueOnFailure: boolean; - createdAt: Date; - updatedAt: Date; -} - -export const rawDataToServerTask = (data: any): Task => ({ - id: data.id, - sequenceId: data.sequence_id, - action: data.action, - payload: data.payload, - timeOffset: data.time_offset, - isQueued: data.is_queued, - continueOnFailure: data.continue_on_failure, - createdAt: new Date(data.created_at), - updatedAt: new Date(data.updated_at), -}); - -export const rawDataToServerSchedule = (data: any): Schedule => ({ - id: data.id, - name: data.name, - cron: { - dayOfWeek: data.cron.day_of_week, - month: data.cron.month, - dayOfMonth: data.cron.day_of_month, - hour: data.cron.hour, - minute: data.cron.minute, - }, - isActive: data.is_active, - isProcessing: data.is_processing, - onlyWhenOnline: data.only_when_online, - lastRunAt: data.last_run_at ? new Date(data.last_run_at) : null, - nextRunAt: data.next_run_at ? new Date(data.next_run_at) : null, - createdAt: new Date(data.created_at), - updatedAt: new Date(data.updated_at), - - tasks: (data.relationships?.tasks?.data || []).map((row: any) => rawDataToServerTask(row.attributes)), -}); - -export default async (uuid: string): Promise => { - const { data } = await http.get(`/api/client/servers/${uuid}/schedules`, { - params: { - include: [ 'tasks' ], - }, - }); - - return (data.data || []).map((row: any) => rawDataToServerSchedule(row.attributes)); -}; diff --git a/resources/scripts/api/server/schedules/triggerScheduleExecution.ts b/resources/scripts/api/server/schedules/triggerScheduleExecution.ts deleted file mode 100644 index 92f7a589f..000000000 --- a/resources/scripts/api/server/schedules/triggerScheduleExecution.ts +++ /dev/null @@ -1,4 +0,0 @@ -import http from '@/api/http'; - -export default async (server: string, schedule: number): Promise => - await http.post(`/api/client/servers/${server}/schedules/${schedule}/execute`); diff --git a/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx b/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx index 463202dce..315080f8a 100644 --- a/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx +++ b/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import deleteSchedule from '@/api/server/schedules/deleteSchedule'; +import { deleteSchedule } from '@/api/server/schedules'; import { ServerContext } from '@/state/server'; import { Actions, useStoreActions } from 'easy-peasy'; import { ApplicationStore } from '@/state'; diff --git a/resources/scripts/components/server/schedules/EditScheduleModal.tsx b/resources/scripts/components/server/schedules/EditScheduleModal.tsx index 57602f2ed..8451e4a4d 100644 --- a/resources/scripts/components/server/schedules/EditScheduleModal.tsx +++ b/resources/scripts/components/server/schedules/EditScheduleModal.tsx @@ -1,9 +1,9 @@ import React, { useContext, useEffect } from 'react'; -import { Schedule } from '@/api/server/schedules/getServerSchedules'; +import { Schedule } from '@definitions/user'; import Field from '@/components/elements/Field'; import { Form, Formik, FormikHelpers } from 'formik'; import FormikSwitch from '@/components/elements/FormikSwitch'; -import createOrUpdateSchedule from '@/api/server/schedules/createOrUpdateSchedule'; +import { createOrUpdateSchedule } from '@/api/server/schedules'; import { ServerContext } from '@/state/server'; import { httpErrorToHuman } from '@/api/http'; import FlashMessageRender from '@/components/FlashMessageRender'; diff --git a/resources/scripts/components/server/schedules/NewTaskButton.tsx b/resources/scripts/components/server/schedules/NewTaskButton.tsx index 2ac7b276c..3bc0a56d9 100644 --- a/resources/scripts/components/server/schedules/NewTaskButton.tsx +++ b/resources/scripts/components/server/schedules/NewTaskButton.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Schedule } from '@/api/server/schedules/getServerSchedules'; +import { Schedule } from '@definitions/user'; import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal'; import Button from '@/components/elements/Button'; import tw from 'twin.macro'; diff --git a/resources/scripts/components/server/schedules/RunScheduleButton.tsx b/resources/scripts/components/server/schedules/RunScheduleButton.tsx index 875de28f3..5aa9c2c7c 100644 --- a/resources/scripts/components/server/schedules/RunScheduleButton.tsx +++ b/resources/scripts/components/server/schedules/RunScheduleButton.tsx @@ -2,10 +2,10 @@ import React, { useCallback, useState } from 'react'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import tw from 'twin.macro'; import Button from '@/components/elements/Button'; -import triggerScheduleExecution from '@/api/server/schedules/triggerScheduleExecution'; +import { triggerScheduleExecution } from '@/api/server/schedules'; import { ServerContext } from '@/state/server'; import useFlash from '@/plugins/useFlash'; -import { Schedule } from '@/api/server/schedules/getServerSchedules'; +import { Schedule } from '@definitions/user'; const RunScheduleButton = ({ schedule }: { schedule: Schedule }) => { const [ loading, setLoading ] = useState(false); diff --git a/resources/scripts/components/server/schedules/ScheduleContainer.tsx b/resources/scripts/components/server/schedules/ScheduleContainer.tsx index 958f3fef9..432022578 100644 --- a/resources/scripts/components/server/schedules/ScheduleContainer.tsx +++ b/resources/scripts/components/server/schedules/ScheduleContainer.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import getServerSchedules from '@/api/server/schedules/getServerSchedules'; +import { getServerSchedules } from '@/api/server/schedules'; import { ServerContext } from '@/state/server'; import Spinner from '@/components/elements/Spinner'; import { useHistory, useRouteMatch } from 'react-router-dom'; diff --git a/resources/scripts/components/server/schedules/ScheduleCronRow.tsx b/resources/scripts/components/server/schedules/ScheduleCronRow.tsx index 2a733b2d4..db602269a 100644 --- a/resources/scripts/components/server/schedules/ScheduleCronRow.tsx +++ b/resources/scripts/components/server/schedules/ScheduleCronRow.tsx @@ -1,6 +1,6 @@ import React from 'react'; import tw from 'twin.macro'; -import { Schedule } from '@/api/server/schedules/getServerSchedules'; +import { Schedule } from '@definitions/user'; interface Props { cron: Schedule['cron']; diff --git a/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx b/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx index 33fda7a06..b36c6fd37 100644 --- a/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx +++ b/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import getServerSchedule from '@/api/server/schedules/getServerSchedule'; +import { getServerSchedule } from '@/api/server/schedules'; import Spinner from '@/components/elements/Spinner'; import FlashMessageRender from '@/components/FlashMessageRender'; import EditScheduleModal from '@/components/server/schedules/EditScheduleModal'; diff --git a/resources/scripts/components/server/schedules/ScheduleRow.tsx b/resources/scripts/components/server/schedules/ScheduleRow.tsx index eccdd0f96..51b946e91 100644 --- a/resources/scripts/components/server/schedules/ScheduleRow.tsx +++ b/resources/scripts/components/server/schedules/ScheduleRow.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Schedule } from '@/api/server/schedules/getServerSchedules'; +import { Schedule } from '@definitions/user'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons'; import { format } from 'date-fns'; diff --git a/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx b/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx index d4bdcc0d6..35e7b8a13 100644 --- a/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx +++ b/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Schedule, Task } from '@/api/server/schedules/getServerSchedules'; +import { Schedule, Task } from '@definitions/user'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faArrowCircleDown, @@ -10,7 +10,7 @@ import { faToggleOn, faTrashAlt, } from '@fortawesome/free-solid-svg-icons'; -import deleteScheduleTask from '@/api/server/schedules/deleteScheduleTask'; +import { deleteScheduleTask } from '@/api/server/schedules'; import { httpErrorToHuman } from '@/api/http'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal'; diff --git a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx index 7cc39f555..44d02fd4f 100644 --- a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx +++ b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx @@ -1,8 +1,8 @@ import React, { useContext, useEffect } from 'react'; -import { Schedule, Task } from '@/api/server/schedules/getServerSchedules'; +import { Schedule, Task } from '@definitions/user'; import { Field as FormikField, Form, Formik, FormikHelpers, useField } from 'formik'; import { ServerContext } from '@/state/server'; -import createOrUpdateScheduleTask from '@/api/server/schedules/createOrUpdateScheduleTask'; +import { createOrUpdateScheduleTask } from '@/api/server/schedules'; import { httpErrorToHuman } from '@/api/http'; import Field from '@/components/elements/Field'; import FlashMessageRender from '@/components/FlashMessageRender'; diff --git a/resources/scripts/state/server/schedules.ts b/resources/scripts/state/server/schedules.ts index 47504ef7a..a5ca8409e 100644 --- a/resources/scripts/state/server/schedules.ts +++ b/resources/scripts/state/server/schedules.ts @@ -1,5 +1,5 @@ import { action, Action } from 'easy-peasy'; -import { Schedule } from '@/api/server/schedules/getServerSchedules'; +import { Schedule } from '@definitions/user'; export interface ServerScheduleStore { data: Schedule[];