Added highlighting to restore dialog
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
|
||||
<script type="text/javascript" src="scripts/filters/localize.js"></script>
|
||||
<script type="text/javascript" src="scripts/filters/timeremaining.js"></script>
|
||||
<script type="text/javascript" src="scripts/filters/highlight.js"></script>
|
||||
|
||||
<script type="text/javascript" src="scripts/directives/backupEditUri.js"></script>
|
||||
<script type="text/javascript" src="scripts/directives/sourceFolderPicker.js"></script>
|
||||
|
||||
@@ -3,7 +3,8 @@ var backupApp = angular.module(
|
||||
[
|
||||
'ngRoute',
|
||||
'btford.modal',
|
||||
'dotjem.angular.tree'
|
||||
'dotjem.angular.tree',
|
||||
'ngSanitize'
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -38,193 +38,212 @@ backupApp.controller('RestoreController', function ($scope, $routeParams, $locat
|
||||
|
||||
for(var t in dateBuckets)
|
||||
if (stamp >= dateBuckets[t].stamp)
|
||||
return dateBuckets[t].text;
|
||||
return dateBuckets[t].text;
|
||||
|
||||
return dt.getFullYear() + '';
|
||||
};
|
||||
|
||||
$scope.HideEditUri = function() {
|
||||
$scope.EditUriState = false;
|
||||
};
|
||||
$scope.HideEditUri = function() {
|
||||
$scope.EditUriState = false;
|
||||
};
|
||||
|
||||
$scope.doConnect = function() {
|
||||
$scope.connecting = true;
|
||||
$scope.ConnectionProgress = 'Registering temporary backup ...';
|
||||
$scope.doConnect = function() {
|
||||
$scope.connecting = true;
|
||||
$scope.ConnectionProgress = 'Registering temporary backup ...';
|
||||
|
||||
var opts = {};
|
||||
var obj = {'Backup': {'TargetURL': $scope.TargetURL } };
|
||||
var opts = {};
|
||||
var obj = {'Backup': {'TargetURL': $scope.TargetURL } };
|
||||
|
||||
if (($scope.EncryptionPassphrase || '') == '')
|
||||
opts['--no-encryption'] = 'true';
|
||||
else
|
||||
opts['passphrase'] = $scope.EncryptionPassphrase;
|
||||
if (($scope.EncryptionPassphrase || '') == '')
|
||||
opts['--no-encryption'] = 'true';
|
||||
else
|
||||
opts['passphrase'] = $scope.EncryptionPassphrase;
|
||||
|
||||
if (!AppUtils.parse_extra_options($scope.ExtendedOptions, opts))
|
||||
return false;
|
||||
if (!AppUtils.parse_extra_options($scope.ExtendedOptions, opts))
|
||||
return false;
|
||||
|
||||
obj.Backup.Settings = [];
|
||||
for(var k in opts) {
|
||||
obj.Backup.Settings.push({
|
||||
Name: k,
|
||||
Value: opts[k]
|
||||
});
|
||||
}
|
||||
obj.Backup.Settings = [];
|
||||
for(var k in opts) {
|
||||
obj.Backup.Settings.push({
|
||||
Name: k,
|
||||
Value: opts[k]
|
||||
});
|
||||
}
|
||||
|
||||
AppService.post('/backups?temporary=true', obj, {'headers': {'Content-Type': 'application/json'}}).then(
|
||||
function(resp) {
|
||||
$scope.ConnectionProgress = 'Listing backup dates ...';
|
||||
$scope.BackupID = resp.data.ID;
|
||||
$scope.fetchBackupTimes();
|
||||
}, function(resp) {
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
AppService.post('/backups?temporary=true', obj, {'headers': {'Content-Type': 'application/json'}}).then(
|
||||
function(resp) {
|
||||
$scope.ConnectionProgress = 'Listing backup dates ...';
|
||||
$scope.BackupID = resp.data.ID;
|
||||
$scope.fetchBackupTimes();
|
||||
}, function(resp) {
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
};
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.fetchBackupTimes = function() {
|
||||
AppService.get('/backup/' + $scope.BackupID + '/filesets').then(
|
||||
function(resp) {
|
||||
$scope.Filesets = resp.data;
|
||||
$scope.fetchBackupTimes = function() {
|
||||
AppService.get('/backup/' + $scope.BackupID + '/filesets').then(
|
||||
function(resp) {
|
||||
$scope.Filesets = resp.data;
|
||||
|
||||
for(var n in filesetStamps)
|
||||
delete filesetStamps[n];
|
||||
for(var n in filesetStamps)
|
||||
delete filesetStamps[n];
|
||||
|
||||
for(var n in $scope.Filesets) {
|
||||
var item = $scope.Filesets[n];
|
||||
item.DisplayLabel = item.Version + ': ' + AppUtils.toDisplayDateAndTime(AppUtils.parseDate(item.Time));
|
||||
item.GroupLabel = n == 0 ? 'Latests' : createGroupLabel(AppUtils.parseDate(item.Time));
|
||||
for(var n in $scope.Filesets) {
|
||||
var item = $scope.Filesets[n];
|
||||
item.DisplayLabel = item.Version + ': ' + AppUtils.toDisplayDateAndTime(AppUtils.parseDate(item.Time));
|
||||
item.GroupLabel = n == 0 ? 'Latests' : createGroupLabel(AppUtils.parseDate(item.Time));
|
||||
|
||||
filesetStamps[item.Version + ''] = item.Time;
|
||||
}
|
||||
filesetStamps[item.Version + ''] = item.Time;
|
||||
}
|
||||
|
||||
$scope.RestoreVersion = 0;
|
||||
$scope.restore_step = 1;
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
$scope.RestoreVersion = 0;
|
||||
$scope.restore_step = 1;
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
|
||||
$scope.fetchPathInformation();
|
||||
},
|
||||
$scope.fetchPathInformation();
|
||||
},
|
||||
|
||||
function(resp) {
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
function(resp) {
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
};
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.fetchPathInformation = function() {
|
||||
var version = $scope.RestoreVersion + '';
|
||||
$scope.fetchPathInformation = function() {
|
||||
var version = $scope.RestoreVersion + '';
|
||||
|
||||
if (inProgress[version] || $scope.restore_step != 1)
|
||||
return;
|
||||
if (inProgress[version] || $scope.restore_step != 1)
|
||||
return;
|
||||
|
||||
if (filesetsBuilt[version] == null) {
|
||||
if ($scope.isTemporaryBackup && filesetsRepaired[version] == null) {
|
||||
$scope.connecting = true;
|
||||
$scope.ConnectionProgress = 'Fetching path information ...';
|
||||
inProgress[version] = true;
|
||||
if (filesetsBuilt[version] == null) {
|
||||
if ($scope.isTemporaryBackup && filesetsRepaired[version] == null) {
|
||||
$scope.connecting = true;
|
||||
$scope.ConnectionProgress = 'Fetching path information ...';
|
||||
inProgress[version] = true;
|
||||
|
||||
AppService.post('/backup/' + $scope.BackupID + '/repairupdate', { 'only-paths': true, 'time': filesetStamps[version + '']}).then(
|
||||
function(resp) {
|
||||
AppService.post('/backup/' + $scope.BackupID + '/repairupdate', { 'only-paths': true, 'time': filesetStamps[version + '']}).then(
|
||||
function(resp) {
|
||||
|
||||
var taskid = resp.data.ID;
|
||||
inProgress[version] = taskid;
|
||||
$scope.taskid = taskid;
|
||||
var taskid = resp.data.ID;
|
||||
inProgress[version] = taskid;
|
||||
$scope.taskid = taskid;
|
||||
|
||||
ServerStatus.callWhenTaskCompletes(taskid, function() {
|
||||
ServerStatus.callWhenTaskCompletes(taskid, function() {
|
||||
|
||||
AppService.get('/task/' + taskid).then(function(resp) {
|
||||
delete inProgress[version];
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
AppService.get('/task/' + taskid).then(function(resp) {
|
||||
delete inProgress[version];
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
|
||||
if (resp.data.Status == 'Completed')
|
||||
{
|
||||
filesetsRepaired[version] = true;
|
||||
$scope.fetchPathInformation();
|
||||
}
|
||||
else
|
||||
{
|
||||
alert('Failed to fetch path information: ' + resp.data.ErrorMessage);
|
||||
}
|
||||
if (resp.data.Status == 'Completed')
|
||||
{
|
||||
filesetsRepaired[version] = true;
|
||||
$scope.fetchPathInformation();
|
||||
}
|
||||
else
|
||||
{
|
||||
alert('Failed to fetch path information: ' + resp.data.ErrorMessage);
|
||||
}
|
||||
|
||||
}, function(resp) {
|
||||
delete inProgress[version];
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
}, function(resp) {
|
||||
delete inProgress[version];
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
alert('Failed to fetch path information: ' + message);
|
||||
});
|
||||
});
|
||||
},
|
||||
function(resp) {
|
||||
delete inProgress[version];
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
alert('Failed to fetch path information: ' + message);
|
||||
});
|
||||
});
|
||||
},
|
||||
function(resp) {
|
||||
delete inProgress[version];
|
||||
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
|
||||
} else {
|
||||
var stamp = filesetStamps[version];
|
||||
$scope.connecting = true;
|
||||
$scope.ConnectionProgress = 'Fetching path information ...';
|
||||
inProgress[version] = true;
|
||||
} else {
|
||||
var stamp = filesetStamps[version];
|
||||
$scope.connecting = true;
|
||||
$scope.ConnectionProgress = 'Fetching path information ...';
|
||||
inProgress[version] = true;
|
||||
|
||||
AppService.get('/backup/' + $scope.BackupID + '/files/*?prefix-only=true&folder-contents=false&time=' + encodeURIComponent(stamp)).then(
|
||||
function(resp) {
|
||||
delete inProgress[version];
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
AppService.get('/backup/' + $scope.BackupID + '/files/*?prefix-only=true&folder-contents=false&time=' + encodeURIComponent(stamp)).then(
|
||||
function(resp) {
|
||||
delete inProgress[version];
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
|
||||
filesetsBuilt[version] = resp.data.Files;
|
||||
$scope.Paths = filesetsBuilt[version];
|
||||
},
|
||||
function(resp) {
|
||||
delete inProgress[version];
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
filesetsBuilt[version] = resp.data.Files;
|
||||
$scope.Paths = filesetsBuilt[version];
|
||||
},
|
||||
function(resp) {
|
||||
delete inProgress[version];
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
}
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} else {
|
||||
$scope.Paths = filesetsBuilt[version];
|
||||
}
|
||||
};
|
||||
} else {
|
||||
$scope.Paths = filesetsBuilt[version];
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$watch('RestoreVersion', function() { $scope.fetchPathInformation(); });
|
||||
$scope.$watch('RestoreVersion', function() { $scope.fetchPathInformation(); });
|
||||
|
||||
$scope.onClickNext = function() {
|
||||
var results = $scope.treedata.allSelected();
|
||||
if (results.length == 0) {
|
||||
alert('No items to restore, please select one or more items');
|
||||
return;
|
||||
}
|
||||
}
|
||||
$scope.onClickNext = function() {
|
||||
var results = $scope.treedata.allSelected();
|
||||
if (results.length == 0) {
|
||||
alert('No items to restore, please select one or more items');
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.doSearch = function() {
|
||||
var stamp = filesetStamps[$scope.RestoreVersion + ''];
|
||||
|
||||
AppService.get('/backup/' + $scope.BackupID + '/files/*' + $scope.SearchFilter + '*?prefix-only=false&time=' + encodeURIComponent(stamp)).then(
|
||||
function(resp) {
|
||||
//alert(resp.data.Files);
|
||||
},
|
||||
function(resp) {
|
||||
var message = resp.statusText;
|
||||
if (resp.data != null && resp.data.Message != null)
|
||||
message = resp.data.Message;
|
||||
|
||||
$scope.connecting = false;
|
||||
$scope.ConnectionProgress = '';
|
||||
alert('Failed to connect: ' + message);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
});
|
||||
@@ -8,7 +8,8 @@ backupApp.directive('restoreFilePicker', function() {
|
||||
ngBackupId: '=',
|
||||
ngTimestamp: '=',
|
||||
treedata: '=',
|
||||
ngSelected: '='
|
||||
ngSelected: '=',
|
||||
ngSearchFilter: '='
|
||||
},
|
||||
templateUrl: 'templates/restorefilepicker.html',
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// From https://stackoverflow.com/questions/23285196/highlight-search-result-using-angular-js-and-ui-utils
|
||||
backupApp.filter('highlight', function () {
|
||||
return function (text, search, caseSensitive) {
|
||||
if (text && (search || angular.isNumber(search))) {
|
||||
text = text.toString();
|
||||
search = search.toString();
|
||||
if (caseSensitive) {
|
||||
return text.split(search).join('<span class="ui-match">' + search + '</span>');
|
||||
} else {
|
||||
return text.replace(new RegExp(search, 'gi'), '<span class="ui-match">$&</span>');
|
||||
}
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -334,5 +334,10 @@ body .container .body .content .tasks .tasklist a.action-link {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.ui-match {
|
||||
font-weight: bold;
|
||||
color: darkgreen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
<div ng-hide="EditUriState">
|
||||
<h1>Restore files</h1>
|
||||
<div class="input textarea linklabel">
|
||||
<label for="target"><a href class="target" ng-click="EditUriState = true">Connect to ></a></label>
|
||||
<textarea name="target" id="target" ng-model="TargetURL" placeholder="Enter a url, or click the 'Connect to>' link"></textarea>
|
||||
</div>
|
||||
<div class="input textarea linklabel">
|
||||
<label for="target"><a href class="target" ng-click="EditUriState = true">Connect to ></a></label>
|
||||
<textarea name="target" id="target" ng-model="TargetURL" placeholder="Enter a url, or click the 'Connect to>' link"></textarea>
|
||||
</div>
|
||||
<div class="input password">
|
||||
<label for="password">Passphrase</label>
|
||||
<input type="password" id="password" name="password" ng-model="EncryptionPassphrase" placeholder="Enter backup passphrase, if any" />
|
||||
@@ -38,9 +38,14 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<restore-file-picker id="restore_file_picker" ng-sources="Paths" ng-backup-id="BackupID" ng-timestamp="filesetStamps[RestoreVersion + '']" treedata="treedata" ng-selected="Selected">
|
||||
</restore-file-picker>
|
||||
<div class="input text search overlayButton multiple" style="max-width: none">
|
||||
<label for="searchfilter">Search for files</label>
|
||||
<input type="search" id="searchfilter" name="searchfilter" ng-model="SearchFilter" placeholder="Type to highlight files" />
|
||||
<a href id="searchfiltersubmit" class="button" ng-click="doSearch()">Search</a>
|
||||
</div>
|
||||
|
||||
<restore-file-picker id="restore_file_picker" ng-sources="Paths" ng-backup-id="BackupID" ng-timestamp="filesetStamps[RestoreVersion + '']" treedata="treedata" ng-selected="Selected" ng-search-filter="SearchFilter">
|
||||
</restore-file-picker>
|
||||
<div class="buttons">
|
||||
<a href class="submit" ng-click="onClickNext()">Continue</a>
|
||||
<a href class="submit" ng-click="restore_step = 0">Back</a>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<a class="check" ng-click="toggleCheck(node)" ng-class="{include: node.include == '+', exclude: node.include == '-', partial: node.include == ' ', root: node.root}"></a>
|
||||
<a class="type {{node.iconCls}}" ng-class="{invisible: node.hidden, loading: node.loading}"></a>
|
||||
|
||||
<span ng-click="toggleSelected(node)">{{ node.text }}</span>
|
||||
<span ng-click="toggleSelected(node)" ng-bind-html="node.text | highlight:ngSearchFilter"></span>
|
||||
</div>
|
||||
<ul ng-class="{expanded: node.expanded}" dx-connect="node"/>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user