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="../../../bower_components/polymer/polymer.html">
|
||||||
<link rel="import" href="../../../behaviors/rest-client-behavior.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-label/gr-label.html">
|
||||||
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.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">
|
<link rel="import" href="../../shared/gr-editable-label/gr-editable-label.html">
|
||||||
@@ -45,12 +45,13 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
.labelValueContainer .approved,
|
.labelValueContainer .approved,
|
||||||
.labelValueContainer .notApproved {
|
.labelValueContainer .notApproved {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
padding: .1em .3em;
|
padding: .1em .3em;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
.labelValue {
|
.labelValue {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
padding-right: .3em;
|
||||||
}
|
}
|
||||||
.approved {
|
.approved {
|
||||||
background-color: #d4ffd4;
|
background-color: #d4ffd4;
|
||||||
@@ -150,7 +151,7 @@ limitations under the License.
|
|||||||
<span class="title">[[labelName]]</span>
|
<span class="title">[[labelName]]</span>
|
||||||
<span class="value">
|
<span class="value">
|
||||||
<template is="dom-repeat"
|
<template is="dom-repeat"
|
||||||
items="[[_computeLabelValues(labelName, change.labels)]]"
|
items="[[_computeLabelValues(labelName, change.labels.*)]]"
|
||||||
as="label">
|
as="label">
|
||||||
<div class="labelValueContainer">
|
<div class="labelValueContainer">
|
||||||
<span class$="[[label.className]]">
|
<span class$="[[label.className]]">
|
||||||
@@ -160,7 +161,13 @@ limitations under the License.
|
|||||||
class="labelValue">
|
class="labelValue">
|
||||||
[[label.value]]
|
[[label.value]]
|
||||||
</gr-label>
|
</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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -55,8 +55,9 @@
|
|||||||
return Object.keys(labels).sort();
|
return Object.keys(labels).sort();
|
||||||
},
|
},
|
||||||
|
|
||||||
_computeLabelValues: function(labelName, labels) {
|
_computeLabelValues: function(labelName, _labels) {
|
||||||
var result = [];
|
var result = [];
|
||||||
|
var labels = _labels.base;
|
||||||
var t = labels[labelName];
|
var t = labels[labelName];
|
||||||
if (!t) { return result; }
|
if (!t) { return result; }
|
||||||
var approvals = t.all || [];
|
var approvals = t.all || [];
|
||||||
@@ -101,5 +102,46 @@
|
|||||||
_computeShowReviewersByState: function(serverConfig) {
|
_computeShowReviewersByState: function(serverConfig) {
|
||||||
return !!serverConfig.note_db_enabled;
|
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};
|
element.serverConfig = {note_db_enabled: true};
|
||||||
assert.isTrue(hasCc());
|
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>
|
</script>
|
||||||
|
@@ -53,12 +53,17 @@ limitations under the License.
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.transparentBackground,
|
||||||
|
gr-button.transparentBackground {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container">
|
<div class$="container [[_getBackgroundClass(transparentBackground)]]">
|
||||||
<gr-account-link account="[[account]]"></gr-account-link>
|
<gr-account-link account="[[account]]"></gr-account-link>
|
||||||
<gr-button
|
<gr-button
|
||||||
hidden$="[[!removable]]" hidden
|
hidden$="[[!removable]]" hidden
|
||||||
class="remove" on-tap="_handleRemoveTap">×</gr-button>
|
class$="remove [[_getBackgroundClass(transparentBackground)]]"
|
||||||
|
on-tap="_handleRemoveTap">×</gr-button>
|
||||||
</div>
|
</div>
|
||||||
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -28,6 +28,10 @@
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
reflectToAttribute: true,
|
reflectToAttribute: true,
|
||||||
},
|
},
|
||||||
|
transparentBackground: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
ready: function() {
|
ready: function() {
|
||||||
@@ -36,6 +40,10 @@
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getBackgroundClass: function(transparent) {
|
||||||
|
return transparent ? 'transparentBackground' : '';
|
||||||
|
},
|
||||||
|
|
||||||
_handleRemoveTap: function(e) {
|
_handleRemoveTap: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.fire('remove', {account: this.account});
|
this.fire('remove', {account: this.account});
|
||||||
|
@@ -47,5 +47,6 @@ limitations under the License.
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<script src="../../../scripts/util.js"></script>
|
||||||
<script src="gr-account-label.js"></script>
|
<script src="gr-account-label.js"></script>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
@@ -865,5 +865,10 @@
|
|||||||
deleteAccountSSHKey: function(id) {
|
deleteAccountSSHKey: function(id) {
|
||||||
return this.send('DELETE', '/accounts/self/sshkeys/' + 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