blob: f9a64452f2136aeb7c1abc915da3a2fc5accc059 [file]
// Copyright (C) 2024 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 type m from 'mithril';
import type {SqlValue} from '../../../../trace_processor/query_result';
import type {Trace} from '../../../../public/trace';
import {type SqlColumn, sqlColumnId} from './sql_column';
import type {Filters} from './filters';
import type {PerfettoSqlType} from '../../../../trace_processor/perfetto_sql_type';
// Interface which allows TableColumn to interact with the table (e.g. add filters, or run the query).
export interface TableManager {
filters: Filters;
trace: Trace;
getSqlQuery(data: {[key: string]: SqlColumn}): string;
}
// Context passed to renderCell to allow interaction with the table.
export interface RenderCellContext {
filters: Filters;
trace: Trace;
getSqlQuery(data: {[key: string]: SqlColumn}): string;
hasColumn(column: TableColumn): boolean;
addColumn(column: TableColumn): void;
}
// Context passed to listDerivedColumns to provide information about the table.
export interface ListColumnsContext {
filters: Filters;
trace: Trace;
getSqlQuery(data: {[key: string]: SqlColumn}): string;
}
export interface TableColumnParams {
// See TableColumn.tag.
tag?: string;
// See TableColumn.alias.
alias?: string;
// See TableColumn.startsHidden.
startsHidden?: boolean;
}
// Class which represents a column in a table, which can be displayed to the user.
export interface TableColumn {
readonly column: SqlColumn;
readonly type: PerfettoSqlType | undefined;
// In some cases, the UI needs additional information to be able to render a given cell (e.g. for display arg values,
// we need to know arg type as well as arg value to generate a correct filter). In these cases, the common solution is fetch a JSON value
// or a protobuf from the SQL and render it accordingly, so if set, `display` column overrides which value is going to be passed to `renderCell`.
// `column` is still always going to be used for sorting, aggregation and casting.
readonly display?: SqlColumn;
// Column title to be displayed.
// If not set, then `alias` will be used if it's unique.
// If `alias` is not set as well, then `sqlColumnId(primaryColumn())` will be used.
// TODO(altimin): This should return m.Children, but a bunch of things, including low-level widgets (Button, MenuItem, Anchor) need to be fixed first.
getTitle?(): string | undefined;
// Get column-specific menu items for this column.
// This allows columns to provide their own menu items in the table header menu.
// For example, a CastColumn can provide an "Undo cast" menu item.
getColumnSpecificMenuItems?(args: {
replaceColumn: (column: TableColumn) => void;
}): m.Children;
/**
* Render a table cell. context can be undefined, in which case the cell should provide basic rendering (e.g. for pivot table).
*
* @param value The value to be rendered.
* @param context Optional context to allow interaction with the table (e.g. adding filters).
*/
renderCell(value: SqlValue, context?: RenderCellContext): RenderedCell;
// A set of columns to be added when opening this table.
// It has two primary purposes:
// - Allow some columns to be hidden by default (by returning an empty array).
// - Expand some columns (e.g. utid and upid are not meaningful by themselves, so the corresponding columns might add a "name" column by default).
initialColumns?(): TableColumn[];
// Some columns / values (arg_set_ids, table ids, etc) are primarily used to reference other data.
// This method allows showing the user list of additional columns which can be fetched using this column.
listDerivedColumns?(
context: ListColumnsContext,
): undefined | (() => Promise<Map<string, TableColumn>>);
}
// Returns a unique identifier for the table column.
export function tableColumnId(column: TableColumn): string {
return sqlColumnId(column.column);
}
export function tableColumnAlias(column: TableColumn): string {
return tableColumnId(column).replace(/[^a-zA-Z0-9_]/g, (char) => {
if (char === '_') {
return '__';
}
return '_' + char.charCodeAt(0);
});
}
export function columnTitle(column: TableColumn): string {
if (column.getTitle !== undefined) {
const title = column.getTitle();
if (title !== undefined) return title;
}
return sqlColumnId(column.column);
}
export interface RenderedCell {
readonly content: m.Children;
readonly menu?: m.Children;
readonly isNumerical?: boolean;
readonly isNull?: boolean;
}