xref: /aosp_15_r20/external/perfetto/ui/src/frontend/flow_events_panel.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use size 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
15import m from 'mithril';
16import {Icons} from '../base/semantic_icons';
17import {raf} from '../core/raf_scheduler';
18import {Flow} from '../core/flow_types';
19import {TraceImpl} from '../core/trace_impl';
20
21export const ALL_CATEGORIES = '_all_';
22
23export function getFlowCategories(flow: Flow): string[] {
24  const categories: string[] = [];
25  // v1 flows have their own categories
26  if (flow.category) {
27    categories.push(...flow.category.split(','));
28    return categories;
29  }
30  const beginCats = flow.begin.sliceCategory.split(',');
31  const endCats = flow.end.sliceCategory.split(',');
32  categories.push(...new Set([...beginCats, ...endCats]));
33  return categories;
34}
35
36export interface FlowEventsAreaSelectedPanelAttrs {
37  trace: TraceImpl;
38}
39
40export class FlowEventsAreaSelectedPanel
41  implements m.ClassComponent<FlowEventsAreaSelectedPanelAttrs>
42{
43  view({attrs}: m.CVnode<FlowEventsAreaSelectedPanelAttrs>) {
44    const selection = attrs.trace.selection.selection;
45    if (selection.kind !== 'area') {
46      return;
47    }
48
49    const columns = [
50      m('th', 'Flow Category'),
51      m('th', 'Number of flows'),
52      m(
53        'th',
54        'Show',
55        m(
56          'a.warning',
57          m('i.material-icons', 'warning'),
58          m(
59            '.tooltip',
60            'Showing a large number of flows may impact performance.',
61          ),
62        ),
63      ),
64    ];
65
66    const rows = [m('tr', columns)];
67
68    const categoryToFlowsNum = new Map<string, number>();
69
70    const flows = attrs.trace.flows;
71    flows.selectedFlows.forEach((flow) => {
72      const categories = getFlowCategories(flow);
73      categories.forEach((cat) => {
74        if (!categoryToFlowsNum.has(cat)) {
75          categoryToFlowsNum.set(cat, 0);
76        }
77        categoryToFlowsNum.set(cat, categoryToFlowsNum.get(cat)! + 1);
78      });
79    });
80
81    const allWasChecked = flows.visibleCategories.get(ALL_CATEGORIES);
82    rows.push(
83      m('tr.sum', [
84        m('td.sum-data', 'All'),
85        m('td.sum-data', flows.selectedFlows.length),
86        m(
87          'td.sum-data',
88          m(
89            'i.material-icons',
90            {
91              onclick: () => {
92                if (allWasChecked) {
93                  for (const k of flows.visibleCategories.keys()) {
94                    flows.setCategoryVisible(k, false);
95                  }
96                } else {
97                  categoryToFlowsNum.forEach((_, cat) => {
98                    flows.setCategoryVisible(cat, true);
99                  });
100                }
101                flows.setCategoryVisible(ALL_CATEGORIES, !allWasChecked);
102              },
103            },
104            allWasChecked ? Icons.Checkbox : Icons.BlankCheckbox,
105          ),
106        ),
107      ]),
108    );
109
110    categoryToFlowsNum.forEach((num, cat) => {
111      const wasChecked =
112        flows.visibleCategories.get(cat) ||
113        flows.visibleCategories.get(ALL_CATEGORIES);
114      const data = [
115        m('td.flow-info', cat),
116        m('td.flow-info', num),
117        m(
118          'td.flow-info',
119          m(
120            'i.material-icons',
121            {
122              onclick: () => {
123                if (wasChecked) {
124                  flows.setCategoryVisible(ALL_CATEGORIES, false);
125                }
126                flows.setCategoryVisible(cat, !wasChecked);
127                raf.scheduleFullRedraw();
128              },
129            },
130            wasChecked ? Icons.Checkbox : Icons.BlankCheckbox,
131          ),
132        ),
133      ];
134      rows.push(m('tr', data));
135    });
136
137    return m('.details-panel', [
138      m('.details-panel-heading', m('h2', `Selected flow events`)),
139      m('.flow-events-table', m('table', rows)),
140    ]);
141  }
142}
143