blob: 2d76e474ac3589e363eac9c306c82d992d30cb83 [file] [log] [blame]
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../gr-trigger-vote/gr-trigger-vote';
import '../../checks/gr-checks-chip-for-label';
import {css, html, LitElement, nothing} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {ChangeInfo, PatchSetNumber} from '../../../api/rest-api';
import {LabelExtreme} from '../../../utils/comment-util';
import {getTriggerVotes} from '../../../utils/label-util';
import {ChangeMessage} from '../../../types/common';
import {CheckRun} from '../../../api/checks';
import {subscribe} from '../../lit/subscription-controller';
import {resolve} from '../../../models/dependency';
import {changeModelToken} from '../../../models/change/change-model';
import {getScores, Score, VOTE_RESET_TEXT} from '../../../utils/message-util';
@customElement('gr-message-scores')
export class GrMessageScores extends LitElement {
@property()
labelExtremes?: LabelExtreme;
@property({type: Object})
message?: ChangeMessage;
@property({type: Object})
change?: ChangeInfo;
@state() runs: CheckRun[] = [];
@state() latestPatchNum?: PatchSetNumber;
static override get styles() {
return css`
.score,
gr-trigger-vote {
padding: 0 var(--spacing-s);
margin-right: var(--spacing-s);
display: inline-block;
}
.score {
box-sizing: border-box;
border-radius: var(--border-radius);
color: var(--vote-text-color);
text-align: center;
min-width: 115px;
}
.score.removed {
background-color: var(--vote-color-neutral);
}
.score.negative {
background-color: var(--vote-color-disliked);
border: 1px solid var(--vote-outline-disliked);
line-height: calc(var(--line-height-normal) - 2px);
color: var(--chip-color);
}
.score.negative.min {
background-color: var(--vote-color-rejected);
border: none;
padding-top: 1px;
padding-bottom: 1px;
color: var(--vote-text-color);
}
.score.positive {
background-color: var(--vote-color-recommended);
border: 1px solid var(--vote-outline-recommended);
line-height: calc(var(--line-height-normal) - 2px);
color: var(--chip-color);
}
.score.positive.max {
background-color: var(--vote-color-approved);
border: none;
padding-top: 1px;
padding-bottom: 1px;
color: var(--vote-text-color);
}
@media screen and (max-width: 50em) {
.score {
min-width: 0px;
}
}
gr-checks-chip-for-label {
/* .checksChip has top: 2px, this is canceling it */
position: relative;
top: -2px;
}
`;
}
private readonly getChangeModel = resolve(this, changeModelToken);
constructor() {
super();
subscribe(
this,
() => this.getChangeModel().latestPatchNum$,
x => (this.latestPatchNum = x)
);
}
override render() {
const scores = getScores(this.message, this.labelExtremes);
const triggerVotes = getTriggerVotes(this.change);
return scores.map(score => this.renderScore(score, triggerVotes));
}
private renderScore(score: Score, triggerVotes: string[]) {
if (
score.label &&
triggerVotes.includes(score.label) &&
!score.value?.includes(VOTE_RESET_TEXT)
) {
const labels = this.change?.labels ?? {};
return html`<gr-trigger-vote
.label=${score.label}
.displayValue=${score.value}
.labelInfo=${labels[score.label]}
.change=${this.change}
.mutable=${false}
disable-hovercards
>
</gr-trigger-vote>`;
}
return html`<span
class="score ${this._computeScoreClass(score, this.labelExtremes)}"
>
${score.label} ${score.value} </span
>${this.renderChecks(score)}`;
}
renderChecks(score: Score) {
const labelName = score.label;
if (!labelName) return nothing;
if (Number(score.value) >= 0) return nothing;
if (this.latestPatchNum !== this.message?._revision_number) return nothing;
return html`<gr-checks-chip-for-label
.labels=${[labelName]}
.showRunning=${false}
></gr-checks-chip-for-label>`;
}
_computeScoreClass(score?: Score, labelExtremes?: LabelExtreme) {
if (score === undefined || labelExtremes === undefined) {
return '';
}
if (!score.value) {
return '';
}
if (score.value.includes(VOTE_RESET_TEXT)) {
return 'removed';
}
const classes = [];
if (Number(score.value) > 0) {
classes.push('positive');
} else if (Number(score.value) < 0) {
classes.push('negative');
}
if (score.label) {
const extremes = labelExtremes[score.label];
if (extremes) {
const intScore = Number(score.value);
if (intScore === extremes.max) {
classes.push('max');
} else if (intScore === extremes.min) {
classes.push('min');
}
}
}
return classes.join(' ');
}
}
declare global {
interface HTMLElementTagNameMap {
'gr-message-scores': GrMessageScores;
}
}