1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16import {Component, ElementRef, Inject, Input} from '@angular/core'; 17import {assertDefined} from 'common/assert_utils'; 18import {Timestamp} from 'common/time/time'; 19import {DiffType} from 'viewers/common/diff_type'; 20import {UiPropertyTreeNode} from 'viewers/common/ui_property_tree_node'; 21import {TimestampClickDetail, ViewerEvents} from 'viewers/common/viewer_events'; 22import {propertyTreeNodeDataViewStyles} from 'viewers/components/styles/tree_node_data_view.styles'; 23import { 24 inlineButtonStyle, 25 timeButtonStyle, 26} from './styles/clickable_property.styles'; 27 28@Component({ 29 selector: 'property-tree-node-data-view', 30 template: ` 31 <div class="node-property" *ngIf="node"> 32 <span class=" mat-body-1 property-key"> {{ getKey(node) }} </span> 33 <div *ngIf="node?.formattedValue()" class="property-value" [class]="[timeClass()]"> 34 <button 35 *ngIf="isTimestamp()" 36 class="time-button" 37 mat-button 38 color="primary" 39 (click)="onTimestampClicked(node)"> 40 {{ node.formattedValue() }} 41 </button> 42 <div *ngIf="!isTimestamp() && node?.canPropagate()" class="inline"> 43 <button 44 mat-button 45 color="primary" 46 (click)="onPropagateButtonClicked(node)"> 47 {{ node.formattedValue() }} 48 </button> 49 </div> 50 <a *ngIf="!isTimestamp() && !node?.canPropagate()" [class]="[valueClass()]" class="mat-body-2 value new">{{ node.formattedValue() }}</a> 51 <s *ngIf="isModified()" class="mat-body-2 old-value">{{ node.getOldValue() }}</s> 52 </div> 53 </div> 54 `, 55 styles: [ 56 ` 57 .property-value button { 58 white-space: normal; 59 } 60 `, 61 propertyTreeNodeDataViewStyles, 62 timeButtonStyle, 63 inlineButtonStyle, 64 ], 65}) 66export class PropertyTreeNodeDataViewComponent { 67 @Input() node?: UiPropertyTreeNode; 68 69 constructor(@Inject(ElementRef) private elementRef: ElementRef) {} 70 71 getKey(node: UiPropertyTreeNode) { 72 if (!this.node?.formattedValue()) { 73 return node.getDisplayName(); 74 } 75 return node.getDisplayName() + ': '; 76 } 77 78 isTimestamp() { 79 return this.node?.getValue() instanceof Timestamp; 80 } 81 82 onTimestampClicked(timestampNode: UiPropertyTreeNode) { 83 const timestamp: Timestamp = timestampNode.getValue(); 84 const customEvent = new CustomEvent(ViewerEvents.TimestampClick, { 85 bubbles: true, 86 detail: new TimestampClickDetail(undefined, timestamp), 87 }); 88 this.elementRef.nativeElement.dispatchEvent(customEvent); 89 } 90 91 onPropagateButtonClicked(node: UiPropertyTreeNode) { 92 const event = new CustomEvent(ViewerEvents.PropagatePropertyClick, { 93 bubbles: true, 94 detail: node, 95 }); 96 this.elementRef.nativeElement.dispatchEvent(event); 97 } 98 99 valueClass() { 100 const property = assertDefined(this.node).formattedValue(); 101 if (!property) { 102 return null; 103 } 104 105 if (property === 'null') { 106 return 'null'; 107 } 108 109 if (property === 'true') { 110 return 'true'; 111 } 112 113 if (property === 'false') { 114 return 'false'; 115 } 116 117 if (!isNaN(Number(property))) { 118 return 'number'; 119 } 120 121 return null; 122 } 123 124 timeClass() { 125 if (this.isTimestamp()) { 126 return 'time'; 127 } 128 129 return null; 130 } 131 132 isModified() { 133 return assertDefined(this.node).getDiff() === DiffType.MODIFIED; 134 } 135} 136