blob: 2a614a70fbc6383582e7a75d54c7406d33cfab7d [file] [log] [blame]
/**
* @license
* Copyright (C) 2022 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 '../../change/gr-submit-requirement-dashboard-hovercard/gr-submit-requirement-dashboard-hovercard';
import '../../shared/gr-change-status/gr-change-status';
import {LitElement, css, html} from 'lit';
import {customElement, property} from 'lit/decorators';
import {
ApprovalInfo,
ChangeInfo,
isDetailedLabelInfo,
LabelInfo,
SubmitRequirementResultInfo,
SubmitRequirementStatus,
} from '../../../api/rest-api';
import {submitRequirementsStyles} from '../../../styles/gr-submit-requirements-styles';
import {
extractAssociatedLabels,
getAllUniqueApprovals,
getRequirements,
hasNeutralStatus,
iconForStatus,
} from '../../../utils/label-util';
import {sharedStyles} from '../../../styles/shared-styles';
@customElement('gr-change-list-column-requirement')
export class GrChangeListColumnRequirement extends LitElement {
@property({type: Object})
change?: ChangeInfo;
@property()
labelName?: string;
static override get styles() {
return [
submitRequirementsStyles,
sharedStyles,
css`
iron-icon {
vertical-align: top;
}
.container {
display: flex;
align-items: center;
justify-content: center;
}
.container.not-applicable {
background-color: var(--table-header-background-color);
height: calc(var(--line-height-normal) + var(--spacing-m));
}
`,
];
}
override render() {
return html`<div class="container ${this.computeClass()}">
${this.renderContent()}
</div>`;
}
private renderContent() {
if (!this.labelName) return;
const requirements = this.getRequirement(this.labelName);
if (requirements.length === 0) return;
const requirement = requirements[0];
if (requirement.status === SubmitRequirementStatus.UNSATISFIED) {
return this.renderUnsatisfiedState(requirement);
} else {
return this.renderStatusIcon(requirement.status);
}
}
private renderUnsatisfiedState(requirement: SubmitRequirementResultInfo) {
const requirementLabels = extractAssociatedLabels(
requirement,
'onlySubmittability'
);
const allLabels = this.change?.labels ?? {};
const associatedLabels = Object.keys(allLabels).filter(label =>
requirementLabels.includes(label)
);
let worstVote: ApprovalInfo | undefined;
let labelInfo: LabelInfo | undefined;
for (const label of associatedLabels) {
const votes = this.getSortedVotes(label);
if (votes.length === 0) break;
// votes are already sorted from worst e.g -2 to best e.g +2
if (!worstVote || (worstVote.value ?? 0) > (votes[0].value ?? 0)) {
worstVote = votes[0];
labelInfo = allLabels[label];
}
}
if (worstVote === undefined) {
return this.renderStatusIcon(requirement.status);
} else {
return html`<gr-vote-chip
.vote="${worstVote}"
.label="${labelInfo}"
></gr-vote-chip>`;
}
}
private renderStatusIcon(status: SubmitRequirementStatus) {
const icon = iconForStatus(status ?? SubmitRequirementStatus.ERROR);
return html`<iron-icon
class="${icon}"
icon="gr-icons:${icon}"
></iron-icon>`;
}
private computeClass(): string {
if (!this.labelName) return '';
const requirements = this.getRequirement(this.labelName);
if (requirements.length === 0) {
return 'not-applicable';
}
return '';
}
private getRequirement(labelName: string) {
const requirements = getRequirements(this.change).filter(
sr => sr.name === labelName
);
// TODO(milutin): Remove this after migration from legacy requirements.
if (requirements.length > 1) {
return requirements.filter(sr => !sr.is_legacy);
} else {
return requirements;
}
}
private getSortedVotes(label: string) {
const allLabels = this.change?.labels ?? {};
const labelInfo = allLabels[label];
if (isDetailedLabelInfo(labelInfo)) {
return getAllUniqueApprovals(labelInfo)
.filter(approval => !hasNeutralStatus(labelInfo, approval))
.sort((a, b) => (a.value ?? 0) - (b.value ?? 0));
}
return [];
}
}
declare global {
interface HTMLElementTagNameMap {
'gr-change-list-column-requirement': GrChangeListColumnRequirement;
}
}