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}
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); }); /*