1// Copyright (C) 2023 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Copyright (C) 2023 The Android Open Source Project
16//
17// Licensed under the Apache License, Version 2.0 (the "License");
18// you may not use this file except in compliance with the License.
19// You may obtain a copy of the License at
20//
21//      http://www.apache.org/licenses/LICENSE-2.0
22//
23// Unless required by applicable law or agreed to in writing, software
24// distributed under the License is distributed on an "AS IS" BASIS,
25// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26// See the License for the specific language governing permissions and
27// limitations under the License.
28
29import m from 'mithril';
30import {duration, Time, time} from '../../base/time';
31import {asUpid, Upid} from '../../components/sql_utils/core_types';
32import {DurationWidget} from '../../components/widgets/duration';
33import {Timestamp} from '../../components/widgets/timestamp';
34import {LONG, NUM, STR} from '../../trace_processor/query_result';
35import {DetailsShell} from '../../widgets/details_shell';
36import {GridLayout, GridLayoutColumn} from '../../widgets/grid_layout';
37import {Section} from '../../widgets/section';
38import {SqlRef} from '../../widgets/sql_ref';
39import {dictToTreeNodes, Tree} from '../../widgets/tree';
40import {TrackEventDetailsPanel} from '../../public/details_panel';
41import {Trace} from '../../public/trace';
42
43interface Data {
44  ts: time;
45  dur: duration;
46  interactionType: string;
47  totalDurationMs: duration;
48  upid: Upid;
49}
50
51export class WebContentInteractionPanel implements TrackEventDetailsPanel {
52  private data?: Data;
53
54  constructor(
55    private readonly trace: Trace,
56    private readonly id: number,
57  ) {}
58
59  async load() {
60    const queryResult = await this.trace.engine.query(`
61      SELECT
62        ts,
63        dur,
64        interaction_type AS interactionType,
65        total_duration_ms AS totalDurationMs,
66        renderer_upid AS upid
67      FROM chrome_web_content_interactions
68      WHERE id = ${this.id};
69    `);
70
71    const iter = queryResult.firstRow({
72      ts: LONG,
73      dur: LONG,
74      interactionType: STR,
75      totalDurationMs: LONG,
76      upid: NUM,
77    });
78
79    this.data = {
80      ts: Time.fromRaw(iter.ts),
81      dur: iter.ts,
82      interactionType: iter.interactionType,
83      totalDurationMs: iter.totalDurationMs,
84      upid: asUpid(iter.upid),
85    };
86  }
87
88  private getDetailsDictionary() {
89    const details: {[key: string]: m.Child} = {};
90    if (this.data === undefined) return details;
91    details['Interaction'] = this.data.interactionType;
92    details['Timestamp'] = m(Timestamp, {ts: this.data.ts});
93    details['Duration'] = m(DurationWidget, {dur: this.data.dur});
94    details['Renderer Upid'] = this.data.upid;
95    details['Total duration of all events'] = m(DurationWidget, {
96      dur: this.data.totalDurationMs,
97    });
98    details['SQL ID'] = m(SqlRef, {
99      table: 'chrome_web_content_interactions',
100      id: this.id,
101    });
102    return details;
103  }
104
105  render() {
106    if (!this.data) {
107      return m('h2', 'Loading');
108    }
109
110    return m(
111      DetailsShell,
112      {
113        title: 'Chrome Web Content Interaction',
114      },
115      m(
116        GridLayout,
117        m(
118          GridLayoutColumn,
119          m(
120            Section,
121            {title: 'Details'},
122            m(Tree, dictToTreeNodes(this.getDetailsDictionary())),
123          ),
124        ),
125      ),
126    );
127  }
128}
129