Merge "Allow for deletion of votes from changes"
This commit is contained in:
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
|
||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../../behaviors/rest-client-behavior.html">
|
||||
<link rel="import" href="../../shared/gr-account-link/gr-account-link.html">
|
||||
<link rel="import" href="../../shared/gr-account-chip/gr-account-chip.html">
|
||||
<link rel="import" href="../../shared/gr-label/gr-label.html">
|
||||
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
|
||||
<link rel="import" href="../../shared/gr-editable-label/gr-editable-label.html">
|
||||
@@ -45,12 +45,13 @@ limitations under the License.
|
||||
}
|
||||
.labelValueContainer .approved,
|
||||
.labelValueContainer .notApproved {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
padding: .1em .3em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.labelValue {
|
||||
display: inline-block;
|
||||
padding-right: .3em;
|
||||
}
|
||||
.approved {
|
||||
background-color: #d4ffd4;
|
||||
@@ -150,7 +151,7 @@ limitations under the License.
|
||||
<span class="title">[[labelName]]</span>
|
||||
<span class="value">
|
||||
<template is="dom-repeat"
|
||||
items="[[_computeLabelValues(labelName, change.labels)]]"
|
||||
items="[[_computeLabelValues(labelName, change.labels.*)]]"
|
||||
as="label">
|
||||
<div class="labelValueContainer">
|
||||
<span class$="[[label.className]]">
|
||||
@@ -160,7 +161,13 @@ limitations under the License.
|
||||
class="labelValue">
|
||||
[[label.value]]
|
||||
</gr-label>
|
||||
<gr-account-link account="[[label.account]]"></gr-account-link>
|
||||
<gr-account-chip
|
||||
account="[[label.account]]"
|
||||
data-account-id$="[[label.account._account_id]]"
|
||||
label-name="[[labelName]]"
|
||||
removable="[[_computeCanDeleteVote(label.account, mutable)]]"
|
||||
transparent-background
|
||||
on-remove="_onDeleteVote"></gr-account-chip>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -55,8 +55,9 @@
|
||||
return Object.keys(labels).sort();
|
||||
},
|
||||
|
||||
_computeLabelValues: function(labelName, labels) {
|
||||
_computeLabelValues: function(labelName, _labels) {
|
||||
var result = [];
|
||||
var labels = _labels.base;
|
||||
var t = labels[labelName];
|
||||
if (!t) { return result; }
|
||||
var approvals = t.all || [];
|
||||
@@ -101,5 +102,46 @@
|
||||
_computeShowReviewersByState: function(serverConfig) {
|
||||
return !!serverConfig.note_db_enabled;
|
||||
},
|
||||
|
||||
/**
|
||||
* A user is able to delete a vote iff the mutable property is true and the
|
||||
* reviewer that left the vote exists in the list of removable_reviewers
|
||||
* received from the backend.
|
||||
*
|
||||
* @param {!Object} reviewer An object describing the reviewer that left the
|
||||
* vote.
|
||||
* @param {boolean} mutable this.mutable describes whether the
|
||||
* change-metadata section is modifiable by the current user.
|
||||
*/
|
||||
_computeCanDeleteVote: function(reviewer, mutable) {
|
||||
if (!mutable) { return false; }
|
||||
for (var i = 0; i < this.change.removable_reviewers.length; i++) {
|
||||
if (this.change.removable_reviewers[i]._account_id ===
|
||||
reviewer._account_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onDeleteVote: function(e) {
|
||||
e.preventDefault();
|
||||
var target = Polymer.dom(e).rootTarget;
|
||||
var labelName = target.labelName;
|
||||
var accountID = parseInt(target.getAttribute('data-account-id'), 10);
|
||||
this._xhrPromise =
|
||||
this.$.restAPI.deleteVote(this.change.id, accountID, labelName)
|
||||
.then(function(response) {
|
||||
if (!response.ok) { return response; }
|
||||
|
||||
var labels = this.change.labels[labelName].all || [];
|
||||
for (var i = 0; i < labels.length; i++) {
|
||||
if (labels[i]._account_id === accountID) {
|
||||
this.splice(['change.labels', labelName, 'all'], i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
@@ -77,5 +77,74 @@ limitations under the License.
|
||||
element.serverConfig = {note_db_enabled: true};
|
||||
assert.isTrue(hasCc());
|
||||
});
|
||||
|
||||
suite('remove reviewer votes', function() {
|
||||
var sandbox;
|
||||
setup(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.stub(element, '_computeValueTooltip').returns('');
|
||||
sandbox.stub(element, '_computeTopicReadOnly').returns(true);
|
||||
element.change = {
|
||||
status: 'NEW',
|
||||
submit_type: 'CHERRY_PICK',
|
||||
labels: {
|
||||
test: {
|
||||
all: [{_account_id: 1, name: 'bojack', value: 1}],
|
||||
default_value: 0,
|
||||
},
|
||||
},
|
||||
removable_reviewers: [],
|
||||
};
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
test('_computeCanDeleteVote hides delete button', function() {
|
||||
flushAsynchronousOperations();
|
||||
var button = element.$$('gr-account-chip').$$('gr-button');
|
||||
assert.isTrue(button.hasAttribute('hidden'));
|
||||
element.mutable = true;
|
||||
assert.isTrue(button.hasAttribute('hidden'));
|
||||
});
|
||||
|
||||
test('_computeCanDeleteVote shows delete button', function() {
|
||||
element.change.removable_reviewers = [
|
||||
{
|
||||
_account_id: 1,
|
||||
name: 'bojack',
|
||||
}
|
||||
];
|
||||
element.mutable = true;
|
||||
flushAsynchronousOperations();
|
||||
var button = element.$$('gr-account-chip').$$('gr-button');
|
||||
assert.isFalse(button.hasAttribute('hidden'));
|
||||
});
|
||||
|
||||
test('deletes votes', function(done) {
|
||||
sandbox.stub(element.$.restAPI, 'deleteVote')
|
||||
.returns(Promise.resolve({'ok': true}));
|
||||
element.change.removable_reviewers = [
|
||||
{
|
||||
_account_id: 1,
|
||||
name: 'bojack',
|
||||
}
|
||||
];
|
||||
element.mutable = true;
|
||||
flushAsynchronousOperations();
|
||||
var button = element.$$('gr-account-chip').$$('gr-button');
|
||||
MockInteractions.tap(button);
|
||||
flushAsynchronousOperations();
|
||||
var spliceStub = sinon.stub(element, 'splice',
|
||||
function(path, index, length) {
|
||||
assert.deepEqual(path, ['change.labels', 'test', 'all']);
|
||||
assert.equal(index, 0);
|
||||
assert.equal(length, 1);
|
||||
spliceStub.restore();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@@ -53,12 +53,17 @@ limitations under the License.
|
||||
padding: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
.transparentBackground,
|
||||
gr-button.transparentBackground {
|
||||
background-color: transparent;
|
||||
}
|
||||
</style>
|
||||
<div class="container">
|
||||
<div class$="container [[_getBackgroundClass(transparentBackground)]]">
|
||||
<gr-account-link account="[[account]]"></gr-account-link>
|
||||
<gr-button
|
||||
hidden$="[[!removable]]" hidden
|
||||
class="remove" on-tap="_handleRemoveTap">×</gr-button>
|
||||
class$="remove [[_getBackgroundClass(transparentBackground)]]"
|
||||
on-tap="_handleRemoveTap">×</gr-button>
|
||||
</div>
|
||||
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||
</template>
|
||||
|
@@ -28,6 +28,10 @@
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
transparentBackground: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
@@ -36,6 +40,10 @@
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_getBackgroundClass: function(transparent) {
|
||||
return transparent ? 'transparentBackground' : '';
|
||||
},
|
||||
|
||||
_handleRemoveTap: function(e) {
|
||||
e.preventDefault();
|
||||
this.fire('remove', {account: this.account});
|
||||
|
@@ -47,5 +47,6 @@ limitations under the License.
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
<script src="../../../scripts/util.js"></script>
|
||||
<script src="gr-account-label.js"></script>
|
||||
</dom-module>
|
||||
|
@@ -865,5 +865,10 @@
|
||||
deleteAccountSSHKey: function(id) {
|
||||
return this.send('DELETE', '/accounts/self/sshkeys/' + id);
|
||||
},
|
||||
|
||||
deleteVote: function(changeID, account, label) {
|
||||
return this.send('DELETE', '/changes/' + changeID +
|
||||
'/reviewers/' + account + '/votes/' + encodeURIComponent(label));
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
Reference in New Issue
Block a user