• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 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 {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
17import {Component, ElementRef, Inject, Input, ViewChild} from '@angular/core';
18import {MatSelectChange} from '@angular/material/select';
19import {Events} from './events';
20import {UiData} from './ui_data';
21
22@Component({
23  selector: 'viewer-protolog',
24  template: `
25    <div class="card-grid container">
26      <div class="filters">
27        <div class="log-level">
28          <mat-form-field appearance="fill">
29            <mat-label>Log level</mat-label>
30            <mat-select (selectionChange)="onLogLevelsChange($event)" multiple>
31              <mat-option *ngFor="let level of uiData.allLogLevels" [value]="level">
32                {{ level }}
33              </mat-option>
34            </mat-select>
35          </mat-form-field>
36        </div>
37        <div class="tag">
38          <mat-form-field appearance="fill">
39            <mat-label>Tags</mat-label>
40            <mat-select (selectionChange)="onTagsChange($event)" multiple>
41              <mat-option *ngFor="let tag of uiData.allTags" [value]="tag">
42                {{ tag }}
43              </mat-option>
44            </mat-select>
45          </mat-form-field>
46        </div>
47        <div class="source-file">
48          <mat-form-field appearance="fill">
49            <mat-label>Source files</mat-label>
50            <mat-select (selectionChange)="onSourceFilesChange($event)" multiple>
51              <mat-option *ngFor="let file of uiData.allSourceFiles" [value]="file">
52                {{ file }}
53              </mat-option>
54            </mat-select>
55          </mat-form-field>
56        </div>
57        <div class="text">
58          <mat-form-field appearance="fill">
59            <mat-label>Search text</mat-label>
60            <input matInput [(ngModel)]="searchString" (input)="onSearchStringChange()" />
61          </mat-form-field>
62        </div>
63      </div>
64      <cdk-virtual-scroll-viewport itemSize="16" class="scroll-messages">
65        <div
66          *cdkVirtualFor="let message of uiData.messages; let i = index"
67          class="message"
68          [class.current-message]="isCurrentMessage(i)">
69          <div class="time">
70            <span class="mat-body-1">{{ message.time }}</span>
71          </div>
72          <div class="log-level">
73            <span class="mat-body-1">{{ message.level }}</span>
74          </div>
75          <div class="tag">
76            <span class="mat-body-1">{{ message.tag }}</span>
77          </div>
78          <div class="source-file">
79            <span class="mat-body-1">{{ message.at }}</span>
80          </div>
81          <div class="text">
82            <span class="mat-body-1">{{ message.text }}</span>
83          </div>
84        </div>
85      </cdk-virtual-scroll-viewport>
86    </div>
87  `,
88  styles: [
89    `
90      .container {
91        padding: 16px;
92        box-sizing: border-box;
93        display: flex;
94        flex-direction: column;
95      }
96
97      .filters {
98        display: flex;
99        flex-direction: row;
100        margin-top: 16px;
101      }
102
103      .scroll-messages {
104        height: 100%;
105        flex: 1;
106      }
107
108      .message {
109        display: flex;
110        flex-direction: row;
111        overflow-wrap: anywhere;
112      }
113
114      .message.current-message {
115        background-color: #365179;
116        color: white;
117      }
118
119      .time {
120        flex: 2;
121      }
122
123      .log-level {
124        flex: 1;
125      }
126
127      .filters .log-level {
128        flex: 3;
129      }
130
131      .tag {
132        flex: 2;
133      }
134
135      .source-file {
136        flex: 4;
137      }
138
139      .text {
140        flex: 10;
141      }
142
143      .filters div {
144        margin: 4px;
145      }
146
147      .message div {
148        margin: 4px;
149      }
150
151      mat-form-field {
152        width: 100%;
153      }
154    `,
155  ],
156})
157export class ViewerProtologComponent {
158  constructor(@Inject(ElementRef) elementRef: ElementRef) {
159    this.elementRef = elementRef;
160  }
161
162  @Input()
163  set inputData(data: UiData) {
164    this.uiData = data;
165    if (this.uiData.currentMessageIndex !== undefined && this.scrollComponent) {
166      this.scrollComponent.scrollToIndex(this.uiData.currentMessageIndex);
167    }
168  }
169
170  onLogLevelsChange(event: MatSelectChange) {
171    this.emitEvent(Events.LogLevelsFilterChanged, event.value);
172  }
173
174  onTagsChange(event: MatSelectChange) {
175    this.emitEvent(Events.TagsFilterChanged, event.value);
176  }
177
178  onSourceFilesChange(event: MatSelectChange) {
179    this.emitEvent(Events.SourceFilesFilterChanged, event.value);
180  }
181
182  onSearchStringChange() {
183    this.emitEvent(Events.SearchStringFilterChanged, this.searchString);
184  }
185
186  isCurrentMessage(index: number): boolean {
187    return index === this.uiData.currentMessageIndex;
188  }
189
190  private emitEvent(event: string, data: any) {
191    const customEvent = new CustomEvent(event, {
192      bubbles: true,
193      detail: data,
194    });
195    this.elementRef.nativeElement.dispatchEvent(customEvent);
196  }
197
198  @ViewChild(CdkVirtualScrollViewport) scrollComponent!: CdkVirtualScrollViewport;
199
200  uiData: UiData = UiData.EMPTY;
201  private searchString = '';
202  private elementRef: ElementRef;
203}
204