| /** |
| * @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 '../../../styles/shared-styles'; |
| import '../../shared/gr-button/gr-button'; |
| import '../../shared/gr-icons/gr-icons'; |
| import '../../shared/gr-label/gr-label'; |
| import '../../shared/gr-label-info/gr-label-info'; |
| import '../../shared/gr-limited-text/gr-limited-text'; |
| import {PolymerElement} from '@polymer/polymer/polymer-element'; |
| import {htmlTemplate} from './gr-change-requirements_html'; |
| import {customElement, property, observe} from '@polymer/decorators'; |
| import { |
| ChangeInfo, |
| AccountInfo, |
| QuickLabelInfo, |
| Requirement, |
| RequirementType, |
| LabelNameToInfoMap, |
| LabelInfo, |
| } from '../../../types/common'; |
| import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces'; |
| import {appContext} from '../../../services/app-context'; |
| import {labelCompare} from '../../../utils/label-util'; |
| |
| interface ChangeRequirement extends Requirement { |
| satisfied: boolean; |
| style: string; |
| } |
| |
| interface ChangeWIP { |
| type: RequirementType; |
| fallback_text: string; |
| tooltip: string; |
| } |
| |
| interface Label { |
| labelName: string; |
| labelInfo: LabelInfo; |
| icon: string; |
| style: string; |
| } |
| |
| @customElement('gr-change-requirements') |
| class GrChangeRequirements extends PolymerElement { |
| static get template() { |
| return htmlTemplate; |
| } |
| |
| @property({type: Object}) |
| change?: ChangeInfo; |
| |
| @property({type: Object}) |
| account?: AccountInfo; |
| |
| @property({type: Boolean}) |
| mutable?: boolean; |
| |
| @property({type: Array, computed: '_computeRequirements(change)'}) |
| _requirements?: Array<ChangeRequirement | ChangeWIP>; |
| |
| @property({type: Array}) |
| _requiredLabels: Label[] = []; |
| |
| @property({type: Array}) |
| _optionalLabels: Label[] = []; |
| |
| @property({type: Boolean, computed: '_computeShowWip(change)'}) |
| _showWip?: boolean; |
| |
| @property({type: Boolean}) |
| _showOptionalLabels = true; |
| |
| private readonly reporting = appContext.reportingService; |
| |
| _computeShowWip(change: ChangeInfo) { |
| return change.work_in_progress; |
| } |
| |
| _computeRequirements(change: ChangeInfo) { |
| const _requirements: Array<ChangeRequirement | ChangeWIP> = []; |
| |
| if (change.requirements) { |
| for (const requirement of change.requirements) { |
| const satisfied = requirement.status === 'OK'; |
| const style = this._computeRequirementClass(satisfied); |
| _requirements.push({...requirement, satisfied, style}); |
| } |
| } |
| if (change.work_in_progress) { |
| _requirements.push({ |
| type: 'wip' as RequirementType, |
| fallback_text: 'Work-in-progress', |
| tooltip: "Change must not be in 'Work in Progress' state.", |
| }); |
| } |
| |
| return _requirements; |
| } |
| |
| _computeRequirementClass(requirementStatus: boolean) { |
| return requirementStatus ? 'approved' : ''; |
| } |
| |
| _computeRequirementIcon(requirementStatus: boolean) { |
| return requirementStatus ? 'gr-icons:check' : 'gr-icons:schedule'; |
| } |
| |
| @observe('change.labels.*') |
| _computeLabels( |
| labelsRecord: PolymerDeepPropertyChange< |
| LabelNameToInfoMap, |
| LabelNameToInfoMap |
| > |
| ) { |
| const labels = labelsRecord.base || {}; |
| const allLabels: Label[] = []; |
| |
| for (const label of Object.keys(labels).sort(labelCompare)) { |
| allLabels.push({ |
| labelName: label, |
| icon: this._computeLabelIcon(labels[label]), |
| style: this._computeLabelClass(labels[label]), |
| labelInfo: labels[label], |
| }); |
| } |
| this._optionalLabels = allLabels.filter(label => label.labelInfo.optional); |
| this._requiredLabels = allLabels.filter(label => !label.labelInfo.optional); |
| } |
| |
| /** |
| * @return The icon name, or undefined if no icon should |
| * be used. |
| */ |
| _computeLabelIcon(labelInfo: QuickLabelInfo) { |
| if (labelInfo.approved) { |
| return 'gr-icons:check'; |
| } |
| if (labelInfo.rejected) { |
| return 'gr-icons:close'; |
| } |
| return 'gr-icons:schedule'; |
| } |
| |
| _computeLabelClass(labelInfo: QuickLabelInfo) { |
| if (labelInfo.approved) { |
| return 'approved'; |
| } |
| if (labelInfo.rejected) { |
| return 'rejected'; |
| } |
| return ''; |
| } |
| |
| _computeShowOptional( |
| optionalFieldsRecord: PolymerDeepPropertyChange<Label[], Label[]> |
| ) { |
| return optionalFieldsRecord.base.length ? '' : 'hidden'; |
| } |
| |
| _computeLabelValue(value: number) { |
| return `${value > 0 ? '+' : ''}${value}`; |
| } |
| |
| _computeSectionClass(show: boolean) { |
| return show ? '' : 'hidden'; |
| } |
| |
| _handleShowHide() { |
| this._showOptionalLabels = !this._showOptionalLabels; |
| this.reporting.reportInteraction('toggle show all button', { |
| sectionName: 'optional labels', |
| toState: this._showOptionalLabels ? 'Show all' : 'Show less', |
| }); |
| } |
| |
| _computeSubmitRequirementEndpoint(item: ChangeRequirement | ChangeWIP) { |
| return `submit-requirement-item-${item.type}`; |
| } |
| |
| _computeShowAllLabelText(_showOptionalLabels: boolean) { |
| if (_showOptionalLabels) { |
| return 'Show less'; |
| } else { |
| return 'Show all'; |
| } |
| } |
| } |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| 'gr-change-requirements': GrChangeRequirements; |
| } |
| } |