blob: 9868a605f6c941cb76e649d798ac8c5962d2d1e4 [file] [log] [blame]
// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import m from 'mithril';
import {Engine} from '../trace_processor/engine';
export interface NewBottomTabArgs<Config> {
engine: Engine;
tag?: string;
uuid: string;
config: Config;
}
// An interface representing a bottom tab displayed on the panel in the bottom
// of the ui (e.g. "Current Selection").
//
// The implementations of this class are provided by different plugins, which
// register the implementations with bottomTabRegistry, keyed by a unique name
// for each type of BottomTab.
//
// Lifetime: the instances of this class are owned by BottomTabPanel and exist
// for as long as a tab header is shown to the user in the bottom tab list (with
// minor exceptions, like a small grace period between when the tab is related).
//
// BottomTab implementations should pass the unique identifier(s) for the
// content displayed via the |Config| and fetch additional details via Engine
// instead of relying on getting the data from the global storage. For example,
// for tabs corresponding to details of the selected objects on a track, a new
// BottomTab should be created for each new selection.
export abstract class BottomTabBase<Config = {}> {
// Config for this details panel. Should be serializable.
protected readonly config: Config;
// Engine for running queries and fetching additional data.
protected readonly engine: Engine;
// Optional tag, which is used to ensure that only one tab
// with the same tag can exist - adding a new tab with the same tag
// (e.g. 'current_selection') would close the previous one. This
// also can be used to close existing tab.
readonly tag?: string;
// Unique id for this details panel. Can be used to close previously opened
// panel.
readonly uuid: string;
constructor(args: NewBottomTabArgs<Config>) {
this.config = args.config;
this.engine = args.engine;
this.tag = args.tag;
this.uuid = args.uuid;
}
// Entry point for customisation of the displayed title for this panel.
abstract getTitle(): string;
// Generate a mithril node for this component.
abstract renderPanel(): m.Children;
// API for the tab to notify the TabList that it's still preparing the data.
// If true, adding a new tab will be delayed for a short while (~50ms) to
// reduce the flickering.
//
// Note: it's a "poll" rather than "push" API: there is no explicit API
// for the tabs to notify the tab list, as the tabs are expected to schedule
// global redraw anyway and the tab list will poll the tabs as necessary
// during the redraw.
isLoading(): boolean {
return false;
}
}
// BottomTabBase provides a more generic API allowing users to provide their
// custom mithril component, which would allow them to listen to mithril
// lifecycle events. Most cases, however, don't need them and BottomTab
// provides a simplified API for the common case.
export abstract class BottomTab<Config = {}> extends BottomTabBase<Config> {
constructor(args: NewBottomTabArgs<Config>) {
super(args);
}
abstract viewTab(): m.Children;
renderPanel(): m.Children {
return m(BottomTabAdapter, {
key: this.uuid,
panel: this,
} as BottomTabAdapterAttrs);
}
}
interface BottomTabAdapterAttrs {
panel: BottomTab;
}
class BottomTabAdapter implements m.ClassComponent<BottomTabAdapterAttrs> {
view(vnode: m.CVnode<BottomTabAdapterAttrs>): void | m.Children {
return vnode.attrs.panel.viewTab();
}
}