| /** |
| * @license |
| * Copyright (C) 2021 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 '@polymer/paper-tooltip/paper-tooltip'; |
| import '@polymer/iron-icon/iron-icon'; |
| import {LitElement, css, html, PropertyValues, nothing} from 'lit'; |
| import {customElement, property, state} from 'lit/decorators'; |
| import {RunResult} from '../../models/checks/checks-model'; |
| import {iconFor} from '../../models/checks/checks-util'; |
| import {modifierPressed} from '../../utils/dom-util'; |
| import './gr-checks-results'; |
| import './gr-hovercard-run'; |
| import {fontStyles} from '../../styles/gr-font-styles'; |
| |
| @customElement('gr-diff-check-result') |
| export class GrDiffCheckResult extends LitElement { |
| @property({attribute: false}) |
| result?: RunResult; |
| |
| /** |
| * This is required by <gr-diff> as an identifier for this component. It will |
| * be set to the internalResultId of the check result. |
| */ |
| @property({type: String}) |
| rootId?: string; |
| |
| @state() |
| isExpanded = false; |
| |
| @state() |
| isExpandable = false; |
| |
| static override get styles() { |
| return [ |
| fontStyles, |
| css` |
| .container { |
| font-family: var(--font-family); |
| margin: 0 var(--spacing-s) var(--spacing-s); |
| background-color: var(--unresolved-comment-background-color); |
| box-shadow: var(--elevation-level-2); |
| border-radius: var(--border-radius); |
| padding: var(--spacing-xs) var(--spacing-m); |
| border: 1px solid #888; |
| } |
| .container.info { |
| border-color: var(--info-foreground); |
| background-color: var(--info-background); |
| } |
| .container.info .icon { |
| color: var(--info-foreground); |
| } |
| .container.warning { |
| border-color: var(--warning-foreground); |
| background-color: var(--warning-background); |
| } |
| .container.warning .icon { |
| color: var(--warning-foreground); |
| } |
| .container.error { |
| border-color: var(--error-foreground); |
| background-color: var(--error-background); |
| } |
| .container.error .icon { |
| color: var(--error-foreground); |
| } |
| .header { |
| display: flex; |
| white-space: nowrap; |
| cursor: pointer; |
| } |
| .icon { |
| margin-right: var(--spacing-s); |
| } |
| .name { |
| margin-right: var(--spacing-m); |
| } |
| .summary { |
| font-weight: var(--font-weight-bold); |
| flex-shrink: 1; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| margin-right: var(--spacing-s); |
| } |
| .message { |
| flex-grow: 1; |
| /* Looks a bit unexpected, but the idea is that .message shrinks |
| first, and only when that has shrunken to 0, then .summary should |
| also start shrinking (substantially). */ |
| flex-shrink: 1000000; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| color: var(--deemphasized-text-color); |
| } |
| gr-result-expanded { |
| display: block; |
| margin-top: var(--spacing-m); |
| } |
| iron-icon { |
| width: var(--line-height-normal); |
| height: var(--line-height-normal); |
| vertical-align: top; |
| } |
| .icon iron-icon { |
| width: calc(var(--line-height-normal) - 4px); |
| height: calc(var(--line-height-normal) - 4px); |
| position: relative; |
| top: 2px; |
| } |
| `, |
| ]; |
| } |
| |
| override render() { |
| if (!this.result) return; |
| const cat = this.result.category.toLowerCase(); |
| return html` |
| <div class="${cat} container font-normal"> |
| <div class="header" @click=${this.toggleExpandedClick}> |
| <div class="icon"> |
| <iron-icon |
| icon="gr-icons:${iconFor(this.result.category)}" |
| ></iron-icon> |
| </div> |
| <div class="name"> |
| <gr-hovercard-run .run=${this.result}></gr-hovercard-run> |
| <div |
| class="name" |
| role="button" |
| tabindex="0" |
| @keydown=${this.toggleExpandedPress} |
| > |
| ${this.result.checkName} |
| </div> |
| </div> |
| <!-- The is for being able to shrink a tiny amount without |
| the text itself getting shrunk with an ellipsis. --> |
| <div class="summary">${this.result.summary} </div> |
| <div class="message"> |
| ${this.isExpanded ? nothing : this.result.message} |
| </div> |
| ${this.renderToggle()} |
| </div> |
| <div class="details">${this.renderExpanded()}</div> |
| </div> |
| `; |
| } |
| |
| private renderToggle() { |
| if (!this.isExpandable) return nothing; |
| return html` |
| <div |
| class="show-hide" |
| role="switch" |
| tabindex="0" |
| aria-checked=${this.isExpanded ? 'true' : 'false'} |
| aria-label=${this.isExpanded |
| ? 'Collapse result row' |
| : 'Expand result row'} |
| @keydown=${this.toggleExpandedPress} |
| > |
| <iron-icon |
| icon=${this.isExpanded |
| ? 'gr-icons:expand-less' |
| : 'gr-icons:expand-more'} |
| ></iron-icon> |
| </div> |
| `; |
| } |
| |
| private renderExpanded() { |
| if (!this.isExpanded) return nothing; |
| return html` |
| <gr-result-expanded |
| hidecodepointers |
| .result=${this.result} |
| ></gr-result-expanded> |
| `; |
| } |
| |
| override updated(changedProperties: PropertyValues) { |
| if (changedProperties.has('result')) { |
| this.isExpandable = !!this.result?.summary && !!this.result?.message; |
| } |
| } |
| |
| private toggleExpandedClick(e: MouseEvent) { |
| if (!this.isExpandable) return; |
| e.preventDefault(); |
| e.stopPropagation(); |
| this.toggleExpanded(); |
| } |
| |
| private toggleExpandedPress(e: KeyboardEvent) { |
| if (!this.isExpandable) return; |
| if (modifierPressed(e)) return; |
| // Only react to `return` and `space`. |
| if (e.keyCode !== 13 && e.keyCode !== 32) return; |
| e.preventDefault(); |
| e.stopPropagation(); |
| this.toggleExpanded(); |
| } |
| |
| private toggleExpanded() { |
| if (!this.isExpandable) return; |
| this.isExpanded = !this.isExpanded; |
| } |
| } |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| 'gr-diff-check-result': GrDiffCheckResult; |
| } |
| } |