Update schedules API

This commit is contained in:
Dane Everitt 2022-02-27 12:35:27 -05:00
parent bfd92c314d
commit feffdacf57
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
21 changed files with 172 additions and 167 deletions

View file

@ -115,3 +115,35 @@ interface Subuser extends Model {
can (permission: SubuserPermission): boolean; 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;
}

View file

@ -109,4 +109,41 @@ export default class Transformers {
can: permission => (attributes.permissions || []).indexOf(permission) >= 0, 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)),
};
}
} }

View file

@ -0,0 +1,88 @@
import http from '@/api/http';
import { Schedule, Task, Transformers } from '@definitions/user';
type CreateScheduleData = Pick<Schedule, 'cron' | 'name' | 'onlyWhenOnline' | 'isActive'> & { id?: number }
interface CreateTaskData {
action: string;
payload: string;
timeOffset: string | number;
continueOnFailure: boolean;
}
const createOrUpdateSchedule = async (uuid: string, schedule: CreateScheduleData): Promise<Schedule> => {
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<Task> => {
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<void> => {
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<void> => {
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<Schedule> => {
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<Schedule[]> => {
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<void> =>
await http.post(`/api/client/servers/${server}/schedules/${schedule}/execute`);
export {
deleteSchedule,
deleteScheduleTask,
createOrUpdateSchedule,
createOrUpdateScheduleTask,
getServerSchedule,
getServerSchedules,
triggerScheduleExecution,
};

View file

@ -1,19 +0,0 @@
import { rawDataToServerSchedule, Schedule } from '@/api/server/schedules/getServerSchedules';
import http from '@/api/http';
type Data = Pick<Schedule, 'cron' | 'name' | 'onlyWhenOnline' | 'isActive'> & { id?: number }
export default async (uuid: string, schedule: Data): Promise<Schedule> => {
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);
};

View file

@ -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<Task> => {
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);
};

View file

@ -1,9 +0,0 @@
import http from '@/api/http';
export default (uuid: string, schedule: number): Promise<void> => {
return new Promise((resolve, reject) => {
http.delete(`/api/client/servers/${uuid}/schedules/${schedule}`)
.then(() => resolve())
.catch(reject);
});
};

View file

@ -1,9 +0,0 @@
import http from '@/api/http';
export default (uuid: string, scheduleId: number, taskId: number): Promise<void> => {
return new Promise((resolve, reject) => {
http.delete(`/api/client/servers/${uuid}/schedules/${scheduleId}/tasks/${taskId}`)
.then(() => resolve())
.catch(reject);
});
};

View file

@ -1,14 +0,0 @@
import http from '@/api/http';
import { rawDataToServerSchedule, Schedule } from '@/api/server/schedules/getServerSchedules';
export default (uuid: string, schedule: number): Promise<Schedule> => {
return new Promise((resolve, reject) => {
http.get(`/api/client/servers/${uuid}/schedules/${schedule}`, {
params: {
include: [ 'tasks' ],
},
})
.then(({ data }) => resolve(rawDataToServerSchedule(data.attributes)))
.catch(reject);
});
};

View file

@ -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<Schedule[]> => {
const { data } = await http.get(`/api/client/servers/${uuid}/schedules`, {
params: {
include: [ 'tasks' ],
},
});
return (data.data || []).map((row: any) => rawDataToServerSchedule(row.attributes));
};

View file

@ -1,4 +0,0 @@
import http from '@/api/http';
export default async (server: string, schedule: number): Promise<void> =>
await http.post(`/api/client/servers/${server}/schedules/${schedule}/execute`);

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import deleteSchedule from '@/api/server/schedules/deleteSchedule'; import { deleteSchedule } from '@/api/server/schedules';
import { ServerContext } from '@/state/server'; import { ServerContext } from '@/state/server';
import { Actions, useStoreActions } from 'easy-peasy'; import { Actions, useStoreActions } from 'easy-peasy';
import { ApplicationStore } from '@/state'; import { ApplicationStore } from '@/state';

View file

@ -1,9 +1,9 @@
import React, { useContext, useEffect } from 'react'; 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 Field from '@/components/elements/Field';
import { Form, Formik, FormikHelpers } from 'formik'; import { Form, Formik, FormikHelpers } from 'formik';
import FormikSwitch from '@/components/elements/FormikSwitch'; 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 { ServerContext } from '@/state/server';
import { httpErrorToHuman } from '@/api/http'; import { httpErrorToHuman } from '@/api/http';
import FlashMessageRender from '@/components/FlashMessageRender'; import FlashMessageRender from '@/components/FlashMessageRender';

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react'; 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 TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
import Button from '@/components/elements/Button'; import Button from '@/components/elements/Button';
import tw from 'twin.macro'; import tw from 'twin.macro';

View file

@ -2,10 +2,10 @@ import React, { useCallback, useState } from 'react';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import tw from 'twin.macro'; import tw from 'twin.macro';
import Button from '@/components/elements/Button'; 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 { ServerContext } from '@/state/server';
import useFlash from '@/plugins/useFlash'; import useFlash from '@/plugins/useFlash';
import { Schedule } from '@/api/server/schedules/getServerSchedules'; import { Schedule } from '@definitions/user';
const RunScheduleButton = ({ schedule }: { schedule: Schedule }) => { const RunScheduleButton = ({ schedule }: { schedule: Schedule }) => {
const [ loading, setLoading ] = useState(false); const [ loading, setLoading ] = useState(false);

View file

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'; 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 { ServerContext } from '@/state/server';
import Spinner from '@/components/elements/Spinner'; import Spinner from '@/components/elements/Spinner';
import { useHistory, useRouteMatch } from 'react-router-dom'; import { useHistory, useRouteMatch } from 'react-router-dom';

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import tw from 'twin.macro'; import tw from 'twin.macro';
import { Schedule } from '@/api/server/schedules/getServerSchedules'; import { Schedule } from '@definitions/user';
interface Props { interface Props {
cron: Schedule['cron']; cron: Schedule['cron'];

View file

@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom'; 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 Spinner from '@/components/elements/Spinner';
import FlashMessageRender from '@/components/FlashMessageRender'; import FlashMessageRender from '@/components/FlashMessageRender';
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal'; import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Schedule } from '@/api/server/schedules/getServerSchedules'; import { Schedule } from '@definitions/user';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons'; import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons';
import { format } from 'date-fns'; import { format } from 'date-fns';

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react'; 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 { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { import {
faArrowCircleDown, faArrowCircleDown,
@ -10,7 +10,7 @@ import {
faToggleOn, faToggleOn,
faTrashAlt, faTrashAlt,
} from '@fortawesome/free-solid-svg-icons'; } 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 { httpErrorToHuman } from '@/api/http';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal'; import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';

View file

@ -1,8 +1,8 @@
import React, { useContext, useEffect } from 'react'; 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 { Field as FormikField, Form, Formik, FormikHelpers, useField } from 'formik';
import { ServerContext } from '@/state/server'; import { ServerContext } from '@/state/server';
import createOrUpdateScheduleTask from '@/api/server/schedules/createOrUpdateScheduleTask'; import { createOrUpdateScheduleTask } from '@/api/server/schedules';
import { httpErrorToHuman } from '@/api/http'; import { httpErrorToHuman } from '@/api/http';
import Field from '@/components/elements/Field'; import Field from '@/components/elements/Field';
import FlashMessageRender from '@/components/FlashMessageRender'; import FlashMessageRender from '@/components/FlashMessageRender';

View file

@ -1,5 +1,5 @@
import { action, Action } from 'easy-peasy'; import { action, Action } from 'easy-peasy';
import { Schedule } from '@/api/server/schedules/getServerSchedules'; import { Schedule } from '@definitions/user';
export interface ServerScheduleStore { export interface ServerScheduleStore {
data: Schedule[]; data: Schedule[];