feat(jobs): allow modifying job schedules (#1440)

* feat(jobs): backend implementation

* feat(jobs): initial frontend implementation

* feat(jobs): store job settings as Record

* feat(jobs): use heroicons/react instead of inline svgs

* feat(jobs): use presets instead of cron expressions

* feat(jobs): ran `yarn i18n:extract`

* feat(jobs): suggested changes

- use job ids in settings
- add intervalDuration to jobs to allow choosing only minutes or hours for the job schedule
- move job schedule defaults to settings.json
- better TS types for jobs in settings cache component
- make suggested changes to wording
- plural form for label when job schedule can be defined in minutes
- add fixed job interval duration
- add predefined interval choices for minutes and hours
- add new schema for job to overseerr api

* feat(jobs): required change for CI to not fail

* feat(jobs): suggested changes

* fix(jobs): revert offending type refactor
This commit is contained in:
Danshil Kokil Mungur
2021-10-15 16:23:39 +04:00
committed by GitHub
parent 5683f55ebf
commit 82614ca441
6 changed files with 310 additions and 66 deletions

View File

@@ -2,6 +2,7 @@ import { Router } from 'express';
import rateLimit from 'express-rate-limit';
import fs from 'fs';
import { merge, omit } from 'lodash';
import { rescheduleJob } from 'node-schedule';
import path from 'path';
import { getRepository } from 'typeorm';
import { URL } from 'url';
@@ -49,7 +50,7 @@ settingsRoutes.get('/main', (req, res, next) => {
const settings = getSettings();
if (!req.user) {
return next({ status: 500, message: 'User missing from request' });
return next({ status: 400, message: 'User missing from request' });
}
res.status(200).json(filteredMainSettings(req.user, settings.main));
@@ -310,6 +311,7 @@ settingsRoutes.get('/jobs', (_req, res) => {
id: job.id,
name: job.name,
type: job.type,
interval: job.interval,
nextExecutionTime: job.job.nextInvocation(),
running: job.running ? job.running() : false,
}))
@@ -329,6 +331,7 @@ settingsRoutes.post<{ jobId: string }>('/jobs/:jobId/run', (req, res, next) => {
id: scheduledJob.id,
name: scheduledJob.name,
type: scheduledJob.type,
interval: scheduledJob.interval,
nextExecutionTime: scheduledJob.job.nextInvocation(),
running: scheduledJob.running ? scheduledJob.running() : false,
});
@@ -353,12 +356,45 @@ settingsRoutes.post<{ jobId: string }>(
id: scheduledJob.id,
name: scheduledJob.name,
type: scheduledJob.type,
interval: scheduledJob.interval,
nextExecutionTime: scheduledJob.job.nextInvocation(),
running: scheduledJob.running ? scheduledJob.running() : false,
});
}
);
settingsRoutes.post<{ jobId: string }>(
'/jobs/:jobId/schedule',
(req, res, next) => {
const scheduledJob = scheduledJobs.find(
(job) => job.id === req.params.jobId
);
if (!scheduledJob) {
return next({ status: 404, message: 'Job not found' });
}
const result = rescheduleJob(scheduledJob.job, req.body.schedule);
const settings = getSettings();
if (result) {
settings.jobs[scheduledJob.id].schedule = req.body.schedule;
settings.save();
return res.status(200).json({
id: scheduledJob.id,
name: scheduledJob.name,
type: scheduledJob.type,
interval: scheduledJob.interval,
nextExecutionTime: scheduledJob.job.nextInvocation(),
running: scheduledJob.running ? scheduledJob.running() : false,
});
} else {
return next({ status: 400, message: 'Invalid job schedule' });
}
}
);
settingsRoutes.get('/cache', (req, res) => {
const caches = cacheManager.getAllCaches();