Merge pull request #11023 from owncloud/users-fixundo
Add timeout to user and group deletion notification.
This commit is contained in:
commit
59c79781f7
|
@ -34,6 +34,16 @@ function DeleteHandler(endpoint, paramID, markCallback, removeCallback) {
|
|||
this.notificationPlaceholder = '%oid';
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of milliseconds after which the operation is performed.
|
||||
*/
|
||||
DeleteHandler.TIMEOUT_MS = 7000;
|
||||
|
||||
/**
|
||||
* Timer after which the action will be performed anyway.
|
||||
*/
|
||||
DeleteHandler.prototype._timeout = null;
|
||||
|
||||
/**
|
||||
* The function to be called after successfully marking the object for deletion
|
||||
* @callback markCallback
|
||||
|
@ -72,7 +82,9 @@ DeleteHandler.prototype.setNotification = function(notifier, dataID, message, un
|
|||
|
||||
var dh = this;
|
||||
|
||||
$('#notification').on('click', '.undo', function () {
|
||||
$('#notification')
|
||||
.off('click.deleteHandler_' + dataID)
|
||||
.on('click.deleteHandler_' + dataID, '.undo', function () {
|
||||
if ($('#notification').data(dh.notificationDataID)) {
|
||||
var oid = dh.oidToDelete;
|
||||
dh.cancel();
|
||||
|
@ -116,18 +128,36 @@ DeleteHandler.prototype.hideNotification = function() {
|
|||
*/
|
||||
DeleteHandler.prototype.mark = function(oid) {
|
||||
if(this.oidToDelete !== false) {
|
||||
this.deleteEntry();
|
||||
// passing true to avoid hiding the notification
|
||||
// twice and causing the second notification
|
||||
// to disappear immediately
|
||||
this.deleteEntry(true);
|
||||
}
|
||||
this.oidToDelete = oid;
|
||||
this.canceled = false;
|
||||
this.markCallback(oid);
|
||||
this.showNotification();
|
||||
if (this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = null;
|
||||
}
|
||||
if (DeleteHandler.TIMEOUT_MS > 0) {
|
||||
this._timeout = window.setTimeout(
|
||||
_.bind(this.deleteEntry, this),
|
||||
DeleteHandler.TIMEOUT_MS
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* cancels a delete operation
|
||||
*/
|
||||
DeleteHandler.prototype.cancel = function() {
|
||||
if (this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = null;
|
||||
}
|
||||
|
||||
this.canceled = true;
|
||||
this.oidToDelete = false;
|
||||
};
|
||||
|
@ -137,22 +167,31 @@ DeleteHandler.prototype.cancel = function() {
|
|||
* initialized by mark(). On error, it will show a message via
|
||||
* OC.dialogs.alert. On success, a callback is fired so that the client can
|
||||
* update the web interface accordingly.
|
||||
*
|
||||
* @param {boolean} [keepNotification] true to keep the notification, false to hide
|
||||
* it, defaults to false
|
||||
*/
|
||||
DeleteHandler.prototype.deleteEntry = function() {
|
||||
DeleteHandler.prototype.deleteEntry = function(keepNotification) {
|
||||
if(this.canceled || this.oidToDelete === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var dh = this;
|
||||
if($('#notification').data(this.notificationDataID) === true) {
|
||||
if(!keepNotification && $('#notification').data(this.notificationDataID) === true) {
|
||||
dh.hideNotification();
|
||||
}
|
||||
|
||||
if (this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = null;
|
||||
}
|
||||
|
||||
var payload = {};
|
||||
payload[dh.ajaxParamID] = dh.oidToDelete;
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: OC.filePath('settings', 'ajax', dh.ajaxEndpoint),
|
||||
// FIXME: do not use synchronous ajax calls as they block the browser !
|
||||
async: false,
|
||||
data: payload,
|
||||
success: function (result) {
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
describe('DeleteHandler tests', function() {
|
||||
var showNotificationSpy;
|
||||
var hideNotificationSpy;
|
||||
var clock;
|
||||
var removeCallback;
|
||||
var markCallback;
|
||||
var undoCallback;
|
||||
|
||||
function init(markCallback, removeCallback, undoCallback) {
|
||||
var handler = new DeleteHandler('dummyendpoint.php', 'paramid', markCallback, removeCallback);
|
||||
handler.setNotification(OC.Notification, 'dataid', 'removed %oid entry', undoCallback);
|
||||
return handler;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
showNotificationSpy = sinon.spy(OC.Notification, 'showHtml');
|
||||
hideNotificationSpy = sinon.spy(OC.Notification, 'hide');
|
||||
clock = sinon.useFakeTimers();
|
||||
removeCallback = sinon.stub();
|
||||
markCallback = sinon.stub();
|
||||
undoCallback = sinon.stub();
|
||||
|
||||
$('#testArea').append('<div id="notification"></div>');
|
||||
});
|
||||
afterEach(function() {
|
||||
showNotificationSpy.restore();
|
||||
hideNotificationSpy.restore();
|
||||
clock.restore();
|
||||
});
|
||||
it('shows a notification when marking for delete', function() {
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.mark('some_uid');
|
||||
|
||||
expect(showNotificationSpy.calledOnce).toEqual(true);
|
||||
expect(showNotificationSpy.getCall(0).args[0]).toEqual('removed some_uid entry');
|
||||
|
||||
expect(markCallback.calledOnce).toEqual(true);
|
||||
expect(markCallback.getCall(0).args[0]).toEqual('some_uid');
|
||||
expect(removeCallback.notCalled).toEqual(true);
|
||||
expect(undoCallback.notCalled).toEqual(true);
|
||||
|
||||
expect(fakeServer.requests.length).toEqual(0);
|
||||
});
|
||||
it('deletes first entry and reshows notification on second delete', function() {
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.mark('some_uid');
|
||||
|
||||
expect(showNotificationSpy.calledOnce).toEqual(true);
|
||||
expect(showNotificationSpy.getCall(0).args[0]).toEqual('removed some_uid entry');
|
||||
showNotificationSpy.reset();
|
||||
|
||||
handler.mark('some_other_uid');
|
||||
|
||||
expect(hideNotificationSpy.calledOnce).toEqual(true);
|
||||
expect(showNotificationSpy.calledOnce).toEqual(true);
|
||||
expect(showNotificationSpy.getCall(0).args[0]).toEqual('removed some_other_uid entry');
|
||||
|
||||
expect(markCallback.calledTwice).toEqual(true);
|
||||
expect(markCallback.getCall(0).args[0]).toEqual('some_uid');
|
||||
expect(markCallback.getCall(1).args[0]).toEqual('some_other_uid');
|
||||
expect(removeCallback.notCalled).toEqual(true);
|
||||
expect(undoCallback.notCalled).toEqual(true);
|
||||
|
||||
// previous one was delete
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
var request = fakeServer.requests[0];
|
||||
expect(request.url).toEqual(OC.webroot + '/index.php/settings/ajax/dummyendpoint.php');
|
||||
});
|
||||
it('automatically deletes after timeout', function() {
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.mark('some_uid');
|
||||
|
||||
clock.tick(5000);
|
||||
// nothing happens yet
|
||||
expect(fakeServer.requests.length).toEqual(0);
|
||||
|
||||
clock.tick(3000);
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
var request = fakeServer.requests[0];
|
||||
expect(request.url).toEqual(OC.webroot + '/index.php/settings/ajax/dummyendpoint.php');
|
||||
});
|
||||
it('deletes when deleteEntry is called', function() {
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.mark('some_uid');
|
||||
|
||||
handler.deleteEntry();
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
var request = fakeServer.requests[0];
|
||||
expect(request.url).toEqual(OC.webroot + '/index.php/settings/ajax/dummyendpoint.php');
|
||||
});
|
||||
it('cancels deletion when undo is clicked', function() {
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.setNotification(OC.Notification, 'dataid', 'removed %oid entry <span class="undo">Undo</span>', undoCallback);
|
||||
handler.mark('some_uid');
|
||||
$('#notification .undo').click();
|
||||
|
||||
expect(undoCallback.calledOnce).toEqual(true);
|
||||
|
||||
// timer was cancelled
|
||||
clock.tick(10000);
|
||||
expect(fakeServer.requests.length).toEqual(0);
|
||||
});
|
||||
it('cancels deletion when cancel method is called', function() {
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.setNotification(OC.Notification, 'dataid', 'removed %oid entry <span class="undo">Undo</span>', undoCallback);
|
||||
handler.mark('some_uid');
|
||||
handler.cancel();
|
||||
|
||||
// not sure why, seems to be by design
|
||||
expect(undoCallback.notCalled).toEqual(true);
|
||||
|
||||
// timer was cancelled
|
||||
clock.tick(10000);
|
||||
expect(fakeServer.requests.length).toEqual(0);
|
||||
});
|
||||
it('calls removeCallback after successful server side deletion', function() {
|
||||
fakeServer.respondWith(/\/index\.php\/settings\/ajax\/dummyendpoint.php/, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({status: 'success'})
|
||||
]);
|
||||
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.mark('some_uid');
|
||||
handler.deleteEntry();
|
||||
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
var request = fakeServer.requests[0];
|
||||
var query = OC.parseQueryString(request.requestBody);
|
||||
expect(query.paramid).toEqual('some_uid');
|
||||
|
||||
expect(removeCallback.calledOnce).toEqual(true);
|
||||
expect(undoCallback.notCalled).toEqual(true);
|
||||
expect(removeCallback.getCall(0).args[0]).toEqual('some_uid');
|
||||
});
|
||||
it('calls undoCallback and shows alert after failed server side deletion', function() {
|
||||
// stub t to avoid extra calls
|
||||
var tStub = sinon.stub(window, 't').returns('text');
|
||||
fakeServer.respondWith(/\/index\.php\/settings\/ajax\/dummyendpoint.php/, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({status: 'error', data: {message: 'test error'}})
|
||||
]);
|
||||
|
||||
var alertDialogStub = sinon.stub(OC.dialogs, 'alert');
|
||||
var handler = init(markCallback, removeCallback, undoCallback);
|
||||
handler.mark('some_uid');
|
||||
handler.deleteEntry();
|
||||
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
var request = fakeServer.requests[0];
|
||||
var query = OC.parseQueryString(request.requestBody);
|
||||
expect(query.paramid).toEqual('some_uid');
|
||||
|
||||
expect(removeCallback.notCalled).toEqual(true);
|
||||
expect(undoCallback.calledOnce).toEqual(true);
|
||||
expect(undoCallback.getCall(0).args[0]).toEqual('some_uid');
|
||||
|
||||
expect(alertDialogStub.calledOnce);
|
||||
|
||||
alertDialogStub.restore();
|
||||
tStub.restore();
|
||||
});
|
||||
});
|
|
@ -66,7 +66,15 @@ module.exports = function(config) {
|
|||
'apps/files_external/js/mountsfilelist.js'
|
||||
],
|
||||
testFiles: ['apps/files_external/tests/js/*.js']
|
||||
}];
|
||||
},
|
||||
{
|
||||
name: 'settings',
|
||||
srcFiles: [
|
||||
'settings/js/users/deleteHandler.js'
|
||||
],
|
||||
testFiles: ['settings/tests/js/users/deleteHandlerSpec.js']
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// respect NOCOVERAGE env variable
|
||||
|
|
Loading…
Reference in New Issue