diff --git a/Duplicati/Server/webroot/index.html b/Duplicati/Server/webroot/index.html
index c50e3d535..0d283d93e 100644
--- a/Duplicati/Server/webroot/index.html
+++ b/Duplicati/Server/webroot/index.html
@@ -33,17 +33,17 @@
${Name}
- Source
- - ${SourceSizeString}
+ - ${Metadata.SourceSizeString}
- Backup
- - ${TargetSizeString}
+ - ${Metadata.TargetSizeString}
- - Backup
- - Restore
- - Edit
- - Delete
+ - Backup
+ - Restore
+ - Edit
+ - Delete
diff --git a/Duplicati/Server/webroot/scripts/app.js b/Duplicati/Server/webroot/scripts/app.js
index 721f4b30e..06a7873fd 100644
--- a/Duplicati/Server/webroot/scripts/app.js
+++ b/Duplicati/Server/webroot/scripts/app.js
@@ -137,7 +137,9 @@ $(document).ready(function() {
plugins: {
backend: {},
compression: {},
- encryption: {}
+ encryption: {},
+ primary: {}
+
}
};
@@ -212,12 +214,55 @@ $(document).ready(function() {
// Clear existing stuff
$('#main-list-container > div.main-backup-entry').remove();
- if ($('#backup-item-template').length > 0 && data.length > 0)
+
+ if ($('#backup-item-template').length > 0 && data.length > 0) {
+
+ // Pre-processing of data
+ for(var n in data) {
+ var b = data[n];
+ b.Metadata = b.Metadata || {};
+
+ if (!b.Metadata['TargetSizeString'])
+ b.Metadata['TargetSizeString'] = '< unknown >'
+ if (!b.Metadata['SourceSizeString'])
+ b.Metadata['SourceSizeString'] = '< unknown >'
+ }
+
+ if (APP_DATA.plugins.primary['backup-list-preprocess'])
+ APP_DATA.plugins.primary['backup-list-preprocess'](data);
+
+ //Fill with jQuery template
$.tmpl($('#backup-item-template'), data).prependTo($('#main-list-container'));
- //Fill with jQuery template
- if (callback != null)
+ // Post processing of data
+ for(var n in data) {
+ var id = data[n].ID;
+
+ $('#backup-details-run-' + id).click(function() {
+ APP_DATA.runBackup(id);
+ });
+
+ $('#backup-details-restore-' + id).click(function() {
+ APP_DATA.restoreBackup(id);
+ });
+
+ $('#backup-details-edit-' + id).click(function() {
+ APP_DATA.editBackup(id);
+ });
+
+ $('#backup-details-delete-' + id).click(function() {
+ APP_DATA.deleteBackup(id);
+ });
+
+ }
+
+ if (APP_DATA.plugins.primary['backup-list-postrocess'])
+ APP_DATA.plugins.primary['backup-list-postrocess']($('#main-list-container'), $('#main-list-container > div.main-backup-entry'), data);
+
+ }
+
+ if (callback)
callback(PRIVATE_DATA.backup_list);
})
.fail(function(data, status) {
@@ -228,6 +273,38 @@ $(document).ready(function() {
PRIVATE_DATA.refresh_server_settings();
PRIVATE_DATA.refresh_backup_list();
+ var serverWithCallback = function(data, callback, errorhandler, refreshMethod) {
+ if (typeof(data) == typeof(''))
+ data = { action: data };
+
+ var method = 'GET';
+ if (data.HTTP_METHOD) {
+ method = data.HTTP_METHOD;
+ delete data.HTTP_METHOD;
+ }
+
+ $.ajax({
+ url: APP_CONFIG.server_url,
+ type: method,
+ dataType: 'json',
+ data: data
+ })
+ .done(function(data) {
+ if (refreshMethod)
+ refreshMethod(data, true, null);
+
+ if (callback != null)
+ callback(data, true, null);
+ })
+ .fail(function(data, status) {
+ if (refreshMethod)
+ refreshMethod(data, false, data.statusText);
+
+ if (errorhandler)
+ errorhandler(data, false, data.statusText);
+ });
+ };
+
APP_DATA.getServerConfig = function(callback, errorhandler) {
if (PRIVATE_DATA.server_config == null) {
@@ -237,90 +314,86 @@ $(document).ready(function() {
}
};
- APP_DATA.validatePath = function(path, callback) {
- $.ajax({
- url: APP_CONFIG.server_url,
- dataType: 'json',
- data: { action: 'validate-path', path: path }
- })
- .done(function(data) {
- if (callback != null)
- callback(path, true, null);
- })
- .fail(function(data, status) {
- if (callback)
- callback(path, false, data.statusText);
- });
+ APP_DATA.validatePath = function(path, callback) {
+ serverWithCallback({ action: 'validate-path', path: path }, callback, callback);
+ };
+ APP_DATA.getLabels = function(callback) {
+ serverWithCallback('list-tags', callback, callback);
};
- APP_DATA.getLabels = function(callback) {
- $.ajax({
- url: APP_CONFIG.server_url,
- dataType: 'json',
- data: { action: 'list-tags' }
- })
- .done(function(data) {
- if (callback != null)
- callback(data, true, null);
- })
- .fail(function(data, status) {
- if (callback)
- callback(null, false, data.statusText);
- });
+ APP_DATA.getBackupDefaults = function(callback, errorhandler) {
+ serverWithCallback('get-backup-defaults', callback, errorhandler);
};
-
- APP_DATA.getBackupDefaults = function(callback, errorhandler) {
- $.ajax({
- url: APP_CONFIG.server_url,
- dataType: 'json',
- data: { action: 'get-backup-defaults' }
- })
- .done(function(data) {
- if (callback != null)
- callback(data, true, null);
- })
- .fail(function(data, status) {
- if (errorhandler)
- errorhandler(null, false, data.statusText);
- });
+ APP_DATA.getBackupData = function(id, callback, errorhandler) {
+ serverWithCallback({ action: 'get-backup', id: id}, callback, errorhandler);
};
APP_DATA.addBackup = function(cfg, callback, errorhandler) {
- $.ajax({
- url: APP_CONFIG.server_url,
- type: 'POST',
- dataType: 'json',
- data: { action: 'add-backup', data: JSON.stringify(cfg) }
- })
- .done(function(data) {
- PRIVATE_DATA.refresh_backup_list();
- if (callback != null)
- callback(data, true, null);
- })
- .fail(function(data, status) {
- PRIVATE_DATA.refresh_backup_list();
- if (errorhandler)
- errorhandler(null, false, data.statusText);
- });
+ serverWithCallback(
+ { action: 'add-backup', HTTP_METHOD: 'POST', data: JSON.stringify(cfg)},
+ callback,
+ errorhandler,
+ function() { PRIVATE_DATA.refresh_backup_list(); }
+ );
};
APP_DATA.updateBackup = function(cfg, callback, errorhandler) {
- $.ajax({
- url: APP_CONFIG.server_url,
- type: 'POST',
- dataType: 'json',
- data: { action: 'update-backup', data: JSON.stringify(cfg) }
- })
- .done(function(data) {
- PRIVATE_DATA.refresh_backup_list();
- if (callback != null)
- callback(data, true, null);
- })
- .fail(function(data, status) {
- PRIVATE_DATA.refresh_backup_list();
- if (errorhandler)
- errorhandler(null, false, data.statusText);
- });
+ serverWithCallback(
+ { action: 'update-backup', HTTP_METHOD: 'POST', data: JSON.stringify(cfg)},
+ callback,
+ errorhandler,
+ function() { PRIVATE_DATA.refresh_backup_list(); }
+ );
+ };
+
+
+ APP_DATA.editNewBackup = function() {
+ APP_DATA.editBackup();
+ };
+
+ APP_DATA.deleteBackup = function(id, callback, errorhandler) {
+ serverWithCallback(
+ { action: 'delete-backup', id: id },
+ callback,
+ errorhandler,
+ function() { PRIVATE_DATA.refresh_backup_list(); }
+ );
+ };
+
+ APP_DATA.editBackup = function(id) {
+ APP_DATA.getServerConfig(function(data) {
+
+ var callback = function(data) {
+ $("#edit-dialog").dialog('open');
+
+ // Bug-fix, this will remove style="width: auto", which breaks Chrome a bit
+ $("#edit-dialog").css('width', '');
+
+ // Send the defaults to the dialog
+ $("#edit-dialog").trigger('setup-dialog', data.data);
+ };
+
+ var errorhandler = function() {
+ alert('Failed to get server setup...')
+ };
+
+ if (id == undefined || parseInt(id) < 0)
+ APP_DATA.getBackupDefaults(callback, errorhandler);
+ else
+ APP_DATA.getBackupData(id, callback, errorhandler);
+ },
+ function() {
+ alert('Failed to get server setup...')
+ });
+
+ };
+
+ APP_DATA.runBackup = function(id) {
+
+ };
+
+ APP_DATA.restoreBackup = function(id) {
+
};
$('#main-settings').click(function() {
@@ -345,23 +418,7 @@ $(document).ready(function() {
});
$('#main-newbackup').click(function() {
- APP_DATA.getServerConfig(function(data) {
- APP_DATA.getBackupDefaults(function(defaults) {
- $("#edit-dialog").dialog('open');
-
- // Bug-fix, this will remove style="width: auto", which breaks Chrome a bit
- $("#edit-dialog").css('width', '');
-
- // Send the defaults to the dialog
- $("#edit-dialog").trigger('setup-dialog', defaults.data);
- },
- function() {
- alert('Failed to get server setup...')
- })
- },
- function() {
- alert('Failed to get server setup...')
- });
+ APP_DATA.editNewBackup();
});
diff --git a/Duplicati/Server/webroot/scripts/editdialog.js b/Duplicati/Server/webroot/scripts/editdialog.js
index 5fae1f2c2..c82b3c179 100644
--- a/Duplicati/Server/webroot/scripts/editdialog.js
+++ b/Duplicati/Server/webroot/scripts/editdialog.js
@@ -108,6 +108,15 @@ $(document).ready(function() {
},
'edit-tab-schedule': function(tabindex) {
+ if ($('#use-scheduled-run').is(':checked')) {
+ var t = Date.parse($('#next-run-date').val() + 'T' + $('#next-run-time').val());
+ if (isNaN(t)) {
+ $('#edit-dialog').tabs( "option", "active", tabindex);
+ $('#next-run-time').focus();
+ alert('You must enter a valid time');
+ return false;
+ }
+ }
return true;
}
@@ -115,6 +124,23 @@ $(document).ready(function() {
fill_form_map: {
'encryption-module': 'encryption-method',
+ 'Name': 'backup-name',
+ 'TargetURL': 'backup-uri',
+ 'passphrase': function(dict, key, val, cfgel) {
+ $('#encryption-password').val(val);
+ $('#repeat-password').val(val);
+ },
+ 'Sources': function(dict, key, val, cfgel) {
+ var sources = val || [];
+
+ $('#source-folder-paths').find('.source-folder').empty();
+ for(var n in sources)
+ addSourceFolder(sources[n]);
+ },
+ 'Tags': function(dict, key, val, cfgel) {
+ var tags = val || [];
+ $('#backup-labels').val(tags.join(', '));
+ },
'Schedule': function(dict, key, val, cfgel) {
$('#use-scheduled-run').attr('checked', val != null)
},
@@ -157,30 +183,48 @@ $(document).ready(function() {
}
},
'Time': function(dict, key, val, cfgel) {
- $('#next-run-time').val(val);
- if (!dict['Date']) {
- var parts = val.split(':');
- var now = new Date();
- while(parts.length < 3)
- parts.push('00');
+ var parts = val.split(':');
+ var now = new Date();
+ var msec = Date.parse(val);
+ if (isNaN(msec))
+ msec = Date.parse("1970-01-01T" + val);
- var d = new Date(now.getFullYear(), now.getMonth(), now.getDate(), parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]))
- if (d < now)
- d.setDate(d.getDate()+1);
+ var d = null;
+ if (isNaN(msec)) {
+ d = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 13, 0, 0);
- var y = d.getFullYear() + '';
- var m = d.getMonth() + '';
- var n = d.getDate() + '';
- if (m.length == 1)
- m = '0' + m;
- if (n.length == 1)
- n = '0' + n;
-
- $('#next-run-date').val(y + '-' + m + '-' + n);
+ $('#next-run-time').val('13:00');
+ $('#next-run-date').val(now);
+ } else {
+ d = new Date(msec);
+ if (d.getFullYear() <= 1970) {
+ msec += new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0).getTime();
+ d = new Date(msec);
+ }
}
- },
- 'Date': function(dict, key, val, cfgel) {
- $('#next-run-date').val(val);
+
+ var y = d.getFullYear() + '';
+ var m = (d.getMonth() + 1) + '';
+ var n = d.getDate() + '';
+
+ var h = d.getHours() + '';
+ var l = d.getMinutes() + '';
+ var s = d.getSeconds() + '';
+
+ if (m.length == 1)
+ m = '0' + m;
+ if (n.length == 1)
+ n = '0' + n;
+ if (h.length == 1)
+ h = '0' + h;
+ if (l.length == 1)
+ l = '0' + l;
+ if (s.length == 1)
+ s = '0' + s;
+
+ $('#next-run-date').val(y + '-' + m + '-' + n);
+ $('#next-run-time').val(h + ':' + l + ':' + s);
+
},
'AllowedDays': function(dict, key, val, cfgel) {
@@ -221,6 +265,7 @@ $(document).ready(function() {
'repeat-password': false,
'dblock-size-multiplier': false,
'repeat-run-multiplier': false,
+ 'next-run-date': false,
'allow-day-mon': false,
'allow-day-tue': false,
'allow-day-wed': false,
@@ -273,13 +318,13 @@ $(document).ready(function() {
if (!dict['Schedule'])
return;
- dict['Schedule']['Time'] = $(el).val();
- },
- 'next-run-date': function(dict, key, el, cfgel) {
- if (!dict['Schedule'])
- return;
+ var t = Date.parse($('#next-run-date').val() + 'T' + $('#next-run-time').val());
+ if (t != NaN) {
+ var d = new Date(t);
- dict['Schedule']['Date'] = $(el).val();
+ //TODO: Not correct UTC, returns GMT instead
+ dict['Schedule']['Time'] = d.toUTCString();
+ }
},
'dblock-size-number': function(dict, key, el, cfgel) {
dict['Backup']['Settings']['dblock-size'] = $(el).val() + $('#dblock-size-multiplier').val();
@@ -293,7 +338,7 @@ $(document).ready(function() {
dict['Schedule']['Repeat'] = $(el).val();
else
dict['Schedule']['Repeat'] = $(el).val() + m;
- },
+ }
}
};
@@ -303,6 +348,7 @@ $(document).ready(function() {
$('#encryption-password').watermark('Enter a secure passphrase');
$('#repeat-password').watermark('Repeat the passphrase');
$('#backup-options').watermark('Enter one option pr. line in commandline format, eg. --dblock-size=100MB');
+ $('#source-folder-path-text').watermark('Enter a path to back up');
var updateState = function() { if (EDIT_STATE != null) EDIT_STATE.dataModified = true; };
@@ -536,6 +582,8 @@ $(document).ready(function() {
APP_DATA.getLabels(function(labels) {
EDIT_STATE.tags = labels;
});
+
+ $('#edit-dialog').tabs('option', 'active', 0);
});
$('#encryption-method').change(function() {
@@ -578,7 +626,7 @@ $(document).ready(function() {
$.extend(true, obj, EDIT_STATE.orig_config);
APP_UTIL.read_form($('#edit-dialog-form'), EDIT_BACKUP.fill_dict_map, obj);
- if (!APP_UTIL.parseOptionStrings($('#backup-options').val(), obj, function() {
+ if (!APP_UTIL.parseOptionStrings($('#backup-options').val(), obj.Backup.Settings, function() {
//TODO: Add validation
return true;
})) {
@@ -701,13 +749,31 @@ $(document).ready(function() {
}
$("#edit-dialog").on('setup-dialog', function(e, data) {
+ if (data.Backup && data.Backup.ID && parseInt(data.Backup.ID) > 0) {
+ EDIT_STATE.orig_config = data;
+ EDIT_STATE.newBackup = false;
+ } else {
+ EDIT_STATE.orig_config = null;
+ EDIT_STATE.newBackup = true;
+ }
+
if (data['Schedule'] == null || data['Schedule']['Repeat'] == null || data['Schedule']['Repeat'] == '')
APP_UTIL.fill_form($('#edit-dialog-form'), { 'Schedule': null }, EDIT_BACKUP.fill_form_map, 'Schedule');
else
APP_UTIL.fill_form($('#edit-dialog-form'), data['Schedule'], EDIT_BACKUP.fill_form_map, 'Schedule');
+ // Convert from list-form to key/value map
+ var orig = data['Backup'].Settings;
+ var settings = {};
+ data['Backup'].Settings = settings;
+ for(var n in orig)
+ settings[orig[n].Name] = orig[n].Value;
+
+ APP_UTIL.fill_form($('#edit-dialog-form'), data['Backup'], EDIT_BACKUP.fill_form_map, d);
+
for(var d in data['Backup'])
- APP_UTIL.fill_form($('#edit-dialog-form'), data['Backup'][d], EDIT_BACKUP.fill_form_map, d);
+ if (typeof(data['Backup'][d]) == typeof({}))
+ APP_UTIL.fill_form($('#edit-dialog-form'), data['Backup'][d], EDIT_BACKUP.fill_form_map, d);
});
/*