Files
duplicati/Duplicati/Server/webroot/scripts/restoredialog.js
T

702 lines
22 KiB
JavaScript

$(document).ready(function() {
var curpage = 0;
var backupId = 0;
var dirSep = '/';
var pathSep = ':';
var trees = { };
var searchdata = {};
var nodedata = {};
var missingfiles = null;
var missingfiles_search = null;
var performRestore = function(tasks) {
var dlg = $('<div></div>').attr('title', 'Restoring files ...');
dlg.dialog({
autoOpen: true,
modal: true,
closeOnEscape: false
});
dlg.parent().find('.ui-dialog-titlebar-close').remove().first().remove();
var pg = $('<div></div>');
pg.progressbar({ value: false });
var pgtxt = $('<div></div>');
pgtxt.text('Sending jobs to server ...');
dlg.append(pg);
dlg.append(pgtxt);
var onAllRestoresCompleted = function() {
$(document).off('server-progress-updated', serverProgressUpdateMethod);
$(document).off('server-state-updated', serverStateUpdateMethod);
curpage = Math.min(2, curpage+1);
updatePageNav();
dlg.dialog('close');
dlg.remove();
};
var currentProgressTask = null;
var remainingTasks = tasks.length;
var serverProgressUpdateMethod = function(e, data) {
if (currentProgressTask == null)
pgtxt.text('Waiting for restore to begin ...');
else {
if (tasks.length == 1)
pgtxt.text('Restoring files ...');
else
pgtxt.text('Restoring files (' + (tasks.length - remainingTasks) + ' of ' + tasks.length + ')');
}
};
var serverStateUpdateMethod = function(e, data) {
var activeTaskId = -1;
var queuedTasks = [];
if (data.ActiveTask != null)
activeTaskId = data.ActiveTask.Item1;
if (data.SchedulerQueueIds != null)
for(var n in data.SchedulerQueueIds)
queuedTasks.push(data.SchedulerQueueIds[n].Item1);
var remaining = 0;
for(var n in tasks) {
if (tasks[n].taskId == activeTaskId) {
currentProgressTask = tasks[n];
remaining++;
continue;
}
for(var i in queuedTasks)
if (queuedTasks[i] == tasks[n].taskId) {
remaining++;
continue;
}
}
if (remaining == 0)
onAllRestoresCompleted();
};
var curTask = 0;
var registerTasks = function() {
if (curTask == tasks.length) {
pgtxt.text('Waiting for restore to begin ...');
$(document).on('server-progress-updated', serverProgressUpdateMethod);
$(document).on('server-state-updated', serverStateUpdateMethod);
return;
}
var task = tasks[curTask];
task['action'] = 'restore-files';
task['HTTP_METHOD'] = 'POST';
curTask++;
APP_DATA.callServer(task, function(data) {
task['taskId'] = data.TaskID;
registerTasks();
},
function(d, s, m) {
alert('Error: ' + m);
dlg.dialog('close');
dlg.remove();
});
}
registerTasks();
};
$('#restore-dialog').dialog({
minWidth: 320,
width: $('body').width > 600 ? 320 : 600,
minHeight: 480,
height: 500,
modal: true,
autoOpen: false,
closeOnEscape: true,
buttons: [
{ text: '< Previous', disabled: true, click: function(event, ui) {
curpage = Math.max(0, curpage-1);
updatePageNav();
}},
{ text: 'Next >', click: function(event, ui) {
if (curpage == 2) {
$('#restore-dialog').dialog('close');
} else if (curpage == 1) {
var restorePath = null;
var overwrite = $('#restore-overwrite-overwrite').is(':checked');
if ($('#restore-overwrite-target-other').is(':checked'))
restorePath = $('#restore-target-path').val();
var includes = buildIncludeMap();
var tasks = [];
for(var n in includes) {
var t = {
time: n,
id: backupId,
'restore-path': restorePath,
'overwrite': overwrite,
paths: []
}
for(var p in includes[n]) {
if (p.lastIndexOf(dirSep) == p.length -1)
t.paths.push(p + '*');
else
t.paths.push(p);
}
if (t.paths.length > 0)
{
t.paths = t.paths.join(pathSep);
tasks.push(t);
}
}
performRestore(tasks);
} else {
var els = 0;
var includes = buildIncludeMap();
for(var t in includes)
for(var i in includes[t])
els++;
if (els == 0) {
alert('You must select at least one path to restore');
return;
}
curpage = Math.min(2, curpage+1);
updatePageNav();
}
}}
]
});
var dlg_buttons = $('#restore-dialog').parent().find('.ui-dialog-buttonpane').find('.ui-button');
var updatePageNav = function() {
if (curpage == 0) {
$('#restore-files-page').show();
$('#restore-path-page').hide();
$('#restore-complete-page').hide();
dlg_buttons.first().show();
dlg_buttons.last().button('option', 'label', 'Next >');
} else if (curpage == 1) {
$('#restore-files-page').hide();
$('#restore-path-page').show();
$('#restore-complete-page').hide();
dlg_buttons.first().show();
dlg_buttons.last().button('option', 'label', 'Restore');
} else {
$('#restore-files-page').hide();
$('#restore-path-page').hide();
$('#restore-complete-page').show();
dlg_buttons.first().hide();
dlg_buttons.last().button('option', 'label', 'OK');
}
dlg_buttons.first().button('option', 'disabled', curpage == 0);
};
$('#restore-search').watermark('Search for files & folders');
$('#restore-files-page').show();
$('#restore-path-page').hide();
$('#restore-complete-page').hide();
var colorize = function(tree, term, entry) {
var tr = tree.jstree();
$(entry || tree).find('a.jstree-anchor').each(function(i, e) {
var s = $(e);
var node = tr.get_node(s);
if (node.text) {
s.children('.search-match').remove();
var o = s.children();
s.html(replace_all_insensitive(node.text, term, '<div class="search-match">$1</div>'));
s.prepend(o);
}
});
};
var getRootPrefixes = function(tree) {
var roots = tree.children('ul').children('li');
var prefixes = [];
roots.each(function(i, e) {
var node = tr.get_node(e);
prefixes.push(node.original.filepath);
});
return prefixes;
};
var getRootNode = function(tree, path) {
var roots = tree.children('ul').children('li');
var tr = tree.jstree();
var root = null;
roots.each(function(i, e) {
var node = tr.get_node(e);
if (node && path.indexOf(node.original.filepath) == 0)
root = e;
});
return root;
};
var expandNodes = function(tree, path, callback) {
var root = getRootNode(tree, path);
if (root != null) {
var tr = tree.jstree();
var node = tr.get_node(root);
var prefix = node.original.filepath;
if (prefix.lastIndexOf(dirSep) != prefix.length - 1)
prefix += dirSep;
var remainder = path.substr(prefix.length);
var parts = remainder.split(dirSep);
var rebuilt = prefix;
for(var i in parts) {
var p = parts[i];
if (p == '')
continue;
var selfprefix = rebuilt;
rebuilt += p;
if (parseInt(i) != parts.length - 1)
rebuilt += dirSep;
var next = null;
if ((node.children === undefined || (node.children !== false && node.children.length == 0)) && callback)
callback(node, selfprefix, p);
for(var j in node.children) {
var c = tr.get_node(node.children[j]);
if (c.original.filepath == rebuilt) {
tr.open_node(node);
next = c;
break;
}
}
if (next == null)
return {
path: rebuilt,
node: node
}
node = next;
}
}
return null;
};
var prepareFolderData = function(data, time) {
var tree = trees[time];
var roots = getRootPrefixes(tree);
if (!nodedata[time])
nodedata[time] = {};
var nd = nodedata[time];
for(var n in data) {
var p = data[n].Path;
var root = null;
for(var r in roots)
if (p.indexOf(roots[r]) == 0) {
root = roots[r];
break;
}
if (root == null)
continue;
//createNodeFromData;
}
};
var loadSearchIntermediates = function(missing, files, time, search) {
var filter = [];
for(var n in missing)
filter.push(n + '*');
filter = filter.join(pathSep);
$.ajax({
'url': APP_CONFIG.server_url,
'data': {
'action': 'search-backup-files',
'id': backupId,
'time': time,
'prefix-only': 'false',
'filter': filter
},
'dataType': 'json'
})
.done(function(data, status, xhr) {
var tree = trees[time];
for(var f in files)
expandNodes(tree, files[f].Path, function(node, p, path) {
var c = [];
if (p.lastIndexOf(dirSep) != p.length - 1)
p += dirSep;
for(var f in data.Files) {
var rp = data.Files[f].Path;
if (rp != p && rp.indexOf(p) == 0) {
var np = rp.substr(p.length);
var lix = np.lastIndexOf(dirSep);
if (lix == np.length - 1)
lix = np.substr(0, np.length - 1).lastIndexOf(dirSep);
if (lix < 0)
c.push(createNodeFromData(rp, p, time));
}
}
if (c.length > 0)
node.children = c;
});
inSearch = false;
$('#restore-search-loader').hide();
colorize(tree, search);
})
.fail(function() {
$('#restore-search-loader').hide();
inSearch = false;
alert('Search failed ...');
});
};
var expandAndLoad = function(tree) {
if (missingfiles == null)
return;
var missing = {};
var mf = [];
var anymissing = false;
for(var f in missingfiles) {
var p = expandNodes(tree, missingfiles[f]);
if (p) {
missing[p.path] = p.node;
mf.push(missingfiles[f]);
anymissing = true;
}
}
if (missingfiles_search)
colorize(tree, missingfiles_search);
if (!anymissing) {
inSearch = false;
$('#restore-search-loader').hide();
missingfiles = null;
missingfiles_search = null;
} else {
missingfiles = mf;
var tr = tree.jstree();
for(var m in missing)
tr.open_node(missing[m]);
}
};
var inSearch = false;
var doSearch = function(time, search) {
if (inSearch)
return;
$('#restore-search-loader').show();
inSearch = true;
var tree = trees[time];
var tr = tree.jstree();
colorize(tree, search);
if (searchdata[time]) {
var t = searchdata[time];
for(var p in t) {
if (search.indexOf(p) == 0) {
colorize(tree, search);
inSearch = false;
return;
}
}
}
$.ajax({
'url': APP_CONFIG.server_url,
'data': {
'action': 'search-backup-files',
'id': backupId,
'time': time,
'prefix-only': 'false',
'filter': '*' + search + '*'
},
'dataType': 'json'
})
.done(function(data, status, xhr) {
if (!searchdata[time])
searchdata[time] = {};
searchdata[time][search] = data;
missingfiles = [];
missingfiles_search = search;
for(var f in data.Files)
missingfiles.push(data.Files[f].Path);
expandAndLoad(tree, search);
})
.fail(function() {
$('#restore-search-loader').hide();
inSearch = false;
alert('Search failed ...');
});
};
var createNodeFromData = function(path, prefix, time) {
var disp = path.substr(prefix.length);
var isFolder = disp.lastIndexOf(dirSep) == disp.length - 1;
var icon = null;
var state = null;
if (isFolder)
disp = disp.substr(0, disp.length - 1);
else
icon = 'icon-file icon-file-' + disp.substr(disp.lastIndexOf('.')+1);
if (prefix == '') {
disp = APP_DATA.getBackupName(backupId) || disp;
//state = {opened: true};
}
return {
text: disp,
filepath: path,
time: time,
children: isFolder,
state: state,
icon: icon
};
};
var loadNodes = function(node, callback, time) {
$.ajax({
'url': APP_CONFIG.server_url,
'data': {
'action': 'search-backup-files',
'id': backupId,
'time': time,
'prefix-only': node.id === '#',
'filter': node.id === '#' ? '*' : '[' + node.original.filepath + '[^\\' + dirSep + ']+\\' + dirSep + '?]',
'Prefix': node.id === '#' ? '' : node.original.filepath
},
'dataType': 'json'
})
.done(function(data, status, xhr) {
var nodes = [];
data.Files = data.Files || [];
for(var i = 0; i < data.Files.length; i++) {
var o = data.Files[i];
nodes.push(createNodeFromData(data.Files[i].Path, data.Prefix, time));
}
callback(nodes, data);
expandAndLoad(trees[time]);
});
};
var setupTree = function(time) {
var treeel = trees[time];
if (!trees[time]) {
var treeel = $('<div></div>');
trees[time] = treeel;
$('#restore-files-tree').append(treeel);
treeel.jstree({
'core': {
'data': function(node, callback) {
if (nodedata[node.id]) {
callback(nodedata[node.id]);
} else {
loadNodes(node, function(nodes, data) {
callback(nodes);
if (data.Prefix == '')
treeel.jstree("open_node", treeel.find('li').first());
},
time);
}
}
},
'plugins' : [ 'wholerow', "checkbox" ]
});
}
for(var t in trees)
if (t != time)
trees[t].hide();
else {
trees[t].show();
}
};
var buildIncludeMap = function() {
var m = {};
for(var t in trees) {
m[t] = {};
var tr = trees[t].jstree();
var roots = trees[t].children('ul').children('li');
var follow = [];
roots.each(function(i,e) {
follow.push(tr.get_node(e));
});
while(follow.length > 0) {
var n = follow.pop();
if (n.state.selected && n.original.filepath) {
m[t][n.original.filepath] = 1;
} else {
//TODO: This traverses the entire tree,
// we could choose only those with indeterminate,
// but that state only exists in the DOM which is
// removed when collapsed
for(var c in n.children)
follow.push(tr.get_node(n.children[c]));
}
}
}
return m;
};
$('#restore-dialog').on('setup-data', function(e, id) {
backupId = id;
trees = { };
searchdata = { };
$('#restore-files-tree').empty();
$('#restore-search-loader').hide();
$('#restore-form').each(function(i, e) { e.reset(); });
$('#restore-overwrite-overwrite').each(function(i, e) { e.checked = true; });
$('#restore-overwrite-target-original').each(function(i, e) { e.checked = true; });
curpage = 0;
updatePageNav();
APP_DATA.getServerConfig(function(serverdata) {
dirSep = serverdata.DirectorySeparator;
pathSep = serverdata.PathSeparator;
APP_DATA.callServer({ 'action': 'list-backup-sets', id: id }, function(data, success, message) {
$('#restore-version').empty();
if (data == null || data.length == 0) {
alert('Failed to get list of backup times');
$('#restore-dialog').dialog('close');
}
$('#restore-version').append($("<option></option>").attr("value", data[0].Time).text('Latest - ' + $.timeago(data[0].Time)));
for(var i in data)
if (i != '0')
$('#restore-version').append($("<option></option>").attr("value", data[i].Time).text($.timeago(data[i].Time)));
$('#restore-version').trigger('change');
}, function(data, success, message) {
alert('Failed to get list of backup times:\n' + message);
$('#restore-dialog').dialog('close');
});
}, function() {
alert('Failed to get server config');
$('#restore-dialog').dialog('close');
});
});
var doQuickSearch = function(search) {
var search = $('#restore-search').val();
var time = $('#restore-version').val();
if (searchdata[time]) {
for(var k in searchdata[time]) {
if (search.indexOf(k) == 0) {
colorize(trees[time], search);
return true;
}
}
}
return false;
};
$('#restore-search').keypress(function(e) {
if (e.which == 13 && $('#restore-search').val().trim() != '')
doSearch($('#restore-version').val(), $('#restore-search').val());
else if ($('#restore-search').val().trim() != '')
colorize(trees[$('#restore-version').val()], $('#restore-search').val());
});
$('#restore-search').keyup(function(e) {
colorize(trees[$('#restore-version').val()], $('#restore-search').val());
});
$('#restore-search').change(function(e) {
colorize(trees[$('#restore-version').val()], $('#restore-search').val());
});
$('#restore-search').on('search', function(e) {
if ($('#restore-search').val() == '')
colorize(trees[$('#restore-version').val()], $('#restore-search').val());
else
doSearch($('#restore-search').val(), $('#restore-search').val());
});
$('#restore-version').change(function() {
$('#restore-search').val('');
setupTree($('#restore-version').val());
});
$('#restore-target-path').keypress(function() { $('#restore-overwrite-target-other').each(function(i,e) { e.checked = true; }); });
$('#restore-target-path').change(function() { $('#restore-overwrite-target-other').each(function(i,e) { e.checked = true; }); });
$('#restore-overwrite-target-other').click(function() { $('#restore-target-path-browse').trigger('click'); } );
$('#restore-target-path-browse').click(function(e) {
$.browseForFolder({
title: 'Select restore folder',
resolvePath: true,
callback: function(path, display) {
$('#restore-target-path').val(path);
$('#restore-overwrite-target-other').each(function(i, e) { e.checked = true; });
}
});
});
});