Introduce gr-label-info element
This element will be embedded inside a gr-hovercard, and will replace a large amount of functionality in the change metadata. Some of the code is copied from the change metadata. It will be deleted from there in a descendant change. Change-Id: I10a158dfd7e303e2a15b918e1980680b7f917e59
This commit is contained in:
parent
26d96c4c95
commit
5072d85704
@ -46,6 +46,8 @@ limitations under the License.
|
|||||||
<g id="deleteEdit"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></g>
|
<g id="deleteEdit"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></g>
|
||||||
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/editor-icons.html -->
|
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/editor-icons.html -->
|
||||||
<g id="publishEdit"><path d="M5 4v2h14V4H5zm0 10h4v6h6v-6h4l-7-7-7 7z"/></g>
|
<g id="publishEdit"><path d="M5 4v2h14V4H5zm0 10h4v6h6v-6h4l-7-7-7 7z"/></g>
|
||||||
|
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/editor-icons.html -->
|
||||||
|
<g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></g>
|
||||||
<!-- This SVG is a copy from material.io https://material.io/icons/#ic_hourglass_full-->
|
<!-- This SVG is a copy from material.io https://material.io/icons/#ic_hourglass_full-->
|
||||||
<g id="hourglass"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"/><path d="M0 0h24v24H0V0z" fill="none"/></g>
|
<g id="hourglass"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"/><path d="M0 0h24v24H0V0z" fill="none"/></g>
|
||||||
<!-- This is a custom PolyGerrit SVG -->
|
<!-- This is a custom PolyGerrit SVG -->
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
<!--
|
||||||
|
@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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||||
|
|
||||||
|
<link rel="import" href="../../../styles/gr-voting-styles.html">
|
||||||
|
<link rel="import" href="../../../styles/shared-styles.html">
|
||||||
|
<link rel="import" href="../gr-account-label/gr-account-label.html">
|
||||||
|
<link rel="import" href="../gr-button/gr-button.html">
|
||||||
|
<link rel="import" href="../gr-icons/gr-icons.html">
|
||||||
|
<link rel="import" href="../gr-label/gr-label.html">
|
||||||
|
<link rel="import" href="../gr-rest-api-interface/gr-rest-api-interface.html">
|
||||||
|
|
||||||
|
<dom-module id="gr-label-info">
|
||||||
|
<template strip-whitespace>
|
||||||
|
<style include="gr-voting-styles"></style>
|
||||||
|
<style include="shared-styles">
|
||||||
|
.title {
|
||||||
|
font-size: var(--font-size-large);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.placeholder {
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
padding-top: .5em;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.voteChip {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: .3em;
|
||||||
|
padding: .2em .85em;
|
||||||
|
@apply --vote-chip-styles;
|
||||||
|
}
|
||||||
|
.max {
|
||||||
|
background-color: var(--vote-color-approved);
|
||||||
|
}
|
||||||
|
.min {
|
||||||
|
background-color: var(--vote-color-rejected);
|
||||||
|
}
|
||||||
|
.positive {
|
||||||
|
background-color: var(--vote-color-recommended);
|
||||||
|
}
|
||||||
|
.negative {
|
||||||
|
background-color: var(--vote-color-disliked);
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
min-height: 2.25em;
|
||||||
|
}
|
||||||
|
tr td {
|
||||||
|
padding-top: .35em;
|
||||||
|
}
|
||||||
|
tr.currentUser td {
|
||||||
|
padding-bottom: .5em;
|
||||||
|
}
|
||||||
|
tr.currentUser + tr td {
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
padding-top: .5em;
|
||||||
|
}
|
||||||
|
gr-button {
|
||||||
|
--gr-button: {
|
||||||
|
height: 2em;
|
||||||
|
padding: 0;
|
||||||
|
width: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gr-account-chip {
|
||||||
|
margin-right: 1.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p class="title">[[label]]</p>
|
||||||
|
<p class$="placeholder [[_computeShowPlaceholder(labelInfo, change.labels.*)]]">
|
||||||
|
No votes for this label.
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<template
|
||||||
|
is="dom-repeat"
|
||||||
|
items="[[_mapLabelInfo(labelInfo, account, change.labels.*)]]"
|
||||||
|
as="mappedLabel">
|
||||||
|
<tr class$="labelValueContainer [[_computeLabelContainerClass(mappedLabel)]]">
|
||||||
|
<td>
|
||||||
|
<gr-account-chip
|
||||||
|
account="[[mappedLabel.account]]"
|
||||||
|
transparent-background></gr-account-chip>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<gr-label
|
||||||
|
has-tooltip
|
||||||
|
title="[[_computeValueTooltip(labelInfo, mappedLabel.value)]]"
|
||||||
|
class$="[[mappedLabel.className]] voteChip">
|
||||||
|
[[mappedLabel.value]]
|
||||||
|
</gr-label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<gr-button
|
||||||
|
link
|
||||||
|
aria-label="Remove"
|
||||||
|
on-tap="_onDeleteVote"
|
||||||
|
tooltip="Remove vote"
|
||||||
|
data-account-id$="[[mappedLabel.account._account_id]]"
|
||||||
|
class$="deleteBtn [[_computeDeleteClass(mappedLabel.account, mutable, change)]]">
|
||||||
|
<iron-icon icon="gr-icons:delete"></iron-icon>
|
||||||
|
</gr-button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</table>
|
||||||
|
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||||
|
</template>
|
||||||
|
<script src="gr-label-info.js"></script>
|
||||||
|
</dom-module>
|
186
polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.js
Normal file
186
polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.js
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Polymer({
|
||||||
|
is: 'gr-label-info',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
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) { 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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (label._account_id === account._account_id) {
|
||||||
|
// Put self-votes at the top, and add a flag.
|
||||||
|
result.unshift({
|
||||||
|
value: labelValPrefix + label.value,
|
||||||
|
className: labelClassName,
|
||||||
|
account: label,
|
||||||
|
isCurrentUser: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result.push({
|
||||||
|
value: labelValPrefix + label.value,
|
||||||
|
className: labelClassName,
|
||||||
|
account: label,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = Polymer.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 response; }
|
||||||
|
|
||||||
|
const label = this.change.labels[this.label];
|
||||||
|
const labels = label.all || [];
|
||||||
|
let wasChanged = false;
|
||||||
|
for (let i = 0; i < labels.length; i++) {
|
||||||
|
if (labels[i]._account_id === accountID) {
|
||||||
|
for (const key in label) {
|
||||||
|
if (label.hasOwnProperty(key) &&
|
||||||
|
label[key]._account_id === accountID) {
|
||||||
|
// Remove special label field, keeping change label values
|
||||||
|
// in sync with the backend.
|
||||||
|
this.change.labels[this.label][key] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.change.labels[this.label].all.splice(i, 1);
|
||||||
|
wasChanged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wasChanged) { this.notifySplices('change.labels'); }
|
||||||
|
}).catch(err => {
|
||||||
|
target.disabled = false;
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_computeValueTooltip(labelInfo, score) {
|
||||||
|
if (!labelInfo || !labelInfo.values || !labelInfo.values[score]) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return labelInfo.values[score];
|
||||||
|
},
|
||||||
|
|
||||||
|
_computeLabelContainerClass(label) {
|
||||||
|
return label.isCurrentUser ? 'currentUser' : '';
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.all) {
|
||||||
|
for (const label of labelInfo.all) {
|
||||||
|
if (label.value) { return 'hidden'; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();
|
@ -0,0 +1,230 @@
|
|||||||
|
<!--
|
||||||
|
@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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||||
|
<title>gr-label-info</title>
|
||||||
|
|
||||||
|
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
|
||||||
|
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
||||||
|
<link rel="import" href="../../../test/common-test-setup.html"/>
|
||||||
|
<link rel="import" href="gr-label-info.html">
|
||||||
|
|
||||||
|
<script>void(0);</script>
|
||||||
|
|
||||||
|
<test-fixture id="basic">
|
||||||
|
<template>
|
||||||
|
<gr-label-info></gr-label-info>
|
||||||
|
</template>
|
||||||
|
</test-fixture>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
suite('gr-account-link tests', () => {
|
||||||
|
let element;
|
||||||
|
let sandbox;
|
||||||
|
|
||||||
|
setup(() => {
|
||||||
|
element = fixture('basic');
|
||||||
|
sandbox = sinon.sandbox.create();
|
||||||
|
// Needed to trigger computed bindings.
|
||||||
|
element.account = {};
|
||||||
|
element.change = {labels: {}};
|
||||||
|
});
|
||||||
|
|
||||||
|
teardown(() => {
|
||||||
|
sandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('remove reviewer votes', () => {
|
||||||
|
setup(() => {
|
||||||
|
sandbox.stub(element, '_computeValueTooltip').returns('');
|
||||||
|
element.account = {
|
||||||
|
_account_id: 1,
|
||||||
|
name: 'bojack',
|
||||||
|
};
|
||||||
|
const test = {
|
||||||
|
all: [{_account_id: 1, name: 'bojack', value: 1}],
|
||||||
|
default_value: 0,
|
||||||
|
values: [],
|
||||||
|
};
|
||||||
|
element.change = {
|
||||||
|
_number: 42,
|
||||||
|
change_id: 'the id',
|
||||||
|
actions: [],
|
||||||
|
topic: 'the topic',
|
||||||
|
status: 'NEW',
|
||||||
|
submit_type: 'CHERRY_PICK',
|
||||||
|
labels: {test},
|
||||||
|
removable_reviewers: [],
|
||||||
|
};
|
||||||
|
element.labelInfo = test;
|
||||||
|
element.label = 'test';
|
||||||
|
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_computeCanDeleteVote', () => {
|
||||||
|
element.mutable = false;
|
||||||
|
const button = element.$$('gr-button');
|
||||||
|
assert.isTrue(isHidden(button));
|
||||||
|
element.change.removable_reviewers = [element.account];
|
||||||
|
element.mutable = true;
|
||||||
|
assert.isFalse(isHidden(button));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deletes votes', () => {
|
||||||
|
const deleteResponse = Promise.resolve({ok: true});
|
||||||
|
const deleteStub = sandbox.stub(
|
||||||
|
element.$.restAPI, 'deleteVote').returns(deleteResponse);
|
||||||
|
|
||||||
|
element.change.removable_reviewers = [element.account];
|
||||||
|
element.change.labels.test.recommended = {_account_id: 1};
|
||||||
|
element.mutable = true;
|
||||||
|
const button = element.$$('gr-button');
|
||||||
|
MockInteractions.tap(button);
|
||||||
|
assert.isTrue(button.disabled);
|
||||||
|
return deleteResponse.then(() => {
|
||||||
|
assert.isFalse(button.disabled);
|
||||||
|
assert.notOk(element.change.labels.test.recommended);
|
||||||
|
assert.isTrue(deleteStub.calledWithExactly(42, 1, 'test'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('label color and order', () => {
|
||||||
|
test('valueless label rejected', () => {
|
||||||
|
element.labelInfo = {rejected: {name: 'someone'}};
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
const labels = Polymer.dom(element.root).querySelectorAll('gr-label');
|
||||||
|
assert.isTrue(labels[0].classList.contains('negative'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('valueless label approved', () => {
|
||||||
|
element.labelInfo = {approved: {name: 'someone'}};
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
const labels = Polymer.dom(element.root).querySelectorAll('gr-label');
|
||||||
|
assert.isTrue(labels[0].classList.contains('positive'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('-2 to +2', () => {
|
||||||
|
element.labelInfo = {
|
||||||
|
all: [
|
||||||
|
{value: 2, name: 'user 2'},
|
||||||
|
{value: 1, name: 'user 1'},
|
||||||
|
{value: -1, name: 'user 3'},
|
||||||
|
{value: -2, name: 'user 4'},
|
||||||
|
],
|
||||||
|
values: {
|
||||||
|
'-2': 'Awful',
|
||||||
|
'-1': 'Don\'t submit as-is',
|
||||||
|
' 0': 'No score',
|
||||||
|
'+1': 'Looks good to me',
|
||||||
|
'+2': 'Ready to submit',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
const labels = Polymer.dom(element.root).querySelectorAll('gr-label');
|
||||||
|
assert.isTrue(labels[0].classList.contains('max'));
|
||||||
|
assert.isTrue(labels[1].classList.contains('positive'));
|
||||||
|
assert.isTrue(labels[2].classList.contains('negative'));
|
||||||
|
assert.isTrue(labels[3].classList.contains('min'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('-1 to +1', () => {
|
||||||
|
element.labelInfo = {
|
||||||
|
all: [
|
||||||
|
{value: 1, name: 'user 1'},
|
||||||
|
{value: -1, name: 'user 2'},
|
||||||
|
],
|
||||||
|
values: {
|
||||||
|
'-1': 'Don\'t submit as-is',
|
||||||
|
' 0': 'No score',
|
||||||
|
'+1': 'Looks good to me',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
const labels = Polymer.dom(element.root).querySelectorAll('gr-label');
|
||||||
|
assert.isTrue(labels[0].classList.contains('max'));
|
||||||
|
assert.isTrue(labels[1].classList.contains('min'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('0 to +2', () => {
|
||||||
|
element.labelInfo = {
|
||||||
|
all: [
|
||||||
|
{value: 1, name: 'user 2'},
|
||||||
|
{value: 2, name: 'user '},
|
||||||
|
],
|
||||||
|
values: {
|
||||||
|
' 0': 'Don\'t submit as-is',
|
||||||
|
'+1': 'No score',
|
||||||
|
'+2': 'Looks good to me',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
const labels = Polymer.dom(element.root).querySelectorAll('gr-label');
|
||||||
|
assert.isTrue(labels[0].classList.contains('max'));
|
||||||
|
assert.isTrue(labels[1].classList.contains('positive'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('self votes at top', () => {
|
||||||
|
element.account = {
|
||||||
|
_account_id: 1,
|
||||||
|
name: 'bojack',
|
||||||
|
};
|
||||||
|
element.labelInfo = {
|
||||||
|
all: [
|
||||||
|
{value: 1, name: 'user 1', _account_id: 2},
|
||||||
|
{value: -1, name: 'bojack', _account_id: 1},
|
||||||
|
],
|
||||||
|
values: {
|
||||||
|
'-1': 'Don\'t submit as-is',
|
||||||
|
' 0': 'No score',
|
||||||
|
'+1': 'Looks good to me',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
const chips =
|
||||||
|
Polymer.dom(element.root).querySelectorAll('gr-account-chip');
|
||||||
|
assert.equal(chips[0].account._account_id, element.account._account_id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_computeValueTooltip', () => {
|
||||||
|
// Existing label.
|
||||||
|
let labelInfo = {values: {0: 'Baz'}};
|
||||||
|
let score = '0';
|
||||||
|
assert.equal(element._computeValueTooltip(labelInfo, score), 'Baz');
|
||||||
|
|
||||||
|
// Non-exsistent score.
|
||||||
|
score = '2';
|
||||||
|
assert.equal(element._computeValueTooltip(labelInfo, score), '');
|
||||||
|
|
||||||
|
// No values on label.
|
||||||
|
labelInfo = {values: {}};
|
||||||
|
score = '0';
|
||||||
|
assert.equal(element._computeValueTooltip(labelInfo, score), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('placeholder', () => {
|
||||||
|
element.labelInfo = {};
|
||||||
|
assert.isFalse(isHidden(element.$$('.placeholder')));
|
||||||
|
element.labelInfo = {all: []};
|
||||||
|
assert.isFalse(isHidden(element.$$('.placeholder')));
|
||||||
|
element.labelInfo = {all: [{value: 1}]};
|
||||||
|
assert.isTrue(isHidden(element.$$('.placeholder')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
@ -35,7 +35,7 @@ limitations under the License.
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
// eslint-disable-next-line no-unused-vars
|
/* eslint-disable no-unused-vars */
|
||||||
const mockPromise = () => {
|
const mockPromise = () => {
|
||||||
let res;
|
let res;
|
||||||
const promise = new Promise(resolve => {
|
const promise = new Promise(resolve => {
|
||||||
@ -44,6 +44,8 @@ limitations under the License.
|
|||||||
promise.resolve = res;
|
promise.resolve = res;
|
||||||
return promise;
|
return promise;
|
||||||
};
|
};
|
||||||
|
const isHidden = el => getComputedStyle(el).display === 'none';
|
||||||
|
/* eslint-enable no-unused-vars */
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user