Merge https://github.com/dankrieger/crontab-ui into v0.1.7
commit
f9b23c708d
76
app.js
76
app.js
|
@ -3,6 +3,7 @@ var app = express();
|
|||
var crontab = require("./crontab");
|
||||
var restore = require("./restore");
|
||||
|
||||
var moment = require('moment');
|
||||
var path = require('path');
|
||||
var mime = require('mime');
|
||||
var fs = require('fs');
|
||||
|
@ -30,15 +31,24 @@ app.set('views', __dirname + '/views');
|
|||
|
||||
//set port
|
||||
app.set('port', (process.env.PORT || 8000));
|
||||
app.set('listen', (process.env.LISTEN || '0.0.0.0'));
|
||||
|
||||
app.get(routes.root, function(req, res) {
|
||||
// get all the crontabs
|
||||
crontab.crontabs( function(docs){
|
||||
crontab.templates(function(templates) {
|
||||
res.render('index', {
|
||||
routes : JSON.stringify(routes),
|
||||
crontabs : JSON.stringify(docs),
|
||||
templates: templates,
|
||||
templatesById: templates.reduce(function(memo, t) {
|
||||
memo[t._id] = t;
|
||||
return memo;
|
||||
}, {}),
|
||||
backups : crontab.get_backup_names(),
|
||||
env : crontab.get_env()
|
||||
env : crontab.get_env(),
|
||||
moment: moment,
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
|
@ -46,15 +56,33 @@ app.get(routes.root, function(req, res) {
|
|||
app.post(routes.save, function(req, res) {
|
||||
// new job
|
||||
if(req.body._id == -1){
|
||||
crontab.create_new(req.body.name, req.body.command, req.body.schedule, req.body.logging);
|
||||
crontab.create_new(req.body.name, req.body.command, req.body.command_template, req.body.vars, req.body.schedule, req.body.logging);
|
||||
}
|
||||
// edit job
|
||||
else{
|
||||
|
||||
crontab.update(req.body);
|
||||
}
|
||||
res.end();
|
||||
})
|
||||
|
||||
app.post(routes.save_template, function(req, res) {
|
||||
// new job
|
||||
if(req.body._id == -1){
|
||||
crontab.create_new_template(req.body.name, req.body.command, req.body.schedule);
|
||||
}
|
||||
// edit job
|
||||
else{
|
||||
crontab.update_template(req.body);
|
||||
}
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.post(routes.remove_template, function(req, res) {
|
||||
crontab.remove_template(req.body._id);
|
||||
res.end();
|
||||
})
|
||||
|
||||
app.post(routes.stop, function(req, res) {
|
||||
crontab.status(req.body._id, true);
|
||||
res.end();
|
||||
|
@ -81,11 +109,18 @@ app.get(routes.backup, function(req, res) {
|
|||
|
||||
app.get(routes.restore, function(req, res) {
|
||||
// get all the crontabs
|
||||
restore.crontabs(req.query.db, function(docs){
|
||||
restore.loadBackupFile(req.query.db, function(docs, templates) {
|
||||
res.render('restore', {
|
||||
routes : JSON.stringify(routes),
|
||||
crontabs : JSON.stringify(docs),
|
||||
templates: templates,
|
||||
templatesById: templates.reduce(function(memo, t) {
|
||||
memo[t._id] = t;
|
||||
return memo;
|
||||
}, {}),
|
||||
backups : crontab.get_backup_names(),
|
||||
env : crontab.get_env(),
|
||||
moment: moment,
|
||||
db: req.query.db
|
||||
});
|
||||
});
|
||||
|
@ -102,31 +137,30 @@ app.get(routes.restore_backup, function(req, res) {
|
|||
})
|
||||
|
||||
app.get(routes.export, function(req, res) {
|
||||
var file = __dirname + '/crontabs/crontab.db';
|
||||
var backupData = crontab.backup_data();
|
||||
|
||||
var filename = path.basename(file);
|
||||
var mimetype = mime.lookup(file);
|
||||
res.setHeader('Content-disposition', 'attachment; filename=crontab_ui_backup.json');
|
||||
res.setHeader('Content-type', 'application/json');
|
||||
|
||||
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
|
||||
res.setHeader('Content-type', mimetype);
|
||||
|
||||
var filestream = fs.createReadStream(file);
|
||||
filestream.pipe(res);
|
||||
})
|
||||
res.end(JSON.stringify(backupData));
|
||||
});
|
||||
|
||||
|
||||
app.post(routes.import, function(req, res) {
|
||||
var fstream;
|
||||
req.pipe(req.busboy);
|
||||
req.busboy.on('file', function (fieldname, file, filename) {
|
||||
fstream = fs.createWriteStream(__dirname + '/crontabs/crontab.db');
|
||||
file.pipe(fstream);
|
||||
fstream.on('close', function () {
|
||||
|
||||
file.on('data', function(data) {
|
||||
crontab.restore_data(JSON.parse(data.toString('utf8')));
|
||||
crontab.reload_db();
|
||||
});
|
||||
});
|
||||
|
||||
req.busboy.on('finish', function() {
|
||||
res.redirect(routes.root);
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
app.get(routes.import_crontab, function(req, res) {
|
||||
crontab.import_crontab()
|
||||
|
@ -142,6 +176,8 @@ app.get(routes.logger, function(req, res) {
|
|||
res.end("No errors logged yet");
|
||||
})
|
||||
|
||||
app.listen(app.get('port'), function() {
|
||||
console.log("Crontab UI is running at localhost:" + app.get('port'))
|
||||
// app.use('/scripts/moment.js', express.static(__dirname + '/node_modules/moment/min/moment.min.js'));
|
||||
|
||||
app.listen(app.get('port'), app.get('listen'), function() {
|
||||
console.log("Crontab UI is running at " + app.get('listen') + ":" + app.get('port'))
|
||||
})
|
||||
|
|
127
crontab.js
127
crontab.js
|
@ -1,21 +1,29 @@
|
|||
//load database
|
||||
|
||||
exports.crontab_db_file = __dirname + '/crontabs/crontab.db';
|
||||
exports.templates_db_file = __dirname + '/crontabs/templates.db';
|
||||
|
||||
var Datastore = require('nedb');
|
||||
var db = new Datastore({ filename: __dirname + '/crontabs/crontab.db' });
|
||||
db.loadDatabase(function (err) {
|
||||
});
|
||||
var db = {
|
||||
crontabs: new Datastore({ filename: exports.crontab_db_file, autoload: true }),
|
||||
templates: new Datastore({ filename: exports.templates_db_file, autoload: true }),
|
||||
};
|
||||
var exec = require('child_process').exec;
|
||||
var fs = require('fs');
|
||||
var cron_parser = require("cron-parser")
|
||||
var os = require("os")
|
||||
var _ = require('underscore');
|
||||
|
||||
exports.log_folder = __dirname + '/crontabs/logs';
|
||||
exports.env_file = __dirname + '/crontabs/env.db';
|
||||
|
||||
crontab = function(name, command, schedule, stopped, logging){
|
||||
crontab = function(name, command, command_template, vars, schedule, stopped, logging){
|
||||
var data = {};
|
||||
data.name = name;
|
||||
data.command = command;
|
||||
data.command_template = command_template;
|
||||
data.schedule = schedule;
|
||||
data.vars = vars || {};
|
||||
if(stopped != null) {
|
||||
data.stopped = stopped;
|
||||
}
|
||||
|
@ -24,34 +32,88 @@ crontab = function(name, command, schedule, stopped, logging){
|
|||
return data;
|
||||
}
|
||||
|
||||
exports.create_new = function(name, command, schedule, logging){
|
||||
var tab = crontab(name, command, schedule, false, logging);
|
||||
crontab_template = function(name, command, schedule){
|
||||
var data = {};
|
||||
data.name = name;
|
||||
data.command = command;
|
||||
data.schedule = schedule;
|
||||
data.timestamp = (new Date()).toString();
|
||||
return data;
|
||||
}
|
||||
|
||||
exports.create_new = function(name, command, command_template, vars, schedule, logging){
|
||||
var tab = crontab(name, command, command_template, vars, schedule, false, logging);
|
||||
tab.created = new Date().valueOf();
|
||||
db.insert(tab);
|
||||
db.crontabs.insert(tab);
|
||||
}
|
||||
|
||||
exports.update = function(data){
|
||||
db.update({_id: data._id}, crontab(data.name, data.command, data.schedule, null, data.logging));
|
||||
db.crontabs.update({_id: data._id}, crontab(data.name, data.command, data.command_template, data.vars, data.schedule, null, data.logging));
|
||||
}
|
||||
|
||||
exports.status = function(_id, stopped){
|
||||
db.update({_id: _id},{$set: {stopped: stopped}});
|
||||
db.crontabs.update({_id: _id},{$set: {stopped: stopped}});
|
||||
}
|
||||
|
||||
exports.remove = function(_id){
|
||||
db.remove({_id: _id}, {});
|
||||
db.crontabs.remove({_id: _id}, {});
|
||||
}
|
||||
exports.crontabs = function(callback){
|
||||
db.find({}).sort({ created: -1 }).exec(function(err, docs){
|
||||
exports.crontabs = function(callback) {
|
||||
exports.templates(function(templates) {
|
||||
db.crontabs.find({}).sort({ name: 1 }).exec(function(err, docs){
|
||||
for(var i=0; i<docs.length; i++){
|
||||
if(docs[i].schedule == "@reboot")
|
||||
docs[i].next = "Next Reboot"
|
||||
else
|
||||
docs[i].next = cron_parser.parseExpression(docs[i].schedule).next().toString();
|
||||
var doc = docs[i];
|
||||
|
||||
if(doc.command_template) {
|
||||
var template = _.findWhere(templates, { _id: doc.command_template });
|
||||
|
||||
if(template) {
|
||||
doc.command = exports.renderTemplateCommand(template, doc);
|
||||
doc.schedule = template.schedule;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(doc.schedule == "@reboot")
|
||||
doc.next = "Next Reboot"
|
||||
else if(doc.schedule)
|
||||
doc.next = cron_parser.parseExpression(doc.schedule).next().toString();
|
||||
}
|
||||
callback(docs);
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
exports.templates = function(callback){
|
||||
db.templates.find({}).sort({ name: 1 }).exec(function(err, templates){
|
||||
callback(templates);
|
||||
});
|
||||
}
|
||||
|
||||
exports.renderTemplateCommand = function(template, cronjob) {
|
||||
var vars = cronjob.vars || {};
|
||||
|
||||
return template.command.replace(/{[a-zA-Z]+}/g, function(s) {
|
||||
return vars[s.substring(1, s.length - 1)] || 'undefined';
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
exports.create_new_template = function(name, command, schedule){
|
||||
var tab = crontab_template(name, command, schedule);
|
||||
tab.created = new Date().valueOf();
|
||||
db.templates.insert(tab);
|
||||
}
|
||||
|
||||
exports.update_template = function(data){
|
||||
db.templates.update({_id: data._id}, crontab_template(data.name, data.command, data.schedule));
|
||||
}
|
||||
|
||||
exports.remove_template = function(_id) {
|
||||
db.templates.remove({_id: _id}, {});
|
||||
}
|
||||
|
||||
exports.set_crontab = function(env_vars){
|
||||
exports.crontabs( function(tabs){
|
||||
var crontab_string = "";
|
||||
|
@ -108,18 +170,39 @@ exports.get_backup_names = function(){
|
|||
return backups;
|
||||
}
|
||||
|
||||
exports.backup = function(){
|
||||
exports.backup_data = function() {
|
||||
//TODO check if it failed
|
||||
fs.createReadStream( __dirname + '/crontabs/crontab.db').pipe(fs.createWriteStream( __dirname + '/crontabs/backup ' + (new Date()).toString().replace("+", " ") + '.db'));
|
||||
var crontabData = fs.readFileSync( exports.crontab_db_file ).toString('utf8')
|
||||
var templateData = fs.readFileSync( exports.templates_db_file ).toString('utf8')
|
||||
|
||||
return {
|
||||
version: 1,
|
||||
crontabs: crontabData,
|
||||
templates: templateData,
|
||||
};
|
||||
}
|
||||
|
||||
exports.backup = function(){
|
||||
var backupFile = __dirname + '/crontabs/backup ' + (new Date()).toString().replace("+", " ") + '.db';
|
||||
|
||||
fs.writeFileSync(backupFile, JSON.stringify(exports.backup_data()));
|
||||
}
|
||||
|
||||
exports.restore = function(db_name){
|
||||
fs.createReadStream( __dirname + '/crontabs/' + db_name).pipe(fs.createWriteStream( __dirname + '/crontabs/crontab.db'));
|
||||
db.loadDatabase(); // reload the database
|
||||
exports.restore_data(JSON.parse(fs.readFileSync( __dirname + '/crontabs/' + db_name )))
|
||||
}
|
||||
|
||||
exports.reload_db= function(){
|
||||
db.loadDatabase();
|
||||
exports.restore_data = function(backupData) {
|
||||
fs.writeFileSync(exports.crontab_db_file, backupData.crontabs);
|
||||
fs.writeFileSync(exports.templates_db_file, backupData.templates);
|
||||
|
||||
db.crontabs.loadDatabase(); // reload the database
|
||||
db.templates.loadDatabase();
|
||||
}
|
||||
|
||||
exports.reload_db = function(){
|
||||
db.crontabs.loadDatabase();
|
||||
db.templates.loadDatabase();
|
||||
}
|
||||
|
||||
exports.get_env = function(){
|
||||
|
|
|
@ -7,13 +7,16 @@
|
|||
"start": "node app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "latest",
|
||||
"ejs": "latest",
|
||||
"nedb": "latest",
|
||||
"body-parser": "latest",
|
||||
"mime": "latest",
|
||||
"connect-busboy": "latest",
|
||||
"cron-parser": "latest",
|
||||
"connect-busboy": "latest"
|
||||
"ejs": "latest",
|
||||
"express": "latest",
|
||||
"mime": "latest",
|
||||
"moment": "^2.13.0",
|
||||
"nedb": "latest",
|
||||
"tmp": "0.0.28",
|
||||
"underscore": "^1.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "latest"
|
||||
|
|
|
@ -60,9 +60,11 @@ function editJob(_id){
|
|||
job = crontab;
|
||||
});
|
||||
if(job){
|
||||
current_job = job;
|
||||
$("#job").modal("show");
|
||||
$("#job-name").val(job.name);
|
||||
$("#job-command").val(job.command);
|
||||
$("#job-command-template").val(job.command_template);
|
||||
// if macro not used
|
||||
if(job.schedule.indexOf("@") != 0){
|
||||
var components = job.schedule.split(" ");
|
||||
|
@ -74,22 +76,87 @@ function editJob(_id){
|
|||
}
|
||||
schedule = job.schedule;
|
||||
job_command = job.command;
|
||||
console.log(job.logging)
|
||||
if (job.logging && job.logging != "false")
|
||||
$("#job-logging").prop("checked", true);
|
||||
job_string();
|
||||
setTemplateVariables(job.command_template);
|
||||
} else {
|
||||
setTemplateVariables(null);
|
||||
}
|
||||
|
||||
$("#job-save").unbind("click"); // remove existing events attached to this
|
||||
$("#job-save").click(function(){
|
||||
// TODO good old boring validations
|
||||
$.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: _id, logging: $("#job-logging").prop("checked")}, function(){
|
||||
$.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: _id, logging: $("#job-logging").prop("checked"), command_template: $('#job-command-template').val(), vars: current_job.vars }, function(){
|
||||
location.reload();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function findTemplate(templateId) {
|
||||
var template = null;
|
||||
|
||||
templates.forEach(function(tmpl) {
|
||||
if(tmpl._id == templateId) {
|
||||
template = tmpl;
|
||||
}
|
||||
});
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
function setTemplateVariables(templateId) {
|
||||
var template = findTemplate(templateId);
|
||||
|
||||
$('#job-command-variables-wrapper').toggle(!!template);
|
||||
$('#job-command-wrapper').toggle(!template);
|
||||
|
||||
if(template) {
|
||||
job_command = renderTemplateCommand(templateId);
|
||||
schedule = template.schedule;
|
||||
|
||||
var $jobVariables = $('#job-variables-list').empty(),
|
||||
vars = current_job.vars || {};
|
||||
|
||||
findCommandVariables(template.command).forEach(function(varName) {
|
||||
|
||||
var $input = $('<input type="text" class="form-control job-variables" />').val(vars[varName]);
|
||||
|
||||
$jobVariables.append('<label>'+varName+'</label>');
|
||||
$jobVariables.append($input);
|
||||
$jobVariables.append('<br />');
|
||||
|
||||
$input.change(function() {
|
||||
current_job.vars = current_job.vars || {};
|
||||
current_job.vars[varName] = $(this).val();
|
||||
})
|
||||
})
|
||||
|
||||
} else {
|
||||
job_command = $('#job-command').val();
|
||||
}
|
||||
|
||||
job_string();
|
||||
}
|
||||
|
||||
function findCommandVariables (command) {
|
||||
return command.match(/{[a-zA-Z]+}/g).map(function(cmd) {
|
||||
return cmd.substring(1, cmd.length - 1);
|
||||
});
|
||||
};
|
||||
|
||||
function renderTemplateCommand(templateId) {
|
||||
var template = findTemplate(templateId);
|
||||
|
||||
if(template) {
|
||||
return template.command;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function newJob(){
|
||||
current_job = {};
|
||||
schedule = ""
|
||||
job_command = ""
|
||||
$("#job-minute").val("*");
|
||||
|
@ -101,14 +168,17 @@ function newJob(){
|
|||
$("#job").modal("show");
|
||||
$("#job-name").val("");
|
||||
$("#job-command").val("");
|
||||
$("#job-command-template").val("");
|
||||
job_string();
|
||||
$("#job-save").unbind("click"); // remove existing events attached to this
|
||||
$("#job-save").click(function(){
|
||||
// TODO good old boring validations
|
||||
$.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: -1, logging: $("#job-logging").prop("checked")}, function(){
|
||||
$.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: -1, logging: $("#job-logging").prop("checked"), command_template: $('#job-command-template').val(), vars: current_job.vars }, function(){
|
||||
location.reload();
|
||||
})
|
||||
});
|
||||
|
||||
setTemplateVariables(null);
|
||||
}
|
||||
|
||||
function doBackup(){
|
||||
|
@ -145,6 +215,7 @@ function import_db(){
|
|||
// script corresponding to job popup management
|
||||
var schedule = "";
|
||||
var job_command = "";
|
||||
var current_job = null;
|
||||
function job_string(){
|
||||
$("#job-string").val(schedule + " " + job_command);
|
||||
return schedule + " " + job_command;
|
||||
|
@ -155,3 +226,83 @@ function set_schedule(){
|
|||
job_string();
|
||||
}
|
||||
// popup management ends
|
||||
|
||||
|
||||
/**************** Template Action s***************/
|
||||
|
||||
function newTemplate(){
|
||||
schedule = ""
|
||||
template_command = ""
|
||||
$("#template-minute").val("*");
|
||||
$("#template-hour").val("*");
|
||||
$("#template-day").val("*");
|
||||
$("#template-month").val("*");
|
||||
$("#template-week").val("*");
|
||||
|
||||
$("#template-popup").modal("show");
|
||||
$("#template-name").val("");
|
||||
$("#template-command").val("");
|
||||
template_string();
|
||||
$("#template-save").unbind("click"); // remove existing events attached to this
|
||||
$("#template-save").click(function(){
|
||||
// TODO good old boring validations
|
||||
$.post(routes.save_template, {name: $("#template-name").val(), command: template_command , schedule: schedule, _id: -1}, function(){
|
||||
location.reload();
|
||||
})
|
||||
});
|
||||
|
||||
$('#template-remove').unbind('click').hide();
|
||||
}
|
||||
|
||||
function editTemplate(_id){
|
||||
var template = findTemplate(_id);
|
||||
if(template){
|
||||
$("#template-popup").modal("show");
|
||||
$("#template-name").val(template.name);
|
||||
$("#template-command").val(template.command);
|
||||
|
||||
// if macro not used
|
||||
if(template.schedule && template.schedule.indexOf("@") != 0){
|
||||
var components = template.schedule.split(" ");
|
||||
$("#template-minute").val(components[0]);
|
||||
$("#template-hour").val(components[1]);
|
||||
$("#template-day").val(components[2]);
|
||||
$("#template-month").val(components[3]);
|
||||
$("#template-week").val(components[4]);
|
||||
}
|
||||
schedule = template.schedule;
|
||||
template_command = template.command;
|
||||
|
||||
template_string();
|
||||
}
|
||||
|
||||
$("#template-save").unbind("click"); // remove existing events attached to this
|
||||
$("#template-save").click(function(){
|
||||
// TODO good old boring validations
|
||||
$.post(routes.save_template, {name: $("#template-name").val(), command: template_command , schedule: schedule, _id: _id}, function(){
|
||||
location.reload();
|
||||
})
|
||||
});
|
||||
|
||||
$('#template-remove')
|
||||
.show()
|
||||
.unbind('click')
|
||||
.click(function() {
|
||||
if(window.confirm('Are you sure you want to delete this template?')) {
|
||||
$.post(routes.remove_template, {_id:_id}, function() {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function set_template_schedule(){
|
||||
schedule = $("#template-minute").val() + " " +$("#template-hour").val() + " " +$("#template-day").val() + " " +$("#template-month").val() + " " +$("#template-week").val();
|
||||
template_string();
|
||||
}
|
||||
|
||||
function template_string(){
|
||||
$("#template-string").val(schedule + " " + template_command);
|
||||
return schedule + " " + template_command;
|
||||
}
|
||||
|
|
33
restore.js
33
restore.js
|
@ -3,15 +3,34 @@ var Datastore = require('nedb');
|
|||
|
||||
var exec = require('child_process').exec;
|
||||
var fs = require('fs');
|
||||
var tmp = require('tmp');
|
||||
|
||||
exports.crontabs = function(db_name, callback){
|
||||
var db = new Datastore({ filename: __dirname + '/crontabs/' + db_name });
|
||||
db.loadDatabase(function (err) {
|
||||
exports.loadBackupFile = function(db_name, callback) {
|
||||
|
||||
console.log(__dirname + '/crontabs/' + db_name);
|
||||
|
||||
var backupFileData = fs.readFileSync(__dirname + '/crontabs/' + db_name).toString('utf8');
|
||||
console.log(backupFileData);
|
||||
var data = JSON.parse(backupFileData);
|
||||
|
||||
|
||||
var crontabFile = tmp.fileSync();
|
||||
var templateFile = tmp.fileSync();
|
||||
|
||||
fs.writeFileSync(crontabFile.name, data.crontabs);
|
||||
fs.writeFileSync(templateFile.name, data.templates);
|
||||
|
||||
var crontabDB = new Datastore({ filename: crontabFile.name , autoload: true });
|
||||
var templateDB = new Datastore({ filename: templateFile.name , autoload: true });
|
||||
|
||||
crontabDB.find({}).sort({ created: -1 }).exec(function(err, docs){
|
||||
templateDB.find({}).sort({ name: 1 }).exec(function(err, templates) {
|
||||
|
||||
callback(docs, templates);
|
||||
})
|
||||
});
|
||||
db.find({}).sort({ created: -1 }).exec(function(err, docs){
|
||||
callback(docs);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.delete = function(db_name){
|
||||
fs.unlink(__dirname + '/crontabs/' + db_name);
|
||||
|
|
|
@ -13,4 +13,6 @@ exports.routes = {
|
|||
"import": "/import", // this is import from database
|
||||
"import_crontab": "/import_crontab", // this is from existing crontab
|
||||
"logger": "/logger",
|
||||
"save_template" : "/save_template",
|
||||
"remove_template" : "/remove_template",
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
<script src="jquery.js"></script>
|
||||
<script src="script.js"></script>
|
||||
<script src="bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/v/bs/dt-1.10.12/datatables.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.12/css/dataTables.bootstrap.min.css"/>
|
||||
<script type="text/javascript">
|
||||
var crontabs = [];
|
||||
var routes = [];
|
||||
|
@ -12,6 +15,7 @@
|
|||
// initialize tooltips
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
crontabs = JSON.parse('<%- crontabs.replace(/\\\\/g, "\\\\\\\\").replace(/\\\"/g,"\\\\\"") %>');
|
||||
templates = <%- JSON.stringify(templates) %>;
|
||||
routes = JSON.parse('<%- routes %>');
|
||||
$("#env_vars").val(`<%- env %>`);
|
||||
})
|
||||
|
@ -37,15 +41,18 @@
|
|||
<br/>
|
||||
<br/>
|
||||
|
||||
<table class="table">
|
||||
<table class="table table-striped" id="main_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th></th>
|
||||
<th>#</th>
|
||||
<th>Name</th>
|
||||
<th>Job</th>
|
||||
<th>Time</th>
|
||||
<th>Last Modified</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% var index = 1 %>
|
||||
<% JSON.parse(crontabs).forEach(function(crontab){ %>
|
||||
<!-- color based on crontab state -->
|
||||
|
@ -57,17 +64,33 @@
|
|||
<td>
|
||||
<%= index %>.
|
||||
<% index += 1 %>
|
||||
<%= crontab._id %>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
|
||||
<% if (crontab.name) { %>
|
||||
<a class="btn" data-toggle="tooltip" data-placement="right" title="<%= crontab.name %>"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> </a>
|
||||
<%= crontab.name %>
|
||||
<a class="btn" data-toggle="tooltip" data-placement="right" title="<%= crontab._id %>"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> </a>
|
||||
<% } else { %>
|
||||
<%= crontab._id %>
|
||||
<% } %>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<% if(crontab.command_template && templatesById[crontab.command_template]) { %>
|
||||
<%= templatesById[crontab.command_template].name %>
|
||||
|
||||
<a class="btn" data-toggle="tooltip" data-placement="right" title="<%= crontab.command %>"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> </a>
|
||||
<% } else { %>
|
||||
<%= crontab.command %>
|
||||
<% } %>
|
||||
|
||||
|
||||
</td>
|
||||
<td><%= crontab.command %></td>
|
||||
<td><span style="cursor:pointer" data-toggle="tooltip" data-placement="bottom" title="<%= crontab.next %>"><%= crontab.schedule %></span></td>
|
||||
<td style="width:20%"><%= crontab.timestamp %></td>
|
||||
<td style="width:20%" title="<%= crontab.timestamp %>"><%= moment(new Date(crontab.timestamp)).fromNow() %></td>
|
||||
<td>
|
||||
|
||||
<!-- controls based on crontab state -->
|
||||
|
@ -86,10 +109,25 @@
|
|||
</tr>
|
||||
<% }); %>
|
||||
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
<% include popup.ejs %>
|
||||
<script>
|
||||
jQuery(function($) {
|
||||
$('#main_table').DataTable({
|
||||
order: [1, 'asc'],
|
||||
columns: [
|
||||
{orderable: false},
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{orderable: false},
|
||||
{orderable: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,6 +14,20 @@
|
|||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Templates <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<% if (templates.length > 0){ %>
|
||||
|
||||
<% templates.forEach(function(template){ %>
|
||||
<li><a onclick="editTemplate('<%= template._id %>')"><%= template.name %></a></li>
|
||||
<% }) %>
|
||||
<li class="divider"></li>
|
||||
|
||||
<% } %>
|
||||
<li><a onclick="newTemplate();"><i class="fa fa-plus"></i> Add Template</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Backups <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
|
|
|
@ -42,8 +42,18 @@
|
|||
<div class="modal-body" id="job-body">
|
||||
<label>Name (Optional)</label>
|
||||
<input type='text' class='form-control' id='job-name'/><br />
|
||||
<label>Command Template</label>
|
||||
<select id="job-command-template" class="form-control" onchange="setTemplateVariables(this.value)">
|
||||
<option value="">No Template</option>
|
||||
<% templates.forEach(function(template) { %>
|
||||
<option value="<%= template._id %>"><%= template.name %></option>
|
||||
<% }) %>
|
||||
</select><br />
|
||||
|
||||
<div id="job-command-wrapper">
|
||||
<label>Command</label>
|
||||
<input type='text' class='form-control' id='job-command' onkeyup="job_command = $(this).val(); job_string();"/><br />
|
||||
|
||||
<label>Quick Schedule</label><br />
|
||||
<a class="btn btn-primary" onclick="schedule = '@reboot'; job_string();">Startup</a>
|
||||
<a class="btn btn-primary" onclick="schedule = '@hourly'; job_string();">Hourly</a>
|
||||
|
@ -70,6 +80,17 @@
|
|||
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
<div id="job-command-variables-wrapper" style="display: none">
|
||||
<label>Command Variables</label>
|
||||
|
||||
<div id="job-variables-list">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<label>Job</label>
|
||||
<input type='text' class='form-control' id='job-string' disabled='disabled'/><br />
|
||||
<label><input type="checkbox" id="job-logging" style="position:relative;top:2px"/> Enable error logging.</label>
|
||||
|
@ -81,3 +102,55 @@
|
|||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- Template -->
|
||||
<div class="modal fade" id="template-popup">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="template-title">Template</h4>
|
||||
</div>
|
||||
<div class="modal-body" id="template-body">
|
||||
<label>Name</label>
|
||||
<input type='text' class='form-control' id='template-name'/><br />
|
||||
<label>Command</label>
|
||||
<input type='text' class='form-control' id='template-command' onkeyup="template_command = $(this).val(); template_string();"/><br />
|
||||
<label>Quick Schedule</label><br />
|
||||
<a class="btn btn-primary" onclick="schedule = '@reboot'; template_string();">Startup</a>
|
||||
<a class="btn btn-primary" onclick="schedule = '@hourly'; template_string();">Hourly</a>
|
||||
<a class="btn btn-primary" onclick="schedule = '@daily'; template_string();">Daily</a>
|
||||
<a class="btn btn-primary" onclick="schedule = '@weekly'; template_string();">Weekly</a>
|
||||
<a class="btn btn-primary" onclick="schedule = '@monthly'; template_string();">Monthly</a>
|
||||
<a class="btn btn-primary" onclick="schedule = '@yearly'; template_string();">Yearly</a><br /><br />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-2">Minute</div>
|
||||
<div class="col-md-2">Hour</div>
|
||||
<div class="col-md-2">Day</div>
|
||||
<div class="col-md-2">Month</div>
|
||||
<div class="col-md-2">Week</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2"><input type="text" class="form-control" id="template-minute" value="*" onclick="this.select();"/></div>
|
||||
<div class="col-md-2"><input type="text" class="form-control" id="template-hour" value="*" onclick="this.select();"/></div>
|
||||
<div class="col-md-2"><input type="text" class="form-control" id="template-day" value="*" onclick="this.select();"/></div>
|
||||
<div class="col-md-2"><input type="text" class="form-control" id="template-month" value="*" onclick="this.select();"/></div>
|
||||
<div class="col-md-2"><input type="text" class="form-control" id="template-week" value="*" onclick="this.select();"/></div>
|
||||
<div class="col-md-2"><a class="btn btn-primary" onclick="set_template_schedule();">Set</a></div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<label>Job</label>
|
||||
<input type='text' class='form-control' id='template-string' disabled='disabled'/><br />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal" id="template-remove">Delete Template</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal" id="template-save">Save</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
|
Loading…
Reference in New Issue