Add docs a lot of public interfaces
Change-Id: I875fc21c5a7a5e1e3b359cbb2b50a98e789cc7a8
diff --git a/python/tools/check_ratchet.py b/python/tools/check_ratchet.py
index 8ea5a0d..3395f27 100755
--- a/python/tools/check_ratchet.py
+++ b/python/tools/check_ratchet.py
@@ -36,7 +36,7 @@
from dataclasses import dataclass
-EXPECTED_ANY_COUNT = 34
+EXPECTED_ANY_COUNT = 32
EXPECTED_RUN_METRIC_COUNT = 4
ROOT_DIR = os.path.dirname(
diff --git a/ui/src/plugins/com.android.AndroidNetwork/index.ts b/ui/src/plugins/com.android.AndroidNetwork/index.ts
index 10e5c43..9dcc7dd 100644
--- a/ui/src/plugins/com.android.AndroidNetwork/index.ts
+++ b/ui/src/plugins/com.android.AndroidNetwork/index.ts
@@ -43,19 +43,21 @@
ctx.commands.registerCommand({
id: 'com.android.AddBatteryEventsTrack',
name: 'Add track: battery events',
- callback: async (track) => {
- if (track === undefined) {
- track = await ctx.omnibox.prompt('Battery Track');
- if (track === undefined) return;
- }
+ callback: async (rawTrackName) => {
+ const trackName = await (async function () {
+ if (typeof rawTrackName === 'string') return rawTrackName;
+ return await ctx.omnibox.prompt('Battery Track');
+ })();
+
+ if (!trackName) return;
await ctx.engine.query(`SELECT IMPORT('android.battery_stats');`);
await this.addSimpleTrack(
ctx,
- track,
+ trackName,
`(SELECT *
FROM android_battery_stats_event_slices
- WHERE track_name = "${track}")`,
+ WHERE track_name = "${trackName}")`,
['ts', 'dur', 'str_value', 'int_value'],
);
},
@@ -64,16 +66,23 @@
ctx.commands.registerCommand({
id: 'com.android.AddNetworkActivityTrack',
name: 'Add track: network activity',
- callback: async (groupby, filter, trackName) => {
- if (groupby === undefined) {
- groupby = await ctx.omnibox.prompt('Group by', 'package_name');
- if (groupby === undefined) return;
- }
+ callback: async (rawGroupby, rawFilter, rawTrackName) => {
+ const groupby = await (async function () {
+ if (typeof rawGroupby === 'string') return rawGroupby;
+ return await ctx.omnibox.prompt('Group by', 'package_name');
+ })();
- if (filter === undefined) {
- filter = await ctx.omnibox.prompt('Filter', 'TRUE');
- if (filter === undefined) return;
- }
+ const filter = await (async function () {
+ if (typeof rawFilter === 'string') return rawFilter;
+ return await ctx.omnibox.prompt('Group by', 'package_name');
+ })();
+
+ if (!groupby || !filter) return;
+
+ const trackName = await (async function () {
+ if (typeof rawTrackName === 'string') return rawTrackName;
+ return 'Network Activity';
+ })();
const suffix = new Date().getTime();
await ctx.engine.query(`
@@ -91,7 +100,7 @@
const groupCols = groupby.replaceAll(' ', '').split(',');
await this.addSimpleTrack(
ctx,
- trackName ?? 'Network Activity',
+ trackName,
`android_network_activity_${suffix}`,
['ts', 'dur', ...groupCols, 'packet_length', 'packet_count'],
);
diff --git a/ui/src/plugins/dev.perfetto.TraceProcessorTrack/index.ts b/ui/src/plugins/dev.perfetto.TraceProcessorTrack/index.ts
index 37132e9..a21f812 100644
--- a/ui/src/plugins/dev.perfetto.TraceProcessorTrack/index.ts
+++ b/ui/src/plugins/dev.perfetto.TraceProcessorTrack/index.ts
@@ -24,7 +24,7 @@
metricsFromTableOrSubquery,
QueryFlamegraph,
} from '../../components/query_flamegraph';
-import {MinimapRow} from '../../public/minimap';
+import {MinimapCell, MinimapRow} from '../../public/minimap';
import {PerfettoPlugin} from '../../public/plugin';
import {AreaSelection, areaSelectionsEqual} from '../../public/selection';
import {Trace} from '../../public/trace';
@@ -460,7 +460,7 @@
upid;
`);
- const slicesData = new Map<number, MinimapRow>();
+ const slicesData = new Map<number, MinimapCell[]>();
const it = sliceResult.iter({bucket: LONG, upid: NUM, load: NUM});
for (; it.valid(); it.next()) {
const bucket = it.bucket;
diff --git a/ui/src/public/analytics.ts b/ui/src/public/analytics.ts
index 653b1ea..066903f 100644
--- a/ui/src/public/analytics.ts
+++ b/ui/src/public/analytics.ts
@@ -16,8 +16,33 @@
export type TraceCategories = 'Trace Actions' | 'Record Trace' | 'User Actions';
+/**
+ * Logs analytics events and errors.
+ *
+ * Use this to track user actions, trace operations, and error conditions.
+ * Events are categorized (e.g., 'Trace Actions', 'User Actions') and can
+ * be used to understand how users interact with your plugin.
+ */
export interface Analytics {
+ /**
+ * Logs a generic analytics event.
+ *
+ * @param category The category of the event (e.g., 'Trace Actions').
+ * @param event The name of the event (e.g., 'Save trace').
+ */
logEvent(category: TraceCategories | null, event: string): void;
+
+ /**
+ * Logs an error event.
+ *
+ * @param err The error details to log.
+ */
logError(err: ErrorDetails): void;
+
+ /**
+ * Checks if analytics is enabled.
+ *
+ * @returns `true` if analytics is enabled, `false` otherwise.
+ */
isEnabled(): boolean;
}
diff --git a/ui/src/public/command.ts b/ui/src/public/command.ts
index abf884f..c1aa105 100644
--- a/ui/src/public/command.ts
+++ b/ui/src/public/command.ts
@@ -14,29 +14,87 @@
import {Hotkey} from '../base/hotkeys';
+/**
+ * Manages the registration and execution of commands.
+ *
+ * Commands are user-invokable actions that can be triggered via hotkeys,
+ * the command palette, or programmatically. Use this to register plugin
+ * commands that users can execute.
+ */
export interface CommandManager {
+ /**
+ * Registers a new command.
+ *
+ * The command is uniquely identified by its `id`. If a command with the same
+ * `id` is already registered, this method will throw an error.
+ *
+ * @param command The command to register.
+ */
registerCommand(command: Command): void;
+ /**
+ * Checks if a command with the given `id` is registered.
+ *
+ * @param commandId The unique identifier of the command.
+ * @returns `true` if the command is registered, `false` otherwise.
+ */
hasCommand(commandId: string): boolean;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- runCommand(id: string, ...args: any[]): any;
+ /**
+ * Executes a command by its `id`.
+ *
+ * Any additional arguments are passed to the command's `callback` function.
+ *
+ * @param id The unique identifier of the command to run.
+ * @param args A list of arguments to pass to the command's callback.
+ * @returns The result of the command's callback, if any.
+ */
+ runCommand(id: string, ...args: unknown[]): unknown;
}
+/**
+ * Represents a command that can be executed within the application.
+ *
+ * A command is a self-contained unit of work that can be invoked by the user
+ * or programmatically. It includes a unique identifier, a human-readable name,
+ * a callback function to execute, and an optional default hotkey.
+ */
export interface Command {
- // A unique id for this command.
- id: string;
- // A human-friendly name for this command.
- name: string;
- // Callback is called when the command is invoked.
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- callback: (...args: any[]) => any;
- // Default hotkey for this command.
- // Note: this is just the default and may be changed by the user.
- // Examples:
- // - 'P'
- // - 'Shift+P'
- // - '!Mod+Shift+P'
- // See hotkeys.ts for guidance on hotkey syntax.
- defaultHotkey?: Hotkey;
+ /**
+ * A unique identifier for this command.
+ *
+ * This `id` is used to register, unregister, and execute the command. It is
+ * recommended to use a namespace to avoid collisions (e.g.,
+ * `myPlugin.myCommand`).
+ */
+ readonly id: string;
+
+ /**
+ * A human-friendly name for this command.
+ *
+ * This name is displayed to the user in the command palette and other UI
+ * elements. It should be concise and descriptive.
+ */
+ readonly name: string;
+
+ /**
+ * The function to call when the command is invoked.
+ *
+ * This function receives any arguments passed to `runCommand` and can return
+ * a value.
+ */
+ callback(...args: unknown[]): unknown;
+
+ /**
+ * The default hotkey for this command.
+ *
+ * This is just the default and may be changed by the user in the settings.
+ * See `hotkeys.ts` for guidance on hotkey syntax.
+ *
+ * @example
+ * - 'P'
+ * - 'Shift+P'
+ * - '!Mod+Shift+P'
+ */
+ readonly defaultHotkey?: Hotkey;
}
diff --git a/ui/src/public/feature_flag.ts b/ui/src/public/feature_flag.ts
index c82d38a..f076f3f 100644
--- a/ui/src/public/feature_flag.ts
+++ b/ui/src/public/feature_flag.ts
@@ -12,53 +12,141 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+/**
+ * Manages feature flags for experimental or togglable features.
+ *
+ * Feature flags allow plugins to expose experimental functionality that
+ * users can enable/disable. Flags are persisted across sessions and can be
+ * configured on the flags page.
+ */
export interface FeatureFlagManager {
+ /**
+ * Registers a new feature flag.
+ *
+ * @param settings The settings for the new feature flag.
+ * @returns The registered feature flag.
+ */
register(settings: FlagSettings): Flag;
}
+/**
+ * Settings for defining a new feature flag.
+ */
export interface FlagSettings {
- id: string;
- defaultValue: boolean;
- description: string;
- name?: string;
- devOnly?: boolean;
-}
-
-export interface Flag {
- // A unique identifier for this flag ("magicSorting")
+ /**
+ * A unique identifier for this flag (e.g., "magicSorting").
+ */
readonly id: string;
- // The name of the flag the user sees ("New track sorting algorithm")
- readonly name: string;
-
- // A longer description which is displayed to the user.
- // "Sort tracks using an embedded tfLite model based on your expression
- // while waiting for the trace to load."
- readonly description: string;
-
- // Whether the flag defaults to true or false.
- // If !flag.isOverridden() then flag.get() === flag.defaultValue
+ /**
+ * The default value of the flag (true or false).
+ *
+ * If `flag.isOverridden()` is false, then `flag.get()` will return
+ * `flag.defaultValue`.
+ */
readonly defaultValue: boolean;
- // Get the current value of the flag.
+ /**
+ * A longer description which is displayed to the user.
+ *
+ * Example: "Sort tracks using an embedded tfLite model based on your
+ * expression while waiting for the trace to load."
+ */
+ readonly description: string;
+
+ /**
+ * The name of the flag the user sees (e.g., "New track sorting algorithm").
+ * If omitted, the `id` will be used as the name.
+ */
+ readonly name?: string;
+
+ /**
+ * If true, this flag will only be visible and configurable in development
+ * builds of the Perfetto UI.
+ */
+ readonly devOnly?: boolean;
+}
+
+/**
+ * Represents a feature flag that can be enabled or disabled.
+ */
+export interface Flag {
+ /**
+ * A unique identifier for this flag (e.g., "magicSorting").
+ */
+ readonly id: string;
+
+ /**
+ * The name of the flag the user sees (e.g., "New track sorting algorithm").
+ */
+ readonly name: string;
+
+ /**
+ * A longer description which is displayed to the user.
+ *
+ * Example: "Sort tracks using an embedded tfLite model based on your
+ * expression while waiting for the trace to load."
+ */
+ readonly description: string;
+
+ /**
+ * Whether the flag defaults to true or false.
+ *
+ * If `!flag.isOverridden()`, then `flag.get()` will return
+ * `flag.defaultValue`.
+ */
+ readonly defaultValue: boolean;
+
+ /**
+ * Get the current value of the flag.
+ *
+ * @returns The current boolean value of the flag.
+ */
get(): boolean;
- // Override the flag and persist the new value.
+ /**
+ * Override the flag and persist the new value.
+ *
+ * This will change the flag's value for the current and future sessions.
+ *
+ * @param value The new boolean value for the flag.
+ */
set(value: boolean): void;
- // If the flag has been overridden.
- // Note: A flag can be overridden to its default value.
+ /**
+ * Checks if the flag has been explicitly overridden by the user.
+ *
+ * Note: A flag can be overridden to its default value.
+ *
+ * @returns `true` if the flag's value has been explicitly set, `false`
+ * otherwise.
+ */
isOverridden(): boolean;
- // Reset the flag to its default setting.
+ /**
+ * Reset the flag to its default setting.
+ *
+ * This will remove any user override and revert the flag to its
+ * `defaultValue`.
+ */
reset(): void;
- // Get the current state of the flag.
+ /**
+ * Get the current state of the flag's override status.
+ *
+ * @returns The {@link OverrideState} of the flag.
+ */
overriddenState(): OverrideState;
}
+/**
+ * Represents the override state of a feature flag.
+ */
export enum OverrideState {
+ /** The flag is currently using its default value. */
DEFAULT = 'DEFAULT',
+ /** The flag has been overridden to `true`. */
TRUE = 'OVERRIDE_TRUE',
+ /** The flag has been overridden to `false`. */
FALSE = 'OVERRIDE_FALSE',
}
diff --git a/ui/src/public/minimap.ts b/ui/src/public/minimap.ts
index f78c3de..d4bcf54 100644
--- a/ui/src/public/minimap.ts
+++ b/ui/src/public/minimap.ts
@@ -15,22 +15,61 @@
import {HighPrecisionTimeSpan} from '../base/high_precision_time_span';
import {duration, time} from '../base/time';
+/**
+ * Represents a single cell in the minimap, containing data for a specific time
+ * range.
+ */
export interface MinimapCell {
+ /**
+ * The start timestamp of the cell.
+ */
readonly ts: time;
+
+ /**
+ * The duration of the cell.
+ */
readonly dur: duration;
+
+ /**
+ * The load value for the cell, typically a normalized value between 0 and 1.
+ */
readonly load: number;
}
-export type MinimapRow = MinimapCell[];
+/**
+ * Represents a row of data in the minimap.
+ */
+export type MinimapRow = readonly MinimapCell[];
+/**
+ * Provides content for the minimap.
+ */
export interface MinimapContentProvider {
+ /**
+ * The priority of this content provider. Higher priority providers are
+ * preferred.
+ */
readonly priority: number;
+
+ /**
+ * Gets the data for the minimap for a given time span and resolution.
+ * @param timeSpan The time span for which to provide data.
+ * @param resolution The resolution at which to provide the data.
+ * @returns A promise that resolves to an array of minimap rows.
+ */
getData(
timeSpan: HighPrecisionTimeSpan,
resolution: duration,
): Promise<MinimapRow[]>;
}
+/**
+ * Manages content providers for the minimap.
+ */
export interface MinimapManager {
- registerContentProvider(x: MinimapContentProvider): void;
+ /**
+ * Registers a new content provider for the minimap.
+ * @param provider The content provider to register.
+ */
+ registerContentProvider(provider: MinimapContentProvider): void;
}
diff --git a/ui/src/public/note.ts b/ui/src/public/note.ts
index 20b462a..08276ce 100644
--- a/ui/src/public/note.ts
+++ b/ui/src/public/note.ts
@@ -14,45 +14,127 @@
import {time} from '../base/time';
+/**
+ * Manages notes and span notes on the timeline.
+ *
+ * Notes are flags on the timeline marker, while span notes represent flagged
+ * ranges.
+ */
export interface NoteManager {
+ /**
+ * Retrieves a note or span note by its ID.
+ * @param id The unique identifier of the note.
+ * @returns The note or span note if found, or `undefined`.
+ */
getNote(id: string): Note | SpanNote | undefined;
- // Adds a note (a flag on the timeline marker). Returns the id.
+ /**
+ * Adds a new note (a flag on the timeline marker).
+ * @param args The arguments for adding the note.
+ * @returns The unique ID of the newly added note.
+ */
addNote(args: AddNoteArgs): string;
- // Adds a span note (a flagged range). Returns the id.
+ /**
+ * Adds a new span note (a flagged range).
+ * @param args The arguments for adding the span note.
+ * @returns The unique ID of the newly added span note.
+ */
addSpanNote(args: AddSpanNoteArgs): string;
}
+/**
+ * Arguments for adding a new note.
+ */
export interface AddNoteArgs {
+ /**
+ * The timestamp of the note.
+ */
readonly timestamp: time;
- readonly color?: string; // Default: randomColor().
- readonly text?: string; // Default: ''.
- // The id is optional. If present, allows overriding a previosly created note.
- // If not present it will be auto-assigned with a montonic counter.
+ /**
+ * The color of the note. If not provided, a random color will be assigned.
+ */
+ readonly color?: string;
+ /**
+ * The text content of the note. If not provided, an empty string will be used.
+ */
+ readonly text?: string;
+ /**
+ * The unique ID of the note. If provided, it allows overriding a previously
+ * created note. If not present, an ID will be auto-assigned with a monotonic
+ * counter.
+ */
readonly id?: string;
}
+/**
+ * Represents a note (a flag on the timeline marker).
+ */
export interface Note extends AddNoteArgs {
+ /**
+ * The type of the note, always 'DEFAULT' for a regular note.
+ */
readonly noteType: 'DEFAULT';
+ /**
+ * The unique ID of the note.
+ */
readonly id: string;
+ /**
+ * The color of the note.
+ */
readonly color: string;
+ /**
+ * The text content of the note.
+ */
readonly text: string;
}
+/**
+ * Arguments for adding a new span note.
+ */
export interface AddSpanNoteArgs {
+ /**
+ * The start timestamp of the span note.
+ */
readonly start: time;
+ /**
+ * The end timestamp of the span note.
+ */
readonly end: time;
- readonly color?: string; // Default: randomColor().
- readonly text?: string; // Default: ''.
- // The id is optional. If present, allows overriding a previosly created note.
- // If not present it will be auto-assigned with a montonic counter.
+ /**
+ * The color of the span note. If not provided, a random color will be assigned.
+ */
+ readonly color?: string;
+ /**
+ * The text content of the span note. If not provided, an empty string will be used.
+ */
+ readonly text?: string;
+ /**
+ * The unique ID of the span note. If provided, it allows overriding a previously
+ * created span note. If not present, an ID will be auto-assigned with a monotonic
+ * counter.
+ */
readonly id?: string;
}
+/**
+ * Represents a span note (a flagged range).
+ */
export interface SpanNote extends AddSpanNoteArgs {
+ /**
+ * The type of the note, always 'SPAN' for a span note.
+ */
readonly noteType: 'SPAN';
+ /**
+ * The unique ID of the span note.
+ */
readonly id: string;
+ /**
+ * The color of the span note.
+ */
readonly color: string;
+ /**
+ * The text content of the span note.
+ */
readonly text: string;
}
diff --git a/ui/src/public/omnibox.ts b/ui/src/public/omnibox.ts
index daa2a83..cfd2733 100644
--- a/ui/src/public/omnibox.ts
+++ b/ui/src/public/omnibox.ts
@@ -12,6 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+/**
+ * Provides non-modal user prompts integrated into the UI.
+ *
+ * The omnibox can prompt users for free-form text input or selection from a
+ * list of choices. Think of it as window.prompt() but non-blocking and
+ * better integrated with the UI. Returns a promise that resolves to the
+ * user's input or undefined if dismissed.
+ */
export interface OmniboxManager {
/**
* Turns the omnibox into an interactive prompt for the user. Think of
@@ -70,7 +78,23 @@
prompt<T>(text: string, choices: PromptChoices<T>): Promise<T | undefined>;
}
+/**
+ * Represents a set of choices for the omnibox prompt.
+ *
+ * This interface allows for providing complex objects as choices, with a
+ * custom function to extract the display name for each choice.
+ * @template T The type of the values in the choices list.
+ */
export interface PromptChoices<T> {
- values: ReadonlyArray<T>;
- getName: (x: T) => string;
+ /**
+ * An array of values that the user can choose from.
+ */
+ readonly values: ReadonlyArray<T>;
+
+ /**
+ * A function that returns the display name for a given choice value.
+ * @param x The choice value.
+ * @returns The string representation of the choice.
+ */
+ getName(x: T): string;
}
diff --git a/ui/src/public/page.ts b/ui/src/public/page.ts
index 82a5bb9..30b5c6e 100644
--- a/ui/src/public/page.ts
+++ b/ui/src/public/page.ts
@@ -15,24 +15,46 @@
import m from 'mithril';
/**
- * Allows to register custom page endpoints that response to given routes, e.g.
- * /viewer, /record etc.
+ * Manages custom page registration and routing.
+ *
+ * Use this to register pages that respond to specific routes (e.g.,
+ * '/settings', '/query'). Pages are automatically unregistered when the
+ * trace is closed or the plugin is unloaded.
*/
export interface PageManager {
/**
- * Example usage:
- * registerPage({route: '/foo', page: FooPage})
- * class FooPage implements m.ClassComponent<PageWithTrace> {
- * view({attrs}: m.CVnode<PageWithTrace>) {
- * return m('div', ...
- * onclick: () => attrs.trace.timeline.zoom(...);
- * )
- * }
+ * Registers a new custom page handler.
+ *
+ * The page handler defines the route it responds to and the content to
+ * render. Returns a `Disposable` that can be used to unregister the page.
+ *
+ * @param pageHandler The page handler to register.
+ * @returns A `Disposable` to unregister the page.
+ *
+ * @example
+ * ```ts
+ * // Example usage:
+ * registerPage({route: '/foo', render: (subpage) => m(FooPage, {subpage})})
+ *
+ * class FooPage implements m.ClassComponent<{subpage?: string}> {
+ * view({attrs}: m.CVnode<{subpage?: string}>) {
+ * return m('div',
+ * m('h1', `Foo Page ${attrs.subpage ? `(${attrs.subpage})` : ''}`),
+ * m('button', {onclick: () => console.log('Button clicked')}, 'Click me')
+ * );
* }
+ * }
+ * ```
*/
registerPage(pageHandler: PageHandler): Disposable;
}
+/**
+ * Defines a handler for a custom page.
+ *
+ * A page handler specifies the route it responds to and provides a render
+ * function to display its content.
+ */
export interface PageHandler {
/**
* The route path this page handler responds to (e.g., '/', '/viewer').
@@ -50,7 +72,8 @@
* Renders the page content.
* Called during each Mithril render cycle.
*
- * @param subpage Optional subpage path segment after the main route
+ * @param subpage Optional subpage path segment after the main route.
+ * @returns The Mithril children to render for the page.
*/
- readonly render: (subpage: string | undefined) => m.Children;
+ render(subpage: string | undefined): m.Children;
}
diff --git a/ui/src/public/plugin.ts b/ui/src/public/plugin.ts
index 0891433..a693431 100644
--- a/ui/src/public/plugin.ts
+++ b/ui/src/public/plugin.ts
@@ -24,13 +24,65 @@
*
* On trace load, the core will create a new class instance by calling new on
* this constructor and then call its onTraceLoad() function.
+ * @template T The type of the plugin instance.
*/
export interface PerfettoPluginStatic<T extends PerfettoPlugin> {
+ /**
+ * A unique identifier for the plugin.
+ *
+ * This ID is used to identify the plugin within the Perfetto UI. It is
+ * recommended to use a reverse domain name style (e.g.,
+ * `dev.perfetto.MyPlugin`).
+ */
readonly id: string;
+
+ /**
+ * An optional human-readable description of the plugin.
+ *
+ * This description may be displayed in the UI to provide more information
+ * about the plugin's functionality.
+ */
readonly description?: string;
+
+ /**
+ * An optional list of other plugins that this plugin depends on.
+ *
+ * The Perfetto UI ensures that all dependencies are loaded before activating
+ * this plugin.
+ */
readonly dependencies?: ReadonlyArray<PerfettoPluginStatic<PerfettoPlugin>>;
+
+ /**
+ * Called when the plugin is activated, before a trace has been loaded.
+ *
+ * This method is suitable for registering commands, sidebar items, or pages
+ * that are not dependent on a loaded trace.
+ *
+ * @param app The {@link App} instance, providing access to app-wide
+ * functionality.
+ * @param args The initial route arguments when the app was loaded.
+ */
onActivate?(app: App, args: RouteArgs): void;
+
+ /**
+ * Returns a list of metric visualisations provided by this plugin.
+ *
+ * Metric visualisations are used to display data from trace metrics in a
+ * graphical format.
+ *
+ * @returns An array of {@link MetricVisualisation} objects.
+ */
metricVisualisations?(): MetricVisualisation[];
+
+ /**
+ * The constructor for the plugin's trace-scoped instance.
+ *
+ * This constructor is called when a trace is loaded, creating a new instance
+ * of the plugin that is scoped to the loaded trace.
+ *
+ * @param trace The {@link Trace} instance, providing access to trace-scoped
+ * functionality.
+ */
new (trace: Trace): T;
}
@@ -39,43 +91,98 @@
* is created from the class constructor above at trace load time.
*/
export interface PerfettoPlugin {
+ /**
+ * Called when a trace is loaded.
+ *
+ * This method is suitable for performing trace-specific initialization, such
+ * as querying trace data or registering trace-scoped UI elements.
+ *
+ * @param ctx The {@link Trace} instance, providing access to trace-scoped
+ * functionality.
+ * @param args Optional arguments passed to the plugin during trace loading.
+ */
onTraceLoad?(ctx: Trace, args?: {[key: string]: unknown}): Promise<void>;
}
+/**
+ * Represents a metric visualisation provided by a plugin.
+ *
+ * Metric visualisations are used to display data from trace metrics in a
+ * graphical format, typically using Vega or Vega-Lite specifications.
+ */
export interface MetricVisualisation {
- // The name of the metric e.g. 'android_camera'
+ /**
+ * The name of the metric (e.g., 'android_camera').
+ *
+ * This name corresponds to a metric generated by the trace processor.
+ */
metric: string;
- // A vega or vega-lite visualisation spec.
- // The data from the metric under path will be exposed as a
- // datasource named "metric" in Vega(-Lite)
+ /**
+ * A Vega or Vega-Lite visualisation specification.
+ *
+ * The data from the metric, extracted by the `path` property, will be
+ * exposed as a datasource named "metric" within the Vega(-Lite) spec.
+ */
spec: string;
- // A path index into the metric.
- // For example if the metric returns the folowing protobuf:
- // {
- // foo {
- // bar {
- // baz: { name: "a" }
- // baz: { name: "b" }
- // baz: { name: "c" }
- // }
- // }
- // }
- // That becomes the following json:
- // { "foo": { "bar": { "baz": [
- // {"name": "a"},
- // {"name": "b"},
- // {"name": "c"},
- // ]}}}
- // And given path = ["foo", "bar", "baz"]
- // We extract:
- // [ {"name": "a"}, {"name": "b"}, {"name": "c"} ]
- // And pass that to the vega(-lite) visualisation.
+ /**
+ * A path index into the metric data.
+ *
+ * This path specifies how to extract the relevant data from the metric's
+ * protobuf output. For example, if the metric returns:
+ * ```protobuf
+ * {
+ * foo {
+ * bar {
+ * baz: { name: "a" }
+ * baz: { name: "b" }
+ * baz: { name: "c" }
+ * }
+ * }
+ * }
+ * ```
+ * This becomes the following JSON:
+ * ```json
+ * { "foo": { "bar": { "baz": [
+ * {"name": "a"},
+ * {"name": "b"},
+ * {"name": "c"},
+ * ]}}}
+ * ```
+ * And given `path = ["foo", "bar", "baz"]`, the extracted data
+ * `[ {"name": "a"}, {"name": "b"}, {"name": "c"} ]` is passed to the
+ * Vega(-Lite) visualisation.
+ */
path: string[];
}
+/**
+ * Manages registered plugins and their instances.
+ *
+ * Use this to get instances of other plugins (for inter-plugin
+ * communication) or access metric visualizations. Note that plugin instances
+ * are only available after a trace has been loaded.
+ */
export interface PluginManager {
+ /**
+ * Retrieves an instance of a registered plugin.
+ *
+ * This method can only be called after a trace has been loaded, as plugin
+ * instances are trace-scoped.
+ *
+ * @param plugin The static plugin class (constructor) of the plugin to
+ * retrieve.
+ * @returns The trace-scoped instance of the requested plugin.
+ * @template T The type of the plugin instance.
+ */
getPlugin<T extends PerfettoPlugin>(plugin: PerfettoPluginStatic<T>): T;
+
+ /**
+ * Returns a list of all metric visualisations provided by all registered
+ * plugins.
+ *
+ * @returns An array of {@link MetricVisualisation} objects.
+ */
metricVisualisations(): MetricVisualisation[];
}
diff --git a/ui/src/public/search.ts b/ui/src/public/search.ts
index f0db9a6..839572c 100644
--- a/ui/src/public/search.ts
+++ b/ui/src/public/search.ts
@@ -15,17 +15,41 @@
import {time} from '../base/time';
import {Track} from './track';
+/**
+ * Defines the possible sources for a search result.
+ */
export type SearchSource = 'cpu' | 'log' | 'slice' | 'track' | 'event';
+/**
+ * Represents a single search result.
+ */
export interface SearchResult {
- eventId: number;
- ts: time;
- trackUri: string;
- source: SearchSource;
+ /**
+ * The ID of the event found.
+ */
+ readonly eventId: number;
+ /**
+ * The timestamp of the event.
+ */
+ readonly ts: time;
+ /**
+ * The URI of the track where the event is located.
+ */
+ readonly trackUri: string;
+ /**
+ * The source of the search result.
+ */
+ readonly source: SearchSource;
}
+/**
+ * A callback function type for handling search result steps.
+ */
export type ResultStepEventHandler = (r: SearchResult) => void;
+/**
+ * Represents a filter expression used for searching.
+ */
export interface FilterExpression {
/**
* A SQL WHERE clause that filters the events in the selected tracks. The
@@ -40,6 +64,9 @@
readonly join?: string;
}
+/**
+ * Defines a provider for search functionality.
+ */
export interface SearchProvider {
/**
* A human-readable name for this search provider. This is not currently used
@@ -49,7 +76,7 @@
/**
* Returns a set of tracks that this provider is interested in.
- * @param tracks - A list of all tracks we want to search inside.
+ * @param tracks A list of all tracks we want to search inside.
* @returns A subset of tracks that this provider is interested in.
*/
selectTracks(tracks: ReadonlyArray<Track>): ReadonlyArray<Track>;
@@ -61,13 +88,20 @@
* This function is async because it may need to query some data using the
* search term before it can return a filter expression.
*
- * @param searchTerm - The raw search term entered by the user.
+ * @param searchTerm The raw search term entered by the user.
* @returns A promise that resolves to a FilterExpression that is compiled into
- * the resulting SQL query. If undefined, this provider will not be used.
+ * the resulting SQL query. If `undefined`, this provider will not be used.
*/
getSearchFilter(searchTerm: string): Promise<FilterExpression | undefined>;
}
+/**
+ * Manages the registration of search providers.
+ */
export interface SearchManager {
+ /**
+ * Registers a new search provider.
+ * @param provider The search provider to register.
+ */
registerSearchProvider(provider: SearchProvider): void;
}
diff --git a/ui/src/public/selection.ts b/ui/src/public/selection.ts
index cd0bdef..f468894 100644
--- a/ui/src/public/selection.ts
+++ b/ui/src/public/selection.ts
@@ -17,51 +17,223 @@
import {duration, time, TimeSpan} from '../base/time';
import {Track} from './track';
+/**
+ * Represents content that may be in a loading state.
+ */
export interface ContentWithLoadingFlag {
+ /**
+ * Indicates whether the content is currently loading.
+ */
readonly isLoading: boolean;
+ /**
+ * The actual content to be displayed.
+ */
readonly content: m.Children;
}
+/**
+ * Defines a tab within the area selection details panel.
+ */
export interface AreaSelectionTab {
- // Unique id for this tab.
+ /**
+ * Unique ID for this tab.
+ */
readonly id: string;
- // A name for this tab.
+ /**
+ * A human-readable name for this tab.
+ */
readonly name: string;
- // Defines the sort order of this tab - higher values appear first.
+ /**
+ * Defines the sort order of this tab - higher values appear first.
+ */
readonly priority?: number;
/**
* Called every Mithril render cycle to render the content of the tab. The
* returned content will be displayed inside the current selection tab.
*
- * If undefined is returned then the tab handle will be hidden, which gives
+ * If `undefined` is returned then the tab handle will be hidden, which gives
* the tab the option to dynamically remove itself from the list of tabs if it
* has nothing relevant to show.
*
- * The |isLoading| flag is used to avoid flickering. If set to true, we keep
- * hold of the the previous vnodes, rendering them instead, for up to 50ms
+ * The `isLoading` flag is used to avoid flickering. If set to `true`, we keep
+ * hold of the previous vnodes, rendering them instead, for up to 50ms
* before switching to the new content. This avoids very fast load times
* from causing flickering loading screens, which can be somewhat jarring.
+ * @param selection The current area selection.
+ * @returns The content to render, or `undefined` if the tab should be hidden.
*/
render(selection: AreaSelection): ContentWithLoadingFlag | undefined;
}
/**
- * Compare two area selections for equality. Returns true if the selections are
- * equivalent, false otherwise.
+ * Represents the different types of selections that can be made in the UI.
*/
-export function areaSelectionsEqual(a: AreaSelection, b: AreaSelection) {
- if (a.start !== b.start) return false;
- if (a.end !== b.end) return false;
- if (!arrayEquals(a.trackUris, b.trackUris)) {
- return false;
- }
- return true;
+export type Selection =
+ | TrackEventSelection
+ | TrackSelection
+ | AreaSelection
+ | NoteSelection
+ | EmptySelection;
+
+/**
+ * Defines how changes to selection affect the rest of the UI state.
+ */
+export interface SelectionOpts {
+ /**
+ * If `true`, clears the search input. Defaults to `true`.
+ */
+ readonly clearSearch?: boolean;
+ /**
+ * If `true`, switches to the tab relevant to the current selection. Defaults
+ * to `true`.
+ */
+ readonly switchToCurrentSelectionTab?: boolean;
+ /**
+ * If `true`, scrolls the timeline to reveal the selection. Defaults to `false`.
+ */
+ readonly scrollToSelection?: boolean;
}
+/**
+ * Represents a selection of a specific track event.
+ */
+export interface TrackEventSelection extends TrackEventDetails {
+ /**
+ * The kind of selection, always 'track_event'.
+ */
+ readonly kind: 'track_event';
+ /**
+ * The URI of the track where the event is located.
+ */
+ readonly trackUri: string;
+ /**
+ * The ID of the selected event.
+ */
+ readonly eventId: number;
+}
+
+/**
+ * Represents a selection of an entire track.
+ */
+export interface TrackSelection {
+ /**
+ * The kind of selection, always 'track'.
+ */
+ readonly kind: 'track';
+ /**
+ * The URI of the selected track.
+ */
+ readonly trackUri: string;
+}
+
+/**
+ * Details about a track event.
+ */
+export interface TrackEventDetails {
+ /**
+ * The timestamp of the event. Required by the core.
+ */
+ readonly ts: time;
+
+ /**
+ * The duration of the event. Can be 0 for instant events or -1 for DNF
+ * slices. Will be `undefined` if this selection has no duration (e.g.,
+ * profile/counter samples).
+ */
+ readonly dur?: duration;
+}
+
+/**
+ * Defines an area on the timeline.
+ */
+export interface Area {
+ /**
+ * The start timestamp of the area.
+ */
+ readonly start: time;
+ /**
+ * The end timestamp of the area.
+ */
+ readonly end: time;
+ /**
+ * An array of URIs of the tracks included in the area.
+ */
+ readonly trackUris: ReadonlyArray<string>;
+}
+
+/**
+ * Represents a selection of an area on the timeline.
+ */
+export interface AreaSelection extends Area {
+ /**
+ * The kind of selection, always 'area'.
+ */
+ readonly kind: 'area';
+
+ /**
+ * This array contains the resolved Tracks from `Area.trackUris`. The
+ * resolution is done by `SelectionManager` whenever a `kind='area'` selection
+ * is performed.
+ */
+ readonly tracks: ReadonlyArray<Track>;
+}
+
+/**
+ * Represents a selection of a note.
+ */
+export interface NoteSelection {
+ /**
+ * The kind of selection, always 'note'.
+ */
+ readonly kind: 'note';
+ /**
+ * The ID of the selected note.
+ */
+ readonly id: string;
+}
+
+/**
+ * Represents an empty selection.
+ */
+export interface EmptySelection {
+ /**
+ * The kind of selection, always 'empty'.
+ */
+ readonly kind: 'empty';
+}
+
+/**
+ * Resolves SQL events to track events.
+ */
+export interface SqlSelectionResolver {
+ /**
+ * The name of the SQL table to resolve.
+ */
+ readonly sqlTableName: string;
+ /**
+ * A callback function that resolves an event ID from a SQL table to a track
+ * URI and event ID.
+ * @param id The ID of the event in the SQL table.
+ * @param sqlTable The name of the SQL table.
+ * @returns A promise that resolves to an object containing `trackUri` and
+ * `eventId`, or `undefined` if not found.
+ */
+ callback(
+ id: number,
+ sqlTable: string,
+ ): Promise<{readonly trackUri: string; readonly eventId: number} | undefined>;
+}
+
+/**
+ * Manages the current selection state in the UI.
+ */
export interface SelectionManager {
+ /**
+ * The current selection.
+ */
readonly selection: Selection;
/**
@@ -70,16 +242,16 @@
readonly areaSelectionTabs: ReadonlyArray<AreaSelectionTab>;
/**
- * Clears the current selection, selects nothing.
+ * Clears the current selection, selecting nothing.
*/
clearSelection(): void;
/**
- * Select a track event.
+ * Selects a track event.
*
- * @param trackUri - The URI of the track to select.
- * @param eventId - The value of the events ID column.
- * @param opts - Additional options.
+ * @param trackUri The URI of the track to select.
+ * @param eventId The value of the event's ID column.
+ * @param opts Additional options for the selection.
*/
selectTrackEvent(
trackUri: string,
@@ -88,43 +260,47 @@
): void;
/**
- * Select a track.
+ * Selects a track.
*
- * @param trackUri - The URI for the track to select.
- * @param opts - Additional options.
+ * @param trackUri The URI for the track to select.
+ * @param opts Additional options for the selection.
*/
selectTrack(trackUri: string, opts?: SelectionOpts): void;
/**
- * Resolves events via a sql table name + ids.
+ * Resolves events via a SQL table name and IDs.
*
- * @param sqlTableName - The name of the SQL table to resolve.
- * @param ids - The IDs of the events in that table.
+ * @param sqlTableName The name of the SQL table to resolve.
+ * @param ids The IDs of the events in that table.
+ * @returns A promise that resolves to an array of objects containing eventId
+ * and trackUri.
*/
resolveSqlEvents(
sqlTableName: string,
ids: ReadonlyArray<number>,
- ): Promise<ReadonlyArray<{eventId: number; trackUri: string}>>;
+ ): Promise<
+ ReadonlyArray<{readonly eventId: number; readonly trackUri: string}>
+ >;
/**
- * Select a track event via a sql table name + id.
+ * Selects a track event via a SQL table name and ID.
*
- * @param sqlTableName - The name of the SQL table to resolve.
- * @param id - The ID of the event in that table.
- * @param opts - Additional options.
+ * @param sqlTableName The name of the SQL table to resolve.
+ * @param id The ID of the event in that table.
+ * @param opts Additional options for the selection.
*/
selectSqlEvent(sqlTableName: string, id: number, opts?: SelectionOpts): void;
/**
- * Create an area selection for the purposes of aggregation.
+ * Creates an area selection for the purposes of aggregation.
*
- * @param args - The area to select.
- * @param opts - Additional options.
+ * @param args The area to select.
+ * @param opts Additional options for the selection.
*/
selectArea(args: Area, opts?: SelectionOpts): void;
/**
- * Scroll the timeline horizontally and vertically to reveal the currently
+ * Scrolls the timeline horizontally and vertically to reveal the currently
* selected entity.
*/
scrollToSelection(): void;
@@ -133,78 +309,32 @@
* Returns the smallest time span that contains the currently selected entity.
*
* @returns The time span, if a timeline entity is selected, otherwise
- * undefined.
+ * `undefined`.
*/
getTimeSpanOfSelection(): TimeSpan | undefined;
/**
- * Register a new tab under the area selection details panel.
+ * Registers a new tab under the area selection details panel.
+ * @param tab The area selection tab to register.
*/
registerAreaSelectionTab(tab: AreaSelectionTab): void;
}
-export type Selection =
- | TrackEventSelection
- | TrackSelection
- | AreaSelection
- | NoteSelection
- | EmptySelection;
-
-/** Defines how changes to selection affect the rest of the UI state */
-export interface SelectionOpts {
- clearSearch?: boolean; // Default: true.
- switchToCurrentSelectionTab?: boolean; // Default: true.
- scrollToSelection?: boolean; // Default: false.
-}
-
-export interface TrackEventSelection extends TrackEventDetails {
- readonly kind: 'track_event';
- readonly trackUri: string;
- readonly eventId: number;
-}
-
-export interface TrackSelection {
- readonly kind: 'track';
- readonly trackUri: string;
-}
-
-export interface TrackEventDetails {
- // ts and dur are required by the core, and must be provided.
- readonly ts: time;
-
- // Note: dur can be 0 for instant events or -1 for DNF slices. Will be
- // undefined if this selection has no duration, i.e. profile / counter
- // samples.
- readonly dur?: duration;
-}
-
-export interface Area {
- readonly start: time;
- readonly end: time;
- readonly trackUris: ReadonlyArray<string>;
-}
-
-export interface AreaSelection extends Area {
- readonly kind: 'area';
-
- // This array contains the resolved Tracks from Area.trackUris. The resolution
- // is done by SelectionManager whenever a kind='area' selection is performed.
- readonly tracks: ReadonlyArray<Track>;
-}
-
-export interface NoteSelection {
- readonly kind: 'note';
- readonly id: string;
-}
-
-export interface EmptySelection {
- readonly kind: 'empty';
-}
-
-export interface SqlSelectionResolver {
- readonly sqlTableName: string;
- readonly callback: (
- id: number,
- sqlTable: string,
- ) => Promise<{trackUri: string; eventId: number} | undefined>;
+/**
+ * Compare two area selections for equality. Returns true if the selections are
+ * equivalent, false otherwise.
+ * @param a The first area selection.
+ * @param b The second area selection.
+ * @returns `true` if the selections are equal, `false` otherwise.
+ */
+export function areaSelectionsEqual(
+ a: AreaSelection,
+ b: AreaSelection,
+): boolean {
+ if (a.start !== b.start) return false;
+ if (a.end !== b.end) return false;
+ if (!arrayEquals(a.trackUris, b.trackUris)) {
+ return false;
+ }
+ return true;
}
diff --git a/ui/src/public/settings.ts b/ui/src/public/settings.ts
index 592e0a9..5ceb8bb 100644
--- a/ui/src/public/settings.ts
+++ b/ui/src/public/settings.ts
@@ -21,6 +21,12 @@
import {z} from 'zod';
import m from 'mithril';
+/**
+ * A function type for rendering a custom UI for a setting.
+ * @template T The type of the setting's value.
+ * @param setting The setting instance to render.
+ * @returns Mithril children to be rendered.
+ */
export type SettingRenderer<T> = (setting: Setting<T>) => m.Children;
/**
@@ -29,24 +35,44 @@
* @template T The type of the setting's value.
*/
export interface SettingDescriptor<T> {
- // A unique identifier for the setting. Used as the storage key.
+ /**
+ * A unique identifier for the setting. Used as the storage key.
+ */
readonly id: string;
- // A human-readable name for the setting, used on the settings page.
+
+ /**
+ * A human-readable name for the setting, used on the settings page.
+ */
readonly name: string;
- // A detailed description of what the setting does, used on the settings page.
+
+ /**
+ * A detailed description of what the setting does, used on the settings page.
+ */
readonly description: string;
- // The Zod schema used for validating the setting's value, and defining the
- // structure and type of this setting.
+
+ /**
+ * The Zod schema used for validating the setting's value, and defining the
+ * structure and type of this setting.
+ */
readonly schema: z.ZodType<T>;
- // The default value of the setting if the setting is absent from the
- // underlying storage.
+
+ /**
+ * The default value of the setting if the setting is absent from the
+ * underlying storage.
+ */
readonly defaultValue: T;
- // If true, the user will be prompted to reload the the page when this setting
- // is changed.
+
+ /**
+ * If true, the user will be prompted to reload the the page when this setting
+ * is changed.
+ */
readonly requiresReload?: boolean;
- // An optional render function for customizing the UI of this setting in the
- // settings page. Required for settings that are move complex than a primitive
- // type, such as objects or arrays.
+
+ /**
+ * An optional render function for customizing the UI of this setting in the
+ * settings page. Required for settings that are move complex than a primitive
+ * type, such as objects or arrays.
+ */
readonly render?: SettingRenderer<T>;
}
@@ -57,22 +83,41 @@
* @template T The type of the setting's value.
*/
export interface Setting<T> extends SettingDescriptor<T>, Disposable {
- // Returns true if this settings is currently set to the default value.
+ /**
+ * Returns true if this settings is currently set to the default value.
+ */
readonly isDefault: boolean;
- // Get the current value of the setting.
+
+ /**
+ * Get the current value of the setting.
+ * @returns The current value of the setting.
+ */
get(): T;
- // Set the value of the setting. This will also update the underlying storage.
+
+ /**
+ * Set the value of the setting. This will also update the underlying storage.
+ * @param value The new value for the setting.
+ */
set(value: T): void;
- // Resets back to default.
+
+ /**
+ * Resets back to default.
+ */
reset(): void;
}
/**
* Manages the registration and retrieval of application settings.
+ *
+ * Settings are stored in local storage and can be configured on the settings
+ * page. They support validation via Zod schemas, custom rendering, and can
+ * optionally require an app reload when changed.
*/
export interface SettingsManager {
/**
* Registers a new setting.
+ * @template T The type of the setting's value.
+ * @param setting The descriptor for the setting to register.
* @returns A handle used to interact with the setting.
*/
register<T>(setting: SettingDescriptor<T>): Setting<T>;
@@ -82,6 +127,7 @@
resetAll(): void;
/**
* Retrieves a list of all currently registered settings.
+ * @returns A read-only array of all registered settings.
*/
getAllSettings(): ReadonlyArray<Setting<unknown>>;
/**
@@ -93,7 +139,9 @@
/**
* Get the a setting by its ID.
+ * @template T The expected type of the setting's value.
* @param id The unique identifier of the setting.
+ * @returns The setting instance if found, or `undefined` otherwise.
*/
get<T>(id: string): Setting<T> | undefined;
}
diff --git a/ui/src/public/sidebar.ts b/ui/src/public/sidebar.ts
index 980766f..85a5795 100644
--- a/ui/src/public/sidebar.ts
+++ b/ui/src/public/sidebar.ts
@@ -4,7 +4,7 @@
// 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
+// http://www.apache.org/licenses/LICENSE-20.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -42,43 +42,107 @@
export type SidebarSections = keyof typeof SIDEBAR_SECTIONS;
+/**
+ * Manages the sidebar menu items and visibility.
+ *
+ * The sidebar is organized into sections (navigation, settings, support,
+ * etc.). Use this to add menu entries that can navigate to pages, execute
+ * actions, or trigger commands. Menu items are automatically removed when
+ * the trace is closed or the plugin is unloaded.
+ */
export interface SidebarManager {
+ /**
+ * Whether the sidebar is currently enabled.
+ *
+ * When the sidebar is disabled, menu items cannot be added, and its
+ * visibility cannot be toggled.
+ */
readonly enabled: boolean;
/**
* Adds a new menu item to the sidebar.
- * All entries must map to a command. This will allow the shortcut and
+ *
+ * All entries must map to a command, which allows the shortcut and
* optional shortcut to be displayed on the UI.
+ *
+ * @param menuItem The menu item to add.
*/
addMenuItem(menuItem: SidebarMenuItem): void;
/**
* Gets the current visibility of the sidebar.
+ *
+ * @returns `true` if the sidebar is visible, `false` otherwise.
*/
get visible(): boolean;
/**
- * Toggles the visibility of the sidebar. Can only be called when
- * `sidebarEnabled` returns `ENABLED`.
+ * Toggles the visibility of the sidebar.
+ *
+ * This method can only be called when `enabled` is `true`.
*/
toggleVisibility(): void;
}
+/**
+ * Represents a single menu item in the sidebar.
+ *
+ * A sidebar menu item can either navigate to a URL, execute an action, or
+ * trigger a command.
+ */
export type SidebarMenuItem = {
+ /**
+ * The section of the sidebar where this menu item will be placed.
+ *
+ * Must be one of the predefined `SIDEBAR_SECTIONS`.
+ */
readonly section: SidebarSections;
+
+ /**
+ * An optional number to control the sort order of menu items within a
+ * section.
+ *
+ * Lower numbers appear before higher numbers. If omitted, items are sorted
+ * by their `text` property.
+ */
readonly sortOrder?: number;
- // The properties below can be mutated by passing a callback rather than a
- // direct value. The callback is invoked on every render frame, keep it cheap.
- // readonly text: string | (() => string);
+ /**
+ * An optional icon to display next to the menu item.
+ *
+ * Can be a string (e.g., 'settings') or a function that returns a string.
+ * The function is invoked on every render frame, so keep it cheap.
+ */
readonly icon?: string | (() => string);
+
+ /**
+ * An optional tooltip to display when hovering over the menu item.
+ *
+ * Can be a string or a function that returns a string. The function is
+ * invoked on every render frame, so keep it cheap.
+ */
readonly tooltip?: string | (() => string);
+
+ /**
+ * An optional CSS class to apply to the menu item.
+ *
+ * Can be a string (without trailing '.') or a function that returns a string.
+ * The function is invoked on every render frame, so keep it cheap.
+ */
readonly cssClass?: string | (() => string); // Without trailing '.'.
- // If false or omitted the item works normally.
- // If true the item is striken through and the action/href will be a no-op.
- // If a string, the item acts as disabled and clicking on it shows a popup
- // that shows the returned text (the string has "disabled reason" semantic);
+ /**
+ * Controls the disabled state of the menu item.
+ *
+ * - If `false` or omitted, the item works normally.
+ * - If `true`, the item is struck through, and its action/href will be a
+ * no-op.
+ * - If a `string`, the item acts as disabled, and clicking on it shows a
+ * popup with the returned text (which has "disabled reason" semantics).
+ *
+ * Can be a string, boolean, or a function that returns either. The function
+ * is invoked on every render frame, so keep it cheap.
+ */
readonly disabled?: string | boolean | (() => string | boolean);
// One of the three following arguments must be specified.
@@ -104,7 +168,7 @@
* a promise, a spinner will be drawn next to the sidebar entry until the
* promise resolves.
*/
- readonly action: () => unknown | Promise<unknown>;
+ action(): unknown | Promise<unknown>;
/** Optional. If omitted href = '#'. */
readonly href?: string;
diff --git a/ui/src/public/statusbar.ts b/ui/src/public/statusbar.ts
index 6854be2..4ad6399 100644
--- a/ui/src/public/statusbar.ts
+++ b/ui/src/public/statusbar.ts
@@ -15,17 +15,42 @@
import m from 'mithril';
import {Intent} from '../widgets/common';
+/**
+ * Represents an item to be displayed in the status bar.
+ */
export interface StatusbarItem {
- readonly renderItem: () => {
+ /**
+ * A function that returns the properties for rendering the status bar item.
+ * @returns An object with label, optional icon, optional intent, and an
+ * optional click handler.
+ */
+ renderItem(): {
readonly label: string;
readonly icon?: string;
readonly intent?: Intent;
- readonly onclick?: (event: MouseEvent) => void;
+ onclick?(event: MouseEvent): void;
};
- readonly popupContent?: () => m.Children;
+
+ /**
+ * An optional function that returns the content to be displayed in a popup
+ * when the status bar item is clicked.
+ * @returns The Mithril children to render in the popup.
+ */
+ popupContent?(): m.Children;
}
+/**
+ * Manages items in the status bar.
+ */
export interface StatusbarManager {
+ /**
+ * A read-only array of all currently registered status bar items.
+ */
readonly statusBarItems: ReadonlyArray<StatusbarItem>;
+
+ /**
+ * Registers a new item to be displayed in the status bar.
+ * @param item The status bar item to register.
+ */
registerItem(item: StatusbarItem): void;
}
diff --git a/ui/src/public/tab.ts b/ui/src/public/tab.ts
index 97d7065..6032404 100644
--- a/ui/src/public/tab.ts
+++ b/ui/src/public/tab.ts
@@ -14,22 +14,86 @@
import m from 'mithril';
+/**
+ * Manages the registration, display, and hiding of tabs within the UI.
+ *
+ * Tabs provide a way to organize different views or functionalities within
+ * the application, allowing users to switch between them easily.
+ */
export interface TabManager {
+ /**
+ * Registers a new tab with the TabManager.
+ *
+ * @param tab The descriptor for the tab to register.
+ */
registerTab(tab: TabDescriptor): void;
+
+ /**
+ * Displays the tab associated with the given URI.
+ *
+ * If the tab is not currently visible, it will be brought to the foreground.
+ * @param uri The unique URI of the tab to show.
+ */
showTab(uri: string): void;
+
+ /**
+ * Hides the tab associated with the given URI.
+ *
+ * @param uri The unique URI of the tab to hide.
+ */
hideTab(uri: string): void;
+
+ /**
+ * Adds a tab to the list of default tabs.
+ *
+ * Default tabs are automatically opened when the application starts or
+ * when a new trace is loaded.
+ * @param uri The unique URI of the tab to add as a default.
+ */
addDefaultTab(uri: string): void;
}
+/**
+ * Represents the content and title of a tab.
+ */
export interface Tab {
+ /**
+ * Renders the content of the tab.
+ * @returns The Mithril children to render for the tab's content.
+ */
render(): m.Children;
+
+ /**
+ * Gets the title of the tab.
+ * @returns The human-readable title of the tab.
+ */
getTitle(): string;
}
+/**
+ * Describes a tab to be registered with the TabManager.
+ */
export interface TabDescriptor {
- uri: string; // TODO(stevegolton): Maybe optional for ephemeral tabs.
- content: Tab;
- isEphemeral?: boolean; // Defaults false
+ /**
+ * The unique URI for this tab.
+ * TODO(stevegolton): Maybe optional for ephemeral tabs.
+ */
+ readonly uri: string;
+ /**
+ * The content of the tab, including its render function and title.
+ */
+ readonly content: Tab;
+ /**
+ * If true, this tab is ephemeral and may be closed automatically under
+ * certain conditions (e.g., when a trace is closed). Defaults to `false`.
+ */
+ readonly isEphemeral?: boolean;
+ /**
+ * An optional callback function that is invoked when the tab is hidden.
+ */
onHide?(): void;
+ /**
+ * An optional callback function that is invoked when the tab is shown.
+ */
onShow?(): void;
}
diff --git a/ui/src/public/timeline.ts b/ui/src/public/timeline.ts
index 58507f9..dc45eb7 100644
--- a/ui/src/public/timeline.ts
+++ b/ui/src/public/timeline.ts
@@ -16,56 +16,130 @@
import {time} from '../base/time';
import {Setting} from './settings';
+/**
+ * Defines the various formats for displaying timestamps in the UI.
+ */
export enum TimestampFormat {
+ /** Displays time as a timecode (e.g., HH:MM:SS.mmm). */
Timecode = 'timecode',
+ /** Displays raw trace nanoseconds. */
TraceNs = 'traceNs',
+ /** Displays raw trace nanoseconds, formatted according to locale. */
TraceNsLocale = 'traceNsLocale',
+ /** Displays time in seconds. */
Seconds = 'seconds',
+ /** Displays time in milliseconds. */
Milliseconds = 'milliseconds',
+ /** Displays time in microseconds. */
Microseconds = 'microseconds',
+ /** Displays time in UTC format. */
UTC = 'utc',
+ /** Displays time in a custom timezone. */
CustomTimezone = 'customTimezone',
+ /** Displays time in the trace's timezone. */
TraceTz = 'traceTz',
}
+/**
+ * Defines the precision for displaying durations in the UI.
+ */
export enum DurationPrecision {
+ /** Displays full precision for durations. */
Full = 'full',
+ /** Displays human-readable durations (e.g., 1h 2m 3s). */
HumanReadable = 'human_readable',
}
+/**
+ * Manages the interactive timeline and viewport.
+ *
+ * The timeline allows users to navigate through the trace, zoom in and out,
+ * and interact with various time-based elements.
+ */
export interface Timeline {
- // Bring a timestamp into view.
+ /**
+ * Brings a specific timestamp into the current viewport.
+ * @param ts The timestamp to pan to.
+ */
panToTimestamp(ts: time): void;
- // Move the viewport.
+ /**
+ * Sets the start and end times of the current viewport.
+ * @param start The start timestamp of the viewport.
+ * @param end The end timestamp of the viewport.
+ */
setViewportTime(start: time, end: time): void;
- // A span representing the current viewport location.
+ /**
+ * A span representing the current visible time range in the viewport.
+ */
readonly visibleWindow: HighPrecisionTimeSpan;
- // Render a vertical line on the timeline at this timestamp.
+ /**
+ * The timestamp where the hover cursor is currently located on the timeline.
+ * Setting this value will render a vertical line at the specified timestamp.
+ */
hoverCursorTimestamp: time | undefined;
+ /**
+ * The timestamp of a hovered note on the timeline.
+ * Setting this value will highlight the corresponding note.
+ */
hoveredNoteTimestamp: time | undefined;
+
+ /**
+ * The ID of the currently highlighted slice.
+ * Setting this value will highlight the corresponding slice in the UI.
+ */
highlightedSliceId: number | undefined;
+ /**
+ * The UTID (Unique Thread ID) of the currently hovered thread.
+ */
hoveredUtid: number | undefined;
+
+ /**
+ * The PID (Process ID) of the currently hovered process.
+ */
hoveredPid: bigint | undefined;
- // This value defines the time of the origin of the time axis in trace time.
- // Depending on the timestamp format setting, this value can change:
- // E.g.
- // - Raw - origin = 0
- // - Seconds - origin = trace.start.
- // - Realtime - origin = midnight before trace.start.
+ /**
+ * Gets the time of the origin of the time axis in trace time.
+ *
+ * Depending on the timestamp format setting, this value can change:
+ * - Raw: origin = 0
+ * - Seconds: origin = trace.start
+ * - Realtime: origin = midnight before trace.start
+ *
+ * @returns The origin timestamp of the time axis.
+ */
getTimeAxisOrigin(): time;
- // Get a time in the current domain as specified by timestampOffset.
+ /**
+ * Converts a timestamp to a time in the current domain, as specified by
+ * the timestamp offset.
+ * @param ts The timestamp to convert.
+ * @returns The timestamp in the current domain.
+ */
toDomainTime(ts: time): time;
- // These control how timestamps and durations are formatted throughout the UI
+ /**
+ * Controls how timestamps are formatted throughout the UI.
+ */
timestampFormat: TimestampFormat;
+
+ /**
+ * Controls how durations are formatted throughout the UI.
+ */
durationPrecision: DurationPrecision;
+
+ /**
+ * The custom timezone offset in minutes.
+ */
customTimezoneOffset: number;
+
+ /**
+ * The setting for overriding the default timezone.
+ */
timezoneOverride: Setting<string>;
}
diff --git a/ui/src/public/trace.ts b/ui/src/public/trace.ts
index 80865f2..58a5039 100644
--- a/ui/src/public/trace.ts
+++ b/ui/src/public/trace.ts
@@ -32,7 +32,7 @@
// Lists all the possible event listeners using the key as the event name and
// the type as the type of the callback.
export interface EventListeners {
- traceready: () => Promise<void> | void;
+ traceready(): Promise<void> | void;
}
/**
diff --git a/ui/src/public/trace_info.ts b/ui/src/public/trace_info.ts
index 4e20a90..71b7c38 100644
--- a/ui/src/public/trace_info.ts
+++ b/ui/src/public/trace_info.ts
@@ -4,7 +4,7 @@
// 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
+// http://www.apache.org/licenses/LICENSE-20.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,46 +14,80 @@
import {time} from '../base/time';
+/**
+ * Provides information about the currently loaded trace.
+ */
export interface TraceInfo {
- readonly traceTitle: string; // File name and size of the current trace.
- readonly traceUrl: string; // URL of the Trace.
+ /**
+ * The title of the trace, typically the file name and size.
+ */
+ readonly traceTitle: string;
+ /**
+ * The URL from which the trace was loaded, if applicable.
+ */
+ readonly traceUrl: string;
+ /**
+ * The start timestamp of the trace.
+ */
readonly start: time;
+ /**
+ * The end timestamp of the trace.
+ */
readonly end: time;
- // This is the ts value at the time of the Unix epoch.
- // Normally some large negative value, because the unix epoch is normally in
- // the past compared to ts=0.
+ /**
+ * The timestamp value at the time of the Unix epoch.
+ *
+ * Normally some large negative value, because the Unix epoch is typically in
+ * the past compared to `ts=0`.
+ */
readonly unixOffset: time;
- // Represents the reported timezone in minutes from UTC.
+ /**
+ * The reported timezone offset in minutes from UTC.
+ */
readonly tzOffMin: number;
- // The number of import/analysis errors present in the `stats` table.
+ /**
+ * The number of import/analysis errors present in the `stats` table.
+ */
readonly importErrors: number;
- // The trace type inferred by TraceProcessor (e.g. 'proto', 'json, ...).
- // See TraceTypeToString() in src/trace_processor/util/trace_type.cc for
- // all the available types.
+ /**
+ * The trace type inferred by TraceProcessor (e.g., 'proto', 'json', ...).
+ *
+ * See `TraceTypeToString()` in `src/trace_processor/util/trace_type.cc` for
+ * all available types.
+ */
readonly traceType?: string;
- // True if the trace contains any ftrace data (sched or other ftrace events).
+ /**
+ * `true` if the trace contains any ftrace data (sched or other ftrace events).
+ */
readonly hasFtrace: boolean;
- // The UUID of the trace. This is generated by TraceProcessor by either
- // looking at the TraceUuid packet emitted by traced or, as a fallback, by
- // hashing the first KB of the trace. This can be an empty string in rare
- // cases (e.g., opening an empty trace).
+ /**
+ * The UUID of the trace. This is generated by TraceProcessor by either
+ * looking at the `TraceUuid` packet emitted by `traced` or, as a fallback, by
+ * hashing the first KB of the trace. This can be an empty string in rare
+ * cases (e.g., opening an empty trace).
+ */
readonly uuid: string;
- // Wheteher the current trace has been successfully stored into cache storage.
+ /**
+ * Whether the current trace has been successfully stored into cache storage.
+ */
readonly cached: boolean;
- // Returns true if the current trace can be downloaded via getTraceFile().
- // The trace isn't downloadable in the following cases:
- // - It comes from a source (e.g. HTTP+RPC) that doesn't support re-download
- // due to technical limitations.
- // - Download is disabled because the trace was pushed via postMessage and
- // the caller has asked to disable downloads.
+ /**
+ * Returns `true` if the current trace can be downloaded via `getTraceFile()`.
+ *
+ * The trace isn't downloadable in the following cases:
+ * - It comes from a source (e.g., HTTP+RPC) that doesn't support re-download
+ * due to technical limitations.
+ * - Download is disabled because the trace was pushed via `postMessage` and
+ * the caller has asked to disable downloads.
+ */
readonly downloadable: boolean;
}
diff --git a/ui/src/public/track.ts b/ui/src/public/track.ts
index 58ac999..c15416f 100644
--- a/ui/src/public/track.ts
+++ b/ui/src/public/track.ts
@@ -25,52 +25,99 @@
import {CanvasColors} from './canvas_colors';
import {z} from 'zod';
+/**
+ * Defines criteria for filtering tracks.
+ */
export interface TrackFilterCriteria {
+ /**
+ * The human-readable name of the filter criteria.
+ */
readonly name: string;
- // Run on each node to work out whether it satisfies the selected filter
- // option.
+ /**
+ * A predicate function that determines whether a track satisfies the selected
+ * filter option.
+ * @param track The track node to evaluate.
+ * @param filterOption The selected filter option string.
+ * @returns `true` if the track satisfies the filter, `false` otherwise.
+ */
readonly predicate: (track: TrackNode, filterOption: string) => boolean;
- // The list of possible filter options.
- readonly options: ReadonlyArray<{key: string; label: string}>;
+ /**
+ * The list of possible filter options for this criteria.
+ */
+ readonly options: ReadonlyArray<{
+ readonly key: string;
+ readonly label: string;
+ }>;
}
+/**
+ * Manages the registration and discovery of tracks.
+ */
export interface TrackManager {
/**
- * Register a new track against a unique key known as a URI. The track is not
- * shown by default and callers need to either manually add it to a
- * Workspace or use registerTrackAndShowOnTraceLoad() below.
+ * Registers a new track with a unique URI.
+ *
+ * The track is not shown by default; callers need to either manually add it
+ * to a Workspace or use `registerTrackAndShowOnTraceLoad()` (if available)
+ * to display it.
+ * @param track The track to register.
*/
registerTrack(track: Track): void;
+ /**
+ * Finds a track that satisfies the given predicate.
+ * @param predicate A function that returns `true` for the desired track.
+ * @returns The first track that satisfies the predicate, or `undefined` if
+ * none is found.
+ */
findTrack(
predicate: (track: Track) => boolean | undefined,
): Track | undefined;
+ /**
+ * Retrieves all currently registered tracks.
+ * @returns An array of all registered tracks.
+ */
getAllTracks(): Track[];
+ /**
+ * Retrieves a track by its unique URI.
+ * @param uri The unique URI of the track.
+ * @returns The track if found, or `undefined`.
+ */
getTrack(uri: string): Track | undefined;
/**
- * Register a track filter criteria, which can be used by end users to control
- * the list of tracks they see in workspaces. These criteria can provide more
- * power to the user compared to e.g. purely filtering by name.
+ * Registers a track filter criteria, which can be used by end users to
+ * control the list of tracks they see in workspaces.
+ *
+ * These criteria can provide more power to the user compared to purely
+ * filtering by name.
+ * @param filter The track filter criteria to register.
*/
registerTrackFilterCriteria(filter: TrackFilterCriteria): void;
/**
- * Register a timeline overlay renderer.
+ * Registers a timeline overlay renderer.
*
* Overlays are rendered on top of all tracks in the timeline view and can be
* used to draw annotations that span multiple tracks, such as flow arrows or
* vertical lines marking specific events.
+ * @param overlay The overlay to register.
*/
registerOverlay(overlay: Overlay): void;
}
+/**
+ * Contextual information about the track passed to track lifecycle hooks &
+ * render hooks.
+ */
export interface TrackContext {
- // This track's URI, used for making selections et al.
+ /**
+ * This track's URI, used for making selections and other operations.
+ */
readonly trackUri: string;
}
@@ -116,30 +163,46 @@
readonly colors: CanvasColors;
}
-// A definition of a track, including a renderer implementation and metadata.
+/**
+ * A definition of a track, including a renderer implementation and metadata.
+ */
export interface Track {
- // A unique identifier for this track.
+ /**
+ * A unique identifier for this track.
+ */
readonly uri: string;
- // Describes how to render the track.
+ /**
+ * Describes how to render the track.
+ */
readonly renderer: TrackRenderer;
- // Optional: A human readable description of the track. This can be a simple
- // string or a render function that returns Mithril vnodes.
+ /**
+ * Optional: A human readable description of the track. This can be a simple
+ * string or a render function that returns Mithril vnodes.
+ */
readonly description?: string | (() => m.Children);
- // Optional: Human readable subtitle. Sometimes displayed if there is room.
+ /**
+ * Optional: Human readable subtitle. Sometimes displayed if there is room.
+ */
readonly subtitle?: string;
- // Optional: A list of tags which provide additional metadata about the track.
- // Used mainly for legacy purposes that predate dataset.
+ /**
+ * Optional: A list of tags which provide additional metadata about the track.
+ * Used mainly for legacy purposes that predate dataset.
+ */
readonly tags?: TrackTags;
- // Optional: A list of strings which are displayed as "chips" in the track
- // shell.
+ /**
+ * Optional: A list of strings which are displayed as "chips" in the track
+ * shell.
+ */
readonly chips?: ReadonlyArray<string>;
- // Filled in by the core.
+ /**
+ * Filled in by the core.
+ */
readonly pluginId?: string;
}
@@ -148,12 +211,12 @@
*/
export interface TrackMouseEvent {
/**
- * X coordinate of the mouse event w.r.t. the top-left of the track.
+ * X coordinate of the mouse event with respect to the top-left of the track.
*/
readonly x: number;
/**
- * Y coordinate of the mouse event w.r.t the top-left of the track.
+ * Y coordinate of the mouse event with respect to the top-left of the track.
*/
readonly y: number;
@@ -172,35 +235,51 @@
*
* A lot of the fields in this interface are currently unused, but they will be
* used in the future when track serialization is implemented.
+ * @template T The type of the setting's value.
*/
export interface TrackSettingDescriptor<T> {
- // A unique identifier for this setting. Will be used to store the serialized
- // value for this setting. Currently unused.
+ /**
+ * A unique identifier for this setting. Will be used to store the serialized
+ * value for this setting. Currently unused.
+ */
readonly id: string;
- // A human readable name for this setting. This is displayed in the settings
- // menu unless overridden.
+ /**
+ * A human readable name for this setting. This is displayed in the settings
+ * menu unless overridden.
+ */
readonly name: string;
- // A human readable description for this setting. Currently unused, but good
- // practice to require this in order to document what a setting does and is
- // used for.
+ /**
+ * A human readable description for this setting. Currently unused, but good
+ * practice to require this in order to document what a setting does and is
+ * used for.
+ */
readonly description: string;
- // A Zod schema describing the setting's value type which is used to infer the
- // automatic settings menu type and options, and will be used for
- // serialization and deserialization.
+ /**
+ * A Zod schema describing the setting's value type which is used to infer the
+ * automatic settings menu type and options, and will be used for
+ * serialization and deserialization.
+ */
readonly schema: z.ZodType<T>;
- // The default value for this setting. This will be used to render a 'reset'
- // button in the render menu, and possibly as a fallback if parsing fails when
- // we add serialization. Currently unused.
+ /**
+ * The default value for this setting. This will be used to render a 'reset'
+ * button in the render menu, and possibly as a fallback if parsing fails when
+ * we add serialization. Currently unused.
+ */
readonly defaultValue: T;
- // An optional function used to render a control for this setting. This
- // describes what the control looks like in the settings menu on the track and
- // also the bulk settings menu when multiple tracks are selected. If omitted,
- // a control will be automatically generated based on the schema and name.
+ /**
+ * An optional function used to render a control for this setting. This
+ * describes what the control looks like in the settings menu on the track and
+ * also the bulk settings menu when multiple tracks are selected. If omitted,
+ * a control will be automatically generated based on the schema and name.
+ * @param setter A function to set the value of the setting.
+ * @param values An array of current values for the setting (for bulk editing).
+ * @returns Mithril children to render the control.
+ */
render?(setter: (value: T) => void, values: ReadonlyArray<T>): m.Children;
}
@@ -208,13 +287,28 @@
* A setting that can be changed by the user that affects how the track is
* rendered or behaves. References a TrackSettingDescriptor which describes the
* setting's metadata and how to render a control for it.
+ * @template T The type of the setting's value.
*/
export interface TrackSetting<T> {
+ /**
+ * The descriptor for this track setting.
+ */
readonly descriptor: TrackSettingDescriptor<T>;
- getValue: () => T;
+ /**
+ * Gets the current value of the setting.
+ * @returns The current value of the setting.
+ */
+ getValue(): T;
+ /**
+ * Sets the value of the setting.
+ * @param newValue The new value for the setting.
+ */
setValue(newValue: T): void;
}
+/**
+ * Defines the rendering logic and lifecycle hooks for a track.
+ */
export interface TrackRenderer {
/**
* Describes which root table the events on this track come from. This is
@@ -251,6 +345,7 @@
*
* Note: On the first render cycle, both onCreate and onUpdate are called one
* after another.
+ * @param ctx The track context.
*/
onCreate?(ctx: TrackContext): Promise<void>;
@@ -260,6 +355,7 @@
* The track should inspect things like the visible window, track size, and
* resolution to work out whether any data needs to be reloaded based on these
* properties and perform a reload.
+ * @param ctx The track render context.
*/
onUpdate?(ctx: TrackRenderContext): Promise<void>;
@@ -272,48 +368,93 @@
/**
* Required method used to render the track's content to the canvas, called
* synchronously on every render cycle.
+ * @param ctx The track render context.
*/
render(ctx: TrackRenderContext): void;
+
+ /**
+ * Optional: Called when a full redraw of the track is required.
+ */
onFullRedraw?(): void;
/**
* Return the vertical bounds (top & bottom) of a slice were it to be rendered
* at a specific depth, given the slice height and padding/spacing that this
* track uses.
+ * @param depth The depth of the slice.
+ * @returns The vertical bounds of the slice, or `undefined`.
*/
getSliceVerticalBounds?(depth: number): VerticalBounds | undefined;
+
+ /**
+ * Optional: Returns the height of the track.
+ * @returns The height of the track in pixels.
+ */
getHeight?(): number;
+
+ /**
+ * Optional: Returns Mithril children for buttons to be displayed in the track shell.
+ * @returns Mithril children representing the track shell buttons.
+ */
getTrackShellButtons?(): m.Children;
+
+ /**
+ * Optional: Called when the mouse moves over the track.
+ * @param event The track mouse event.
+ */
onMouseMove?(event: TrackMouseEvent): void;
+
+ /**
+ * Optional: Called when the mouse is clicked on the track.
+ * @param event The track mouse event.
+ * @returns `true` if the click was handled, `false` otherwise.
+ */
onMouseClick?(event: TrackMouseEvent): boolean;
+
+ /**
+ * Optional: Called when the mouse leaves the track area.
+ */
onMouseOut?(): void;
/**
* Optional: Returns a dataset that represents the events displayed on this
* track.
+ * @returns The source dataset for the track, or `undefined`.
*/
getDataset?(): SourceDataset | undefined;
/**
* Optional: Get details of a track event given by eventId on this track.
+ * @param eventId The ID of the track event.
+ * @returns A promise that resolves to the track event details, or `undefined`.
*/
getSelectionDetails?(eventId: number): Promise<TrackEventDetails | undefined>;
- // Optional: A factory that returns a details panel object for a given track
- // event selection. This is called each time the selection is changed (and the
- // selection is relevant to this track).
+ /**
+ * Optional: A factory that returns a details panel object for a given track
+ * event selection. This is called each time the selection is changed (and the
+ * selection is relevant to this track).
+ * @param sel The track event selection.
+ * @returns The track event details panel, or `undefined`.
+ */
detailsPanel?(sel: TrackEventSelection): TrackEventDetailsPanel | undefined;
- // Optional: Returns tooltip content if available. If the return value is
- // falsy, no tooltip is rendered.
+ /**
+ * Optional: Returns tooltip content if available. If the return value is
+ * falsy, no tooltip is rendered.
+ * @returns Mithril children for the tooltip content, or `undefined`.
+ */
renderTooltip?(): m.Children;
}
-// An set of key/value pairs describing a given track. These are used for
-// selecting tracks to pin/unpin, diplsaying "chips" in the track shell, and
-// (in future) the sorting and grouping of tracks.
-// We define a handful of well known fields, and the rest are arbitrary key-
-// value pairs.
+/**
+ * An set of key/value pairs describing a given track. These are used for
+ * selecting tracks to pin/unpin, displaying "chips" in the track shell, and
+ * (in future) the sorting and grouping of tracks.
+ *
+ * We define a handful of well known fields, and the rest are arbitrary key-
+ * value pairs.
+ */
export type TrackTags = Partial<WellKnownTrackTags> & {
// There may be arbitrary other key/value pairs.
[key: string]:
@@ -325,72 +466,147 @@
| ReadonlyArray<number>;
};
+/**
+ * Well-known track tags used for various subsystems.
+ */
interface WellKnownTrackTags {
- // The track "kinds", are by various subsystems e.g. aggregation controllers
- // in order to select tracks to operate on. A good analogy is how CSS
- // selectors can match elements using their class list.
- kinds: ReadonlyArray<string>;
+ /**
+ * The track "kinds", are by various subsystems e.g. aggregation controllers
+ * in order to select tracks to operate on. A good analogy is how CSS
+ * selectors can match elements using their class list.
+ */
+ readonly kinds: ReadonlyArray<string>;
- // Optional: list of track IDs represented by this trace.
- // This list is used for participation in track indexing by track ID.
- // This index is used by various subsystems to find links between tracks based
- // on the track IDs used by trace processor.
- trackIds: ReadonlyArray<number>;
+ /**
+ * Optional: list of track IDs represented by this trace.
+ * This list is used for participation in track indexing by track ID.
+ * This index is used by various subsystems to find links between tracks based
+ * on the track IDs used by trace processor.
+ */
+ readonly trackIds: ReadonlyArray<number>;
- // Optional: The CPU number associated with this track.
- cpu: number;
+ /**
+ * Optional: The CPU number associated with this track.
+ */
+ readonly cpu: number;
- // Optional: The UTID associated with this track.
- utid: number;
+ /**
+ * Optional: The UTID associated with this track.
+ */
+ readonly utid: number;
- // Optional: The UPID associated with this track.
- upid: number;
+ /**
+ * Optional: The UPID associated with this track.
+ */
+ readonly upid: number;
- // Track type, used for filtering
- type: string;
+ /**
+ * Track type, used for filtering.
+ */
+ readonly type: string;
}
+/**
+ * Represents a single slice on a track.
+ */
export interface Slice {
- // These properties are updated only once per query result when the Slice
- // object is created and don't change afterwards.
+ /**
+ * The unique ID of the slice.
+ * These properties are updated only once per query result when the Slice
+ * object is created and don't change afterwards.
+ */
readonly id: number;
+ /**
+ * The start timestamp of the slice in nanoseconds.
+ */
readonly startNs: time;
+ /**
+ * The end timestamp of the slice in nanoseconds.
+ */
readonly endNs: time;
+ /**
+ * The duration of the slice in nanoseconds.
+ */
readonly durNs: duration;
+ /**
+ * The timestamp of the slice.
+ */
readonly ts: time;
+ /**
+ * The count associated with the slice.
+ */
readonly count: number;
+ /**
+ * The duration of the slice.
+ */
readonly dur: duration;
+ /**
+ * The depth of the slice in its track.
+ */
readonly depth: number;
+ /**
+ * Flags associated with the slice.
+ */
readonly flags: number;
- // Each slice can represent some extra numerical information by rendering a
- // portion of the slice with a lighter tint.
- // |fillRatio\ describes the ratio of the normal area to the tinted area
- // width of the slice, normalized between 0.0 -> 1.0.
- // 0.0 means the whole slice is tinted.
- // 1.0 means none of the slice is tinted.
- // E.g. If |fillRatio| = 0.65 the slice will be rendered like this:
- // [############|*******]
- // ^------------^-------^
- // Normal Light
+ /**
+ * Each slice can represent some extra numerical information by rendering a
+ * portion of the slice with a lighter tint.
+ * `fillRatio` describes the ratio of the normal area to the tinted area
+ * width of the slice, normalized between 0.0 -> 1.0.
+ * 0.0 means the whole slice is tinted.
+ * 1.0 means none of the slice is tinted.
+ * E.g. If `fillRatio` = 0.65 the slice will be rendered like this:
+ * [############|*******]
+ * ^------------^-------^
+ * Normal Light
+ */
readonly fillRatio: number;
- // These can be changed by the Impl.
+ /**
+ * The title of the slice. These can be changed by the Impl.
+ */
title?: string;
+ /**
+ * The subtitle of the slice.
+ */
subTitle: string;
+ /**
+ * The color scheme used for the slice.
+ */
colorScheme: ColorScheme;
+ /**
+ * Whether the slice is currently highlighted.
+ */
isHighlighted: boolean;
}
/**
- * Contains a track and it's top and bottom coordinates in the timeline.
+ * Contains a track and its top and bottom coordinates in the timeline.
*/
export interface TrackBounds {
+ /**
+ * The track node.
+ */
readonly node: TrackNode;
+ /**
+ * The vertical bounds of the track.
+ */
readonly verticalBounds: VerticalBounds;
}
+/**
+ * Defines a timeline overlay renderer.
+ */
export interface Overlay {
+ /**
+ * Renders the overlay on top of the tracks.
+ * @param ctx The 2D rendering context of the canvas.
+ * @param timescale The time scale used for translating between pixels and time.
+ * @param size The dimensions of the canvas in pixels.
+ * @param tracks A read-only array of track bounds.
+ * @param theme The canvas colors for the current theme.
+ */
render(
ctx: CanvasRenderingContext2D,
timescale: TimeScale,
diff --git a/ui/src/public/workspace.ts b/ui/src/public/workspace.ts
index a8987c7..ed506cb 100644
--- a/ui/src/public/workspace.ts
+++ b/ui/src/public/workspace.ts
@@ -15,11 +15,29 @@
import {assertTrue} from '../base/logging';
import {errResult, okResult, Result} from '../base/result';
+/**
+ * Manages workspaces, allowing for creation, switching, and access to the
+ * current workspace.
+ */
export interface WorkspaceManager {
- // This is the same of ctx.workspace, exposed for consistency also here.
+ /**
+ * The currently active workspace. This is the same as `ctx.workspace`.
+ */
readonly currentWorkspace: Workspace;
+ /**
+ * A read-only array of all available workspaces.
+ */
readonly all: ReadonlyArray<Workspace>;
+ /**
+ * Creates a new, empty workspace.
+ * @param displayName The human-readable name for the new workspace.
+ * @returns The newly created workspace.
+ */
createEmptyWorkspace(displayName: string): Workspace;
+ /**
+ * Switches the currently active workspace.
+ * @param workspace The workspace to switch to.
+ */
switchWorkspace(workspace: Workspace): void;
}
@@ -37,80 +55,100 @@
*
* TODO(stevegolton): We could possibly move this into its own module and use it
* everywhere where session-unique ids are required.
+ * @returns A session-unique ID.
*/
function createSessionUniqueId(): string {
return (sessionUniqueIdCounter++).toString();
}
/**
- * Describes generic parent track node functionality - i.e. any entity that can
- * contain child TrackNodes, providing methods to add, remove, and access child
- * nodes.
- *
- * This class is abstract because, while it can technically be instantiated on
- * its own (no abstract methods/properties), it can't and shouldn't be
- * instantiated anywhere in practice - all APIs require either a TrackNode or a
- * Workspace.
- *
- * Thus, it serves two purposes:
- * 1. Avoiding duplication between Workspace and TrackNode, which is an internal
- * implementation detail of this module.
- * 2. Providing a typescript interface for a generic TrackNode container class,
- * which otherwise you might have to achieve using `Workspace | TrackNode`
- * which is uglier.
- *
- * If you find yourself using this as a Javascript class in external code, e.g.
- * `instance of TrackNodeContainer`, you're probably doing something wrong.
+ * Arguments for creating a new `TrackNode`.
*/
-
export interface TrackNodeArgs {
- name: string;
- uri: string;
- headless: boolean;
- sortOrder: number;
- collapsed: boolean;
- isSummary: boolean;
- removable: boolean;
+ /**
+ * The human-readable name for this track, displayed in the track shell.
+ */
+ readonly name: string;
+ /**
+ * The URI of the track content to display.
+ */
+ readonly uri: string;
+ /**
+ * If `true`, the header for this track will not be shown, and its children
+ * will be displayed un-nested.
+ */
+ readonly headless: boolean;
+ /**
+ * An optional sort order, which workspaces may use for sorting. Lower numbers
+ * appear first.
+ */
+ readonly sortOrder: number;
+ /**
+ * If `true`, the track will be initially collapsed.
+ */
+ readonly collapsed: boolean;
+ /**
+ * If `true`, this track will be used as a summary for its children.
+ */
+ readonly isSummary: boolean;
+ /**
+ * If `true`, this node will be removable by the user.
+ */
+ readonly removable: boolean;
}
/**
* A base class for any node with children (i.e. a group or a workspace).
*/
export class TrackNode {
- // Immutable unique (within the workspace) ID of this track node. Used for
- // efficiently retrieving this node object from a workspace. Note: This is
- // different to |uri| which is used to reference a track to render on the
- // track. If this means nothing to you, don't bother using it.
+ /**
+ * Immutable unique (within the workspace) ID of this track node. Used for
+ * efficiently retrieving this node object from a workspace. Note: This is
+ * different to `uri` which is used to reference a track to render on the
+ * track. If this means nothing to you, don't bother using it.
+ */
public readonly id: string;
- // A human readable string for this track - displayed in the track shell.
- // TODO(stevegolton): Make this optional, so that if we implement a string for
- // this track then we can implement it here as well.
+ /**
+ * A human readable string for this track - displayed in the track shell.
+ * TODO(stevegolton): Make this optional, so that if we implement a string for
+ * this track then we can implement it here as well.
+ */
public name: string;
- // The URI of the track content to display here.
+ /**
+ * The URI of the track content to display here.
+ */
public uri?: string;
- // Optional sort order, which workspaces may or may not take advantage of for
- // sorting when displaying the workspace. Lower numbers appear first.
+ /**
+ * Optional sort order, which workspaces may or may not take advantage of for
+ * sorting when displaying the workspace. Lower numbers appear first.
+ */
public sortOrder?: number;
- // Don't show the header at all for this track, just show its un-nested
- // children. This is helpful to group together tracks that logically belong to
- // the same group (e.g. all ftrace cpu tracks) and ease the job of
- // sorting/grouping plugins.
+ /**
+ * Don't show the header at all for this track, just show its un-nested
+ * children. This is helpful to group together tracks that logically belong to
+ * the same group (e.g. all ftrace cpu tracks) and ease the job of
+ * sorting/grouping plugins.
+ */
public headless: boolean;
- // If true, this track is to be used as a summary for its children. When the
- // group is expanded the track will become sticky to the top of the viewport
- // to provide context for the tracks within, and the content of this track
- // shall be omitted. It will also be squashed down to a smaller height to save
- // vertical space.
+ /**
+ * If true, this track is to be used as a summary for its children. When the
+ * group is expanded the track will become sticky to the top of the viewport
+ * to provide context for the tracks within, and the content of this track
+ * shall be omitted. It will also be squashed down to a smaller height to save
+ * vertical space.
+ */
public isSummary: boolean;
- // If true, this node will be removable by the user. It will show a little
- // close button in the track shell which the user can press to remove the
- // track from the workspace.
+ /**
+ * If true, this node will be removable by the user. It will show a little
+ * close button in the track shell which the user can press to remove the
+ * track from the workspace.
+ */
public removable: boolean;
protected _collapsed = true;
@@ -120,6 +158,9 @@
private _parent?: TrackNode;
public _workspace?: Workspace;
+ /**
+ * The parent of this track node, or `undefined` if it is a root node.
+ */
get parent(): TrackNode | undefined {
return this._parent;
}
@@ -146,7 +187,8 @@
}
/**
- * Remove this track from it's parent & unpin from the workspace if pinned.
+ * Removes this track from its parent and unpins it from the workspace if
+ * pinned.
*/
remove(): void {
this.workspace?.unpinTrack(this);
@@ -154,7 +196,7 @@
}
/**
- * Add this track to the list of pinned tracks in its parent workspace.
+ * Adds this track to the list of pinned tracks in its parent workspace.
*
* Has no effect if this track is not added to a workspace.
*/
@@ -163,7 +205,7 @@
}
/**
- * Remove this track from the list of pinned tracks in its parent workspace.
+ * Removes this track from the list of pinned tracks in its parent workspace.
*
* Has no effect if this track is not added to a workspace.
*/
@@ -172,23 +214,24 @@
}
/**
- * Returns true if this node is added to a workspace as is in the pinned track
- * list of that workspace.
+ * Returns `true` if this node is added to a workspace and is in the pinned
+ * track list of that workspace.
*/
get isPinned(): boolean {
return Boolean(this.workspace?.hasPinnedTrack(this));
}
/**
- * Find the closest visible ancestor TrackNode.
+ * Finds the closest visible ancestor TrackNode.
*
- * Given the path from the root workspace to this node, find the fist one,
+ * Given the path from the root workspace to this node, find the first one,
* starting from the root, which is collapsed. This will be, from the user's
* point of view, the closest ancestor of this node.
*
- * Returns undefined if this node is actually visible.
+ * Returns `undefined` if this node is actually visible.
*
* TODO(stevegolton): Should it return itself in this case?
+ * @returns The closest visible ancestor, or `this` if the node is visible.
*/
findClosestVisibleAncestor(): TrackNode {
// Build a path from the root workspace to this node
@@ -206,7 +249,7 @@
}
/**
- * Expand all ancestor nodes.
+ * Expands all ancestor nodes to make this node visible.
*/
reveal(): void {
let parent = this.parent;
@@ -217,8 +260,9 @@
}
/**
- * Get all ancestors of this node from root to immediate parent.
- * Returns an empty array if this node has no parent.
+ * Gets all ancestors of this node from root to immediate parent.
+ * @returns An array of ancestor nodes, or an empty array if this node has no
+ * parent.
*/
getAncestors(): TrackNode[] {
const ancestors: TrackNode[] = [];
@@ -231,7 +275,7 @@
}
/**
- * Find this node's root node - this may be a workspace or another node.
+ * Finds this node's root node - this may be a workspace or another node.
*/
get rootNode(): TrackNode {
let node: TrackNode = this;
@@ -242,21 +286,21 @@
}
/**
- * Find this node's workspace if it is attached to one.
+ * Finds this node's workspace if it is attached to one.
*/
get workspace(): Workspace | undefined {
return this.rootNode._workspace;
}
/**
- * Mark this node as un-collapsed, indicating its children should be rendered.
+ * Marks this node as un-collapsed, indicating its children should be rendered.
*/
expand(): void {
this._collapsed = false;
}
/**
- * Mark this node as collapsed, indicating its children should not be
+ * Marks this node as collapsed, indicating its children should not be
* rendered.
*/
collapse(): void {
@@ -264,14 +308,15 @@
}
/**
- * Toggle the collapsed state.
+ * Toggles the collapsed state.
*/
toggleCollapsed(): void {
this._collapsed = !this._collapsed;
}
/**
- * Whether this node is collapsed, indicating its children should be rendered.
+ * Whether this node is collapsed, indicating its children should not be
+ * rendered.
*/
get collapsed(): boolean {
return this._collapsed;
@@ -287,7 +332,7 @@
/**
* Returns the list of titles representing the full path from the root node to
- * the current node. This path consists only of node titles, workspaces are
+ * the current node. This path consists only of node titles; workspaces are
* omitted.
*/
get fullPath(): ReadonlyArray<string> {
@@ -304,7 +349,7 @@
}
/**
- * True if this node has children, false otherwise.
+ * `true` if this node has children, `false` otherwise.
*/
get hasChildren(): boolean {
return this._children.length > 0;
@@ -318,14 +363,15 @@
}
/**
- * Inserts a new child node considering it's sortOrder.
+ * Inserts a new child node considering its `sortOrder`.
*
- * The child will be added before the first child whose |sortOrder| is greater
+ * The child will be added before the first child whose `sortOrder` is greater
* than the child node's sort order, or at the end if one does not exist. If
- * |sortOrder| is omitted on either node in the comparison it is assumed to be
+ * `sortOrder` is omitted on either node in the comparison it is assumed to be
* 0.
*
- * @param child - The child node to add.
+ * @param child The child node to add.
+ * @returns A `Result` indicating success or failure.
*/
addChildInOrder(child: TrackNode): Result {
const insertPoint = this._children.find(
@@ -339,9 +385,10 @@
}
/**
- * Add a new child node at the start of the list of children.
+ * Adds a new child node at the end of the list of children.
*
* @param child The new child node to add.
+ * @returns A `Result` indicating success or failure.
*/
addChildLast(child: TrackNode): Result {
const result = this.adopt(child);
@@ -351,9 +398,10 @@
}
/**
- * Add a new child node at the end of the list of children.
+ * Adds a new child node at the start of the list of children.
*
* @param child The child node to add.
+ * @returns A `Result` indicating success or failure.
*/
addChildFirst(child: TrackNode): Result {
const result = this.adopt(child);
@@ -363,11 +411,12 @@
}
/**
- * Add a new child node before an existing child node.
+ * Adds a new child node before an existing child node.
*
* @param child The child node to add.
* @param referenceNode An existing child node. The new node will be added
- * before this node.
+ * before this node.
+ * @returns A `Result` indicating success or failure.
*/
addChildBefore(child: TrackNode, referenceNode: TrackNode): Result {
// Nodes are the same, nothing to do.
@@ -385,11 +434,12 @@
}
/**
- * Add a new child node after an existing child node.
+ * Adds a new child node after an existing child node.
*
* @param child The child node to add.
* @param referenceNode An existing child node. The new node will be added
- * after this node.
+ * after this node.
+ * @returns A `Result` indicating success or failure.
*/
addChildAfter(child: TrackNode, referenceNode: TrackNode): Result {
// Nodes are the same, nothing to do.
@@ -407,7 +457,7 @@
}
/**
- * Remove a child node from this node.
+ * Removes a child node from this node.
*
* @param child The child node to remove.
*/
@@ -419,9 +469,9 @@
}
/**
- * The flattened list of all descendent nodes in depth first order.
+ * The flattened list of all descendent nodes in depth-first order.
*
- * Use flatTracksUnordered if you don't care about track order, as it's more
+ * Use `flatTracks` if you don't care about track order, as it's more
* efficient.
*/
get flatTracksOrdered(): ReadonlyArray<TrackNode> {
@@ -445,7 +495,7 @@
}
/**
- * Remove all children from this node.
+ * Removes all children from this node.
*/
clear(): void {
this._children = [];
@@ -453,24 +503,24 @@
}
/**
- * Get a track node by its id.
+ * Gets a track node by its ID.
*
- * Node: This is an O(1) operation.
+ * Note: This is an O(1) operation.
*
- * @param id The id of the node we want to find.
- * @returns The node or undefined if no such node exists.
+ * @param id The ID of the node we want to find.
+ * @returns The node or `undefined` if no such node exists.
*/
getTrackById(id: string): TrackNode | undefined {
return this.tracksById.get(id);
}
/**
- * Get a track node via its URI.
+ * Gets a track node via its URI.
*
- * Node: This is an O(1) operation.
+ * Note: This is an O(1) operation.
*
- * @param uri The uri of the track to find.
- * @returns The node or undefined if no such node exists with this URI.
+ * @param uri The URI of the track to find.
+ * @returns The node or `undefined` if no such node exists with this URI.
*/
getTrackByUri(uri: string): TrackNode | undefined {
return this.tracksByUri.get(uri);
@@ -479,8 +529,8 @@
/**
* Creates a copy of this node with a new ID.
*
- * @param deep - If true, children are copied too.
- * @returns - A copy of this node.
+ * @param deep If `true`, children are copied too.
+ * @returns A copy of this node.
*/
clone(deep = false): TrackNode {
const cloned = new TrackNode({...this, id: undefined});
@@ -552,14 +602,31 @@
* Defines a workspace containing a track tree and a pinned area.
*/
export class Workspace {
+ /**
+ * The human-readable title of the workspace.
+ */
public title = '<untitled-workspace>';
+ /**
+ * The unique ID of the workspace.
+ */
public readonly id: string;
+ /**
+ * Whether the workspace is user-editable.
+ */
public userEditable: boolean = true;
- // Dummy node to contain the pinned tracks
+ /**
+ * A dummy node to contain the pinned tracks.
+ */
public readonly pinnedTracksNode = new TrackNode();
+ /**
+ * The root node for the main track tree.
+ */
public readonly tracks = new TrackNode();
+ /**
+ * A read-only array of pinned tracks in this workspace.
+ */
get pinnedTracks(): ReadonlyArray<TrackNode> {
return this.pinnedTracksNode.children;
}
@@ -575,7 +642,7 @@
}
/**
- * Reset the entire workspace including the pinned tracks.
+ * Resets the entire workspace including the pinned tracks.
*/
clear(): void {
this.pinnedTracksNode.clear();
@@ -584,6 +651,7 @@
/**
* Adds a track node to this workspace's pinned area.
+ * @param track The track to pin.
*/
pinTrack(track: TrackNode): void {
// Make a lightweight clone of this track - just the uri and the title.
@@ -597,6 +665,7 @@
/**
* Removes a track node from this workspace's pinned area.
+ * @param track The track to unpin.
*/
unpinTrack(track: TrackNode): void {
const foundNode = this.pinnedTracksNode.children.find(
@@ -608,31 +677,33 @@
}
/**
- * Check if this workspace has a pinned track with the same URI as |track|.
+ * Checks if this workspace has a pinned track with the same URI as `track`.
+ * @param track The track to check.
+ * @returns `true` if a matching pinned track is found, `false` otherwise.
*/
hasPinnedTrack(track: TrackNode): boolean {
return this.pinnedTracksNode.flatTracks.some((p) => p.uri === track.uri);
}
/**
- * Get a track node via its URI.
+ * Gets a track node via its URI.
*
- * Node: This is an O(1) operation.
+ * Note: This is an O(1) operation.
*
- * @param uri The uri of the track to find.
- * @returns The node or undefined if no such node exists with this URI.
+ * @param uri The URI of the track to find.
+ * @returns The node or `undefined` if no such node exists with this URI.
*/
getTrackByUri(uri: string): TrackNode | undefined {
return this.tracks.flatTracks.find((t) => t.uri === uri);
}
/**
- * Get a track node by its id.
+ * Gets a track node by its ID.
*
- * Node: This is an O(1) operation.
+ * Note: This is an O(1) operation.
*
- * @param id The id of the node we want to find.
- * @returns The node or undefined if no such node exists.
+ * @param id The ID of the node we want to find.
+ * @returns The node or `undefined` if no such node exists.
*/
getTrackById(id: string): TrackNode | undefined {
return (
@@ -648,61 +719,66 @@
}
/**
- * Inserts a new child node considering it's sortOrder.
+ * Inserts a new child node considering its `sortOrder`.
*
- * The child will be added before the first child whose |sortOrder| is greater
+ * The child will be added before the first child whose `sortOrder` is greater
* than the child node's sort order, or at the end if one does not exist. If
- * |sortOrder| is omitted on either node in the comparison it is assumed to be
+ * `sortOrder` is omitted on either node in the comparison it is assumed to be
* 0.
*
- * @param child - The child node to add.
+ * @param child The child node to add.
+ * @returns A `Result` indicating success or failure.
*/
addChildInOrder(child: TrackNode): Result {
return this.tracks.addChildInOrder(child);
}
/**
- * Add a new child node at the start of the list of children.
+ * Adds a new child node at the end of the list of children.
*
* @param child The new child node to add.
+ * @returns A `Result` indicating success or failure.
*/
addChildLast(child: TrackNode): Result {
return this.tracks.addChildLast(child);
}
/**
- * Add a new child node at the end of the list of children.
+ * Adds a new child node at the start of the list of children.
*
* @param child The child node to add.
+ * @returns A `Result` indicating success or failure.
*/
addChildFirst(child: TrackNode): Result {
return this.tracks.addChildFirst(child);
}
/**
- * Add a new child node before an existing child node.
+ * Adds a new child node before an existing child node.
*
* @param child The child node to add.
* @param referenceNode An existing child node. The new node will be added
- * before this node.
+ * before this node.
+ * @returns A `Result` indicating success or failure.
*/
addChildBefore(child: TrackNode, referenceNode: TrackNode): Result {
return this.tracks.addChildBefore(child, referenceNode);
}
/**
- * Add a new child node after an existing child node.
+ * Adds a new child node after an existing child node.
*
* @param child The child node to add.
* @param referenceNode An existing child node. The new node will be added
- * after this node.
+ * after this node.
+ * @returns A `Result` indicating success or failure.
*/
addChildAfter(child: TrackNode, referenceNode: TrackNode): Result {
return this.tracks.addChildAfter(child, referenceNode);
}
/**
- * Remove a child node from this node.
+ * Removes a child node from this node.
*
* @param child The child node to remove.
*/
@@ -711,19 +787,19 @@
}
/**
- * The flattened list of all descendent nodes in depth first order.
+ * The flattened list of all descendent nodes in depth-first order.
*
- * Use flatTracksUnordered if you don't care about track order, as it's more
+ * Use `flatTracks` if you don't care about track order, as it's more
* efficient.
*/
- get flatTracksOrdered() {
+ get flatTracksOrdered(): ReadonlyArray<TrackNode> {
return this.tracks.flatTracksOrdered;
}
/**
* The flattened list of all descendent nodes in no particular order.
*/
- get flatTracks() {
+ get flatTracks(): ReadonlyArray<TrackNode> {
return this.tracks.flatTracks;
}
}