From 49275b0aad3096f86c5ba0100a6a8c6f117891fd Mon Sep 17 00:00:00 2001 From: Lydia Tse Date: Wed, 4 Dec 2024 17:26:08 +0000 Subject: [PATCH] ui: explore page persistent state/charts. This change prevents users from having to recreate charts/reselect tables when navigating to/from the explore page. Bug: b/380882773 Change-Id: I2a3e23414f952854520a0090fac523cd45ed5861 --- .../dev.perfetto.ExplorePage/explore_page.ts | 45 +++++++++---------- .../plugins/dev.perfetto.ExplorePage/index.ts | 18 +++++++- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/ui/src/plugins/dev.perfetto.ExplorePage/explore_page.ts b/ui/src/plugins/dev.perfetto.ExplorePage/explore_page.ts index 26b4bd89b2..ff2c1b0e8e 100644 --- a/ui/src/plugins/dev.perfetto.ExplorePage/explore_page.ts +++ b/ui/src/plugins/dev.perfetto.ExplorePage/explore_page.ts @@ -45,7 +45,7 @@ import { CollapsiblePanelVisibility, } from '../../components/widgets/collapsible_panel'; -interface ExploreTableState { +export interface ExploreTableState { sqlTableState?: SqlTableState; selectedTable?: ExplorableTable; } @@ -56,20 +56,18 @@ interface ExplorableTable { columns: (TableColumn | TableColumnSet)[]; } -export class ExplorePage implements m.ClassComponent { - private readonly state: ExploreTableState; - private readonly charts: Chart[]; - private visibility: CollapsiblePanelVisibility; +interface ExplorePageAttrs extends PageWithTraceAttrs { + readonly state: ExploreTableState; + readonly charts: Chart[]; +} - constructor() { - this.charts = []; - this.state = {}; - this.visibility = CollapsiblePanelVisibility.VISIBLE; - } +export class ExplorePage implements m.ClassComponent { + private visibility = CollapsiblePanelVisibility.VISIBLE; // Show menu with standard library tables private renderSelectableTablesMenuItems( trace: Trace, + state: ExploreTableState, ): m.Vnode[] { // TODO (lydiatse@): The following is purely for prototyping and // should be derived from the actual stdlib itself rather than @@ -118,16 +116,13 @@ export class ExplorePage implements m.ClassComponent { return m(MenuItem, { label: table.name, onclick: () => { - if ( - this.state.selectedTable && - table.name === this.state.selectedTable.name - ) { + if (state.selectedTable && table.name === state.selectedTable.name) { return; } - this.state.selectedTable = table; + state.selectedTable = table; - this.state.sqlTableState = new SqlTableState( + state.sqlTableState = new SqlTableState( trace, { name: table.name, @@ -140,8 +135,8 @@ export class ExplorePage implements m.ClassComponent { }); } - private renderSqlTable() { - const sqlTableState = this.state.sqlTableState; + private renderSqlTable(state: ExploreTableState, charts: Chart[]) { + const sqlTableState = state.sqlTableState; if (sqlTableState === undefined) return; @@ -181,27 +176,29 @@ export class ExplorePage implements m.ClassComponent { sqlTableState, ), chartOptions: [ChartOption.HISTOGRAM], - addChart: (chart) => this.charts.push(chart), + addChart: (chart) => charts.push(chart), }), }), ); } - view({attrs}: m.CVnode) { + view({attrs}: m.CVnode) { + const {trace, state, charts} = attrs; + return m( '.page.explore-page', m( '.chart-container', - m(Menu, this.renderSelectableTablesMenuItems(attrs.trace)), - this.charts.map((chart) => renderChartComponent(chart)), + m(Menu, this.renderSelectableTablesMenuItems(trace, state)), + charts.map((chart) => renderChartComponent(chart)), ), - this.state.selectedTable && + state.selectedTable && m(CollapsiblePanel, { visibility: this.visibility, setVisibility: (visibility) => { this.visibility = visibility; }, - tabs: [this.renderSqlTable()], + tabs: [this.renderSqlTable(state, charts)], }), ); } diff --git a/ui/src/plugins/dev.perfetto.ExplorePage/index.ts b/ui/src/plugins/dev.perfetto.ExplorePage/index.ts index 5c18701a0c..1abc34e013 100644 --- a/ui/src/plugins/dev.perfetto.ExplorePage/index.ts +++ b/ui/src/plugins/dev.perfetto.ExplorePage/index.ts @@ -12,15 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. +import m from 'mithril'; import {PerfettoPlugin} from '../../public/plugin'; import {Trace} from '../../public/trace'; -import {ExplorePage} from './explore_page'; +import {ExplorePage, ExploreTableState} from './explore_page'; +import {Chart} from '../../components/widgets/charts/chart'; export default class implements PerfettoPlugin { static readonly id = 'dev.perfetto.ExplorePage'; + // The following allows us to have persistent + // state/charts for the lifecycle of a single + // trace. + private readonly state: ExploreTableState = {}; + private readonly charts: Chart[] = []; + async onTraceLoad(trace: Trace): Promise { - trace.pages.registerPage({route: '/explore', page: ExplorePage}); + trace.pages.registerPage({ + route: '/explore', + page: { + view: ({attrs}) => + m(ExplorePage, {...attrs, state: this.state, charts: this.charts}), + }, + }); trace.sidebar.addMenuItem({ section: 'current_trace', text: 'Explore',