• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 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
15import m from 'mithril';
16import {TraceImpl} from '../../core/trace_impl';
17import {Button} from '../../widgets/button';
18import {MenuItem, PopupMenu} from '../../widgets/menu';
19import {Tab, TabbedSplitPanel} from '../../widgets/tabbed_split_panel';
20import {DEFAULT_DETAILS_CONTENT_HEIGHT} from '../css_constants';
21import {CurrentSelectionTab} from './current_selection_tab';
22
23export interface TabPanelAttrs {
24  readonly trace: TraceImpl;
25  readonly className?: string;
26}
27
28export class TabPanel implements m.ClassComponent<TabPanelAttrs> {
29  view({
30    attrs,
31    children,
32  }: m.Vnode<TabPanelAttrs, this>): m.Children | null | void {
33    const tabs = this.gatherTabs(attrs.trace);
34
35    return m(
36      TabbedSplitPanel,
37      {
38        className: attrs.className,
39        startingHeight: DEFAULT_DETAILS_CONTENT_HEIGHT,
40        leftHandleContent: this.renderDropdownMenu(attrs.trace),
41        tabs,
42        visibility: attrs.trace.tabs.tabPanelVisibility,
43        onVisibilityChange: (visibility) =>
44          attrs.trace.tabs.setTabPanelVisibility(visibility),
45        onTabChange: (key) => attrs.trace.tabs.showTab(key),
46        currentTabKey: attrs.trace.tabs.currentTabUri,
47      },
48      children,
49    );
50  }
51
52  private gatherTabs(trace: TraceImpl) {
53    const tabMan = trace.tabs;
54    const tabList = trace.tabs.openTabsUri;
55    const resolvedTabs = tabMan.resolveTabs(tabList);
56
57    const tabs = resolvedTabs.map(({uri, tab: tabDesc}): Tab => {
58      if (tabDesc) {
59        return {
60          key: uri,
61          hasCloseButton: true,
62          title: tabDesc.content.getTitle(),
63          content: tabDesc.content.render(),
64          onClose: () => {
65            trace.tabs.hideTab(uri);
66          },
67        };
68      } else {
69        return {
70          key: uri,
71          hasCloseButton: true,
72          title: 'Tab does not exist',
73          content: undefined,
74        };
75      }
76    });
77
78    // Add the permanent current selection tab to the front of the list of tabs
79    tabs.unshift({
80      key: 'current_selection',
81      title: 'Current Selection',
82      content: m(CurrentSelectionTab, {trace}),
83    });
84
85    return tabs;
86  }
87
88  private renderDropdownMenu(trace: TraceImpl): m.Child {
89    const entries = trace.tabs.tabs
90      .filter((tab) => tab.isEphemeral === false)
91      .map(({content, uri}) => {
92        return {
93          key: uri,
94          title: content.getTitle(),
95          onClick: () => trace.tabs.toggleTab(uri),
96          checked: trace.tabs.isOpen(uri),
97        };
98      });
99
100    return m(
101      PopupMenu,
102      {
103        trigger: m(Button, {
104          compact: true,
105          icon: 'more_vert',
106          disabled: entries.length === 0,
107          title: 'More Tabs',
108        }),
109      },
110      entries.map((entry) => {
111        return m(MenuItem, {
112          key: entry.key,
113          label: entry.title,
114          onclick: () => entry.onClick(),
115          icon: entry.checked ? 'check_box' : 'check_box_outline_blank',
116        });
117      }),
118    );
119  }
120}
121