Fix system tags conflict situations

Does not disrupt the UX whenever a tag or association was created
concurrently. The input field will adjust itself as if the tag was
already there in the first place.
This commit is contained in:
Vincent Petry 2016-01-27 15:09:59 +01:00
parent 308396b770
commit 714d8c2424
2 changed files with 85 additions and 3 deletions

View File

@ -186,6 +186,12 @@
return false;
},
_addToSelect2Selection: function(selection) {
var data = this.$tagsField.select2('data');
data.push(selection);
this.$tagsField.select2('data', data);
},
/**
* Event handler whenever a tag is selected.
* Also called whenever tag creation is requested through the dummy tag object.
@ -204,10 +210,27 @@
userAssignable: true
}, {
success: function(model) {
var data = self.$tagsField.select2('data');
data.push(model.toJSON());
self.$tagsField.select2('data', data);
self._addToSelect2Selection(model.toJSON());
self.trigger('select', model);
},
error: function(model, xhr) {
if (xhr.status === 409) {
// re-fetch collection to get the missing tag
self.collection.reset();
self.collection.fetch({
success: function(collection) {
// find the tag in the collection
var model = collection.where({name: e.object.name, userVisible: true, userAssignable: true});
if (model.length) {
model = model[0];
// the tag already exists or was already assigned,
// add it to the list anyway
self._addToSelect2Selection(model.toJSON());
self.trigger('select', model);
}
}
});
}
}
});
this.$tagsField.select2('close');

View File

@ -158,6 +158,65 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
expect(selectHandler.calledOnce).toEqual(true);
expect(selectHandler.getCall(0).args[0]).toEqual('2');
});
it('triggers select event and still adds to list even in case of conflict', function() {
var selectHandler = sinon.stub();
view.on('select', selectHandler);
var fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
var createStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'create');
view.$el.find('input').trigger(new $.Event('select2-selecting', {
object: {
id: -1,
name: 'newname',
isNew: true
}
}));
expect(createStub.calledOnce).toEqual(true);
expect(createStub.getCall(0).args[0]).toEqual({
name: 'newname',
userVisible: true,
userAssignable: true
});
var newModel = new OC.SystemTags.SystemTagModel({
id: '123',
name: 'newname',
userVisible: true,
userAssignable: true
});
// not called yet
expect(selectHandler.notCalled).toEqual(true);
select2Stub.withArgs('data').returns([{
id: '1',
name: 'abc'
}]);
// simulate conflict response for tag creation
createStub.yieldTo('error', view.collection, {status: 409});
// at this point it fetches from the server
expect(fetchStub.calledOnce).toEqual(true);
// simulate fetch result by adding model to the collection
view.collection.add(newModel);
fetchStub.yieldTo('success', view.collection);
expect(select2Stub.lastCall.args[0]).toEqual('data');
expect(select2Stub.lastCall.args[1]).toEqual([{
id: '1',
name: 'abc'
},
newModel.toJSON()
]);
// select event still called
expect(selectHandler.calledOnce).toEqual(true);
expect(selectHandler.getCall(0).args[0]).toEqual(newModel);
createStub.restore();
fetchStub.restore();
});
});
describe('tag actions', function() {
var opts;