gr-request/gr-ajax cleanup (gr-reviewer-list)
Bug: Issue 3988
Change-Id: I432557954fa8d745ce1ac766e15082650fd13100
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html
index 6e081ea..3fee424 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html
@@ -18,9 +18,8 @@
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
<link rel="import" href="../../../behaviors/keyboard-shortcut-behavior.html">
<link rel="import" href="../../shared/gr-account-chip/gr-account-chip.html">
-<link rel="import" href="../../shared/gr-ajax/gr-ajax.html">
<link rel="import" href="../../shared/gr-button/gr-button.html">
-<link rel="import" href="../../shared/gr-request/gr-request.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<dom-module id="gr-reviewer-list">
<template>
@@ -80,10 +79,6 @@
}
}
</style>
- <gr-ajax id="autocompleteXHR"
- url="[[_computeAutocompleteURL(change)]]"
- params="[[_computeAutocompleteParams(_inputVal)]]"
- on-response="_handleResponse"></gr-ajax>
<template is="dom-repeat" items="[[_reviewers]]" as="reviewer">
<gr-account-chip class="reviewer" account="[[reviewer]]"
on-remove="_handleRemove"
@@ -119,6 +114,7 @@
<gr-button link id="addReviewer" class="addReviewer" on-tap="_handleAddTap"
hidden$="[[_showInput]]">Add reviewer</gr-button>
</div>
+ <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-reviewer-list.js"></script>
</dom-module>
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
index 275ab6f..09ce7d7 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
@@ -121,35 +121,10 @@
return false;
},
- _computeAutocompleteURL: function(change) {
- return '/changes/' + change._number + '/suggest_reviewers';
- },
-
- _computeAutocompleteParams: function(inputVal) {
- return {
- n: 10, // Return max 10 results
- q: inputVal,
- };
- },
-
_computeSelected: function(index, selectedIndex) {
return index == selectedIndex;
},
- _handleResponse: function(e) {
- this._autocompleteData = e.detail.response.filter(function(reviewer) {
- var account = reviewer.account;
- if (!account) { return true; }
- for (var i = 0; i < this._reviewers.length; i++) {
- if (account._account_id == this.change.owner._account_id ||
- account._account_id == this._reviewers[i]._account_id) {
- return false;
- }
- }
- return true;
- }, this);
- },
-
_handleBodyClick: function(e) {
var eventPath = Polymer.dom(e).path;
for (var i = 0; i < eventPath.length; i++) {
@@ -165,7 +140,15 @@
e.preventDefault();
var target = Polymer.dom(e).rootTarget;
var accountID = parseInt(target.getAttribute('data-account-id'), 10);
- this._send('DELETE', this._restEndpoint(accountID)).then(function(req) {
+ this.disabled = true;
+ this._xhrPromise =
+ this._removeReviewer(accountID).then(function(response) {
+ this.disabled = false;
+ if (!response.ok) {
+ return response.text().then(function(text) {
+ alert(text);
+ });
+ }
var reviewers = this.change.reviewers;
['REVIEWER', 'CC'].forEach(function(type) {
reviewers[type] = reviewers[type] || [];
@@ -176,10 +159,6 @@
}
}
}, this);
- }.bind(this)).catch(function(err) {
- alert('Oops. Something went wrong. Check the console and bug the ' +
- 'PolyGerrit team for assistance.');
- throw err;
}.bind(this));
},
@@ -241,7 +220,8 @@
return;
}
this._lastAutocompleteRequest =
- this.$.autocompleteXHR.generateRequest();
+ this._getSuggestedReviewers(this.change._number, val).then(
+ this._handleReviewersResponse.bind(this));
}.bind(this);
this._clearInputRequestHandle();
@@ -253,6 +233,24 @@
}
},
+ _handleReviewersResponse: function(response) {
+ this._autocompleteData = response.filter(function(reviewer) {
+ var account = reviewer.account;
+ if (!account) { return true; }
+ for (var i = 0; i < this._reviewers.length; i++) {
+ if (account._account_id == this.change.owner._account_id ||
+ account._account_id == this._reviewers[i]._account_id) {
+ return false;
+ }
+ }
+ return true;
+ }, this);
+ },
+
+ _getSuggestedReviewers: function(changeNum, inputVal) {
+ return this.$.restAPI.getChangeSuggestedReviewers(changeNum, inputVal);
+ },
+
_handleKey: function(e) {
if (this._hideAutocomplete) {
if (e.keyCode == 27) { // 'esc'
@@ -302,43 +300,32 @@
reviewerID = reviewer.group.id;
}
this._autocompleteData = [];
- this._send('POST', this._restEndpoint(), reviewerID).then(function(req) {
- this.change.reviewers.CC = this.change.reviewers.CC || [];
- req.response.reviewers.forEach(function(r) {
- this.push('change.removable_reviewers', r);
- this.push('change.reviewers.CC', r);
- }, this);
- this._inputVal = '';
- this.$.input.focus();
- }.bind(this)).catch(function(err) {
- // TODO(andybons): Use the message returned by the server.
- alert('Unable to add ' + reviewerID + ' as a reviewer.');
- throw err;
+ this.disabled = true;
+ this._xhrPromise = this._addReviewer(reviewerID).then(function(response) {
+ this.change.reviewers['CC'] = this.change.reviewers['CC'] || [];
+ this.disabled = false;
+ if (!response.ok) {
+ return response.text().then(function(text) {
+ alert(text);
+ });
+ }
+ return this.$.restAPI.getResponseObject(response).then(function(obj) {
+ obj.reviewers.forEach(function(r) {
+ this.push('change.removable_reviewers', r);
+ this.push('change.reviewers.CC', r);
+ }, this);
+ this._inputVal = '';
+ this.$.input.focus();
+ }.bind(this));
}.bind(this));
},
- _send: function(method, url, reviewerID) {
- this.disabled = true;
- var request = document.createElement('gr-request');
- var opts = {
- method: method,
- url: url,
- };
- if (reviewerID) {
- opts.body = {reviewer: reviewerID};
- }
- this._xhrPromise = request.send(opts);
- var enableEl = function() { this.disabled = false; }.bind(this);
- this._xhrPromise.then(enableEl).catch(enableEl);
- return this._xhrPromise;
+ _addReviewer: function(id) {
+ return this.$.restAPI.addChangeReviewer(this.change._number, id);
},
- _restEndpoint: function(id) {
- var path = '/changes/' + this.change._number + '/reviewers';
- if (id) {
- path += '/' + id;
- }
- return path;
+ _removeReviewer: function(id) {
+ return this.$.restAPI.removeChangeReviewer(this.change._number, id);
},
});
})();
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
index eccc72e..9311e91 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
@@ -34,20 +34,12 @@
<script>
suite('gr-reviewer-list tests', function() {
var element;
- var server;
setup(function() {
element = fixture('basic');
-
- server = sinon.fakeServer.create();
- server.respondWith(
- 'GET',
- /\/changes\/42\/suggest_reviewers\?n=10&q=andy(.*)/,
- [
- 200,
- {'Content-Type': 'application/json'},
- ')]}\'\n' +
- JSON.stringify([
+ stub('gr-rest-api-interface', {
+ getChangeSuggestedReviewers: function() {
+ return Promise.resolve([
{
account: {
_account_id: 1021482,
@@ -68,41 +60,32 @@
name: 'andy',
}
}
- ]),
- ]
- );
- server.respondWith(
- 'POST',
- '/changes/42/reviewers',
- [
- 200,
- {'Content-Type': 'application/json'},
- ')]}\'\n' +
- JSON.stringify({
- reviewers: [{
- _account_id: 1021482,
- approvals: {
- 'Code-Review': ' 0'
- },
- email: 'andybons@chromium.org',
- name: 'Andrew Bonventre',
- }]
- }),
- ]
- );
- server.respondWith(
- 'DELETE',
- '/changes/42/reviewers/1021482',
- [
- 204,
- {'Content-Type': 'application/json'},
- ')]}\'\n{}',
- ]
- );
- });
-
- teardown(function() {
- server.restore();
+ ]);
+ },
+ addChangeReviewer: function() {
+ return Promise.resolve({
+ ok: true,
+ text: function() {
+ return Promise.resolve(
+ ')]}\'\n' +
+ JSON.stringify({
+ reviewers: [{
+ _account_id: 1021482,
+ approvals: {
+ 'Code-Review': ' 0'
+ },
+ email: 'andybons@chromium.org',
+ name: 'Andrew Bonventre',
+ }]
+ })
+ );
+ },
+ });
+ },
+ removeChangeReviewer: function() {
+ return Promise.resolve({ok: true});
+ },
+ });
});
test('controls hidden on immutable element', function() {
@@ -176,7 +159,7 @@
};
flushAsynchronousOperations();
var chips =
- Polymer.dom(element.root).querySelectorAll('gr-account-chip');
+ Polymer.dom(element.root).querySelectorAll('gr-account-chip');
assert.equal(chips.length, 3);
Array.from(chips).forEach(function(el) {
var accountID = parseInt(el.getAttribute('data-account-id'), 10);
@@ -195,17 +178,15 @@
test('autocomplete starts at >= 3 chars', function() {
element._inputRequestTimeout = 0;
element._mutable = true;
- var genRequestStub = sinon.stub(
- element.$.autocompleteXHR,
- 'generateRequest',
+ var requestStub = sinon.stub(element, '_getSuggestedReviewers',
function() {
- assert(false, 'generateRequest should not be called for input ' +
- 'lengths of less than 3 chars');
+ assert(false, '_getSuggestedReviewers should not be called for ' +
+ 'input lengths of less than 3 chars');
}
);
element._inputVal = 'fo';
flushAsynchronousOperations();
- genRequestStub.restore();
+ requestStub.restore();
});
test('add/remove reviewer flow', function(done) {
@@ -220,9 +201,8 @@
MockInteractions.tap(element.$$('.addReviewer'));
flushAsynchronousOperations();
element._inputVal = 'andy';
- server.respond();
- element._lastAutocompleteRequest.completes.then(function() {
+ element._lastAutocompleteRequest.then(function() {
flushAsynchronousOperations();
assert.isFalse(element.$$('.dropdown').hasAttribute('hidden'));
var itemEls = Polymer.dom(element.root).querySelectorAll('.reviewer');
@@ -242,8 +222,7 @@
assert.isTrue(element.$$('.dropdown').hasAttribute('hidden'));
element._inputVal = 'andyb';
- server.respond();
- element._lastAutocompleteRequest.completes.then(function() {
+ element._lastAutocompleteRequest.then(function() {
assert.isFalse(element.$$('.dropdown').hasAttribute('hidden'));
var itemEls = Polymer.dom(element.root).querySelectorAll('.reviewer');
assert.equal(itemEls.length, 3);
@@ -251,7 +230,6 @@
assert.isFalse(itemEls[1].hasAttribute('selected'));
MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
assert.isTrue(element.disabled);
- server.respond();
element._xhrPromise.then(function() {
assert.isFalse(element.disabled);
@@ -262,13 +240,12 @@
MockInteractions.tap(element.$$('.reviewer').$$('gr-button'));
flushAsynchronousOperations();
assert.isTrue(element.disabled);
- server.respond();
element._xhrPromise.then(function() {
flushAsynchronousOperations();
assert.isFalse(element.disabled);
var reviewerEls =
- Polymer.dom(element.root).querySelectorAll('.reviewer');
+ Polymer.dom(element.root).querySelectorAll('.reviewer');
assert.equal(reviewerEls.length, 0);
done();
});
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 54ce15c..0765ec8 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -311,6 +311,40 @@
});
},
+ getChangeSuggestedReviewers: function(changeNum, inputVal, opt_errFn,
+ opt_ctx) {
+ var url = this.getChangeActionURL(changeNum, null, '/suggest_reviewers');
+ return this.fetchJSON(url, opt_errFn, opt_ctx, {
+ n: 10, // Return max 10 results
+ q: inputVal,
+ });
+ },
+
+ addChangeReviewer: function(changeNum, reviewerID) {
+ return this._sendChangeReviewerRequest('POST', changeNum, reviewerID);
+ },
+
+ removeChangeReviewer: function(changeNum, reviewerID) {
+ return this._sendChangeReviewerRequest('DELETE', changeNum, reviewerID);
+ },
+
+ _sendChangeReviewerRequest: function(method, changeNum, reviewerID) {
+ var url = this.getChangeActionURL(changeNum, null, '/reviewers');
+ var body;
+ switch(method) {
+ case 'POST':
+ body = {reviewer: reviewerID};
+ break;
+ case 'DELETE':
+ url += '/' + reviewerID;
+ break;
+ default:
+ throw Error('Unsupported HTTP method: ' + method);
+ }
+
+ return this.send(method, url, body);
+ },
+
getReviewedFiles: function(changeNum, patchNum) {
return this.fetchJSON(
this.getChangeActionURL(changeNum, patchNum, '/files?reviewed'));