blob: 22bdce16d222cf6a3f455722fa4bbeb3182d16c9 [file] [log] [blame]
/**
* @license
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-voting-styles.js';
import '../../../styles/shared-styles.js';
import '../gr-account-label/gr-account-label.js';
import '../gr-account-chip/gr-account-chip.js';
import '../gr-button/gr-button.js';
import '../gr-icons/gr-icons.js';
import '../gr-label/gr-label.js';
import '../gr-rest-api-interface/gr-rest-api-interface.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-label-info_html.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/** @extends Polymer.Element */
class GrLabelInfo extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
static get template() { return htmlTemplate; }
static get is() { return 'gr-label-info'; }
static get properties() {
return {
labelInfo: Object,
label: String,
/** @type {?} */
change: Object,
account: Object,
mutable: Boolean,
};
}
/**
* @param {!Object} labelInfo
* @param {!Object} account
* @param {Object} changeLabelsRecord not used, but added as a parameter in
* order to trigger computation when a label is removed from the change.
*/
_mapLabelInfo(labelInfo, account, changeLabelsRecord) {
const result = [];
if (!labelInfo || !account) { return result; }
if (!labelInfo.values) {
if (labelInfo.rejected || labelInfo.approved) {
const ok = labelInfo.approved || !labelInfo.rejected;
return [{
value: ok ? '👍️' : '👎️',
className: ok ? 'positive' : 'negative',
account: ok ? labelInfo.approved : labelInfo.rejected,
}];
}
return result;
}
// Sort votes by positivity.
const votes = (labelInfo.all || []).sort((a, b) => a.value - b.value);
const values = Object.keys(labelInfo.values);
for (const label of votes) {
if (label.value && label.value != labelInfo.default_value) {
let labelClassName;
let labelValPrefix = '';
if (label.value > 0) {
labelValPrefix = '+';
if (parseInt(label.value, 10) ===
parseInt(values[values.length - 1], 10)) {
labelClassName = 'max';
} else {
labelClassName = 'positive';
}
} else if (label.value < 0) {
if (parseInt(label.value, 10) === parseInt(values[0], 10)) {
labelClassName = 'min';
} else {
labelClassName = 'negative';
}
}
const formattedLabel = {
value: labelValPrefix + label.value,
className: labelClassName,
account: label,
};
if (label._account_id === account._account_id) {
// Put self-votes at the top.
result.unshift(formattedLabel);
} else {
result.push(formattedLabel);
}
}
}
return result;
}
/**
* 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
* @param {!Object} change
*/
_computeDeleteClass(reviewer, mutable, change) {
if (!mutable || !change || !change.removable_reviewers) {
return 'hidden';
}
const removable = change.removable_reviewers;
if (removable.find(r => r._account_id === reviewer._account_id)) {
return '';
}
return 'hidden';
}
/**
* Closure annotation for Polymer.prototype.splice is off.
* For now, supressing annotations.
*
* @suppress {checkTypes} */
_onDeleteVote(e) {
e.preventDefault();
let target = dom(e).rootTarget;
while (!target.classList.contains('deleteBtn')) {
if (!target.parentElement) { return; }
target = target.parentElement;
}
target.disabled = true;
const accountID = parseInt(target.getAttribute('data-account-id'), 10);
this._xhrPromise =
this.$.restAPI.deleteVote(this.change._number, accountID, this.label)
.then(response => {
target.disabled = false;
if (!response.ok) { return; }
GerritNav.navigateToChange(this.change);
})
.catch(err => {
target.disabled = false;
return;
});
}
_computeValueTooltip(labelInfo, score) {
if (!labelInfo || !labelInfo.values || !labelInfo.values[score]) {
return '';
}
return labelInfo.values[score];
}
/**
* @param {!Object} labelInfo
* @param {Object} changeLabelsRecord not used, but added as a parameter in
* order to trigger computation when a label is removed from the change.
*/
_computeShowPlaceholder(labelInfo, changeLabelsRecord) {
if (labelInfo &&
!labelInfo.values && (labelInfo.rejected || labelInfo.approved)) {
return 'hidden';
}
if (labelInfo && labelInfo.all) {
for (const label of labelInfo.all) {
if (label.value && label.value != labelInfo.default_value) {
return 'hidden';
}
}
}
return '';
}
}
customElements.define(GrLabelInfo.is, GrLabelInfo);