Skip to content

Commit

Permalink
[ui] Add "duplicate" button to SQL table viewer
Browse files Browse the repository at this point in the history
It's often useful to be able to duplicate a table to start two
independent investigations.

Change-Id: Ic5670a04462f2642cb3f70e87e334ef32b4ef2e7
  • Loading branch information
Alexander Timin committed Sep 30, 2024
1 parent 5063b37 commit 4913d62
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 24 deletions.
1 change: 1 addition & 0 deletions ui/src/base/semantic_icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class Icons {
static readonly UpdateSelection = 'call_made'; // Could be 'open_in_new'
static readonly ChangeViewport = 'query_stats'; // Could be 'search'
static readonly ContextMenu = 'arrow_drop_down'; // Could be 'more_vert'
static readonly Menu = 'menu';
static readonly Copy = 'content_copy';
static readonly Delete = 'delete';
static readonly SortedAsc = 'arrow_upward';
Expand Down
57 changes: 39 additions & 18 deletions ui/src/frontend/sql_table_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,40 @@ import {SqlTableState} from './widgets/sql/table/state';
import {SqlTable} from './widgets/sql/table/table';
import {SqlTableDescription} from './widgets/sql/table/table_description';
import {Trace} from '../public/trace';
import {MenuItem, PopupMenu2} from '../widgets/menu';

export interface SqlTableTabConfig {
export interface AddSqlTableTabParams {
table: SqlTableDescription;
filters?: Filter[];
imports?: string[];
}

export function addSqlTableTabImpl(
trace: Trace,
config: SqlTableTabConfig,
config: AddSqlTableTabParams,
): void {
addSqlTableTabWithState(
new SqlTableState(trace, config.table, {
filters: config.filters,
imports: config.imports,
}),
);
}

function addSqlTableTabWithState(state: SqlTableState) {
const queryResultsTab = new SqlTableTab({
config,
trace,
config: {state},
trace: state.trace,
uuid: uuidv4(),
});

addBottomTab(queryResultsTab, 'sqlTable');
}

interface SqlTableTabConfig {
state: SqlTableState;
}

class SqlTableTab extends BottomTab<SqlTableTabConfig> {
static readonly kind = 'dev.perfetto.SqlTableTab';

Expand All @@ -56,14 +70,7 @@ class SqlTableTab extends BottomTab<SqlTableTabConfig> {
constructor(args: NewBottomTabArgs<SqlTableTabConfig>) {
super(args);

this.state = new SqlTableState(this.trace, this.config.table, {
filters: this.config.filters,
imports: this.config.imports,
});
}

static create(args: NewBottomTabArgs<SqlTableTabConfig>): SqlTableTab {
return new SqlTableTab(args);
this.state = args.config.state;
}

viewTab() {
Expand Down Expand Up @@ -111,11 +118,25 @@ class SqlTableTab extends BottomTab<SqlTableTabConfig> {
buttons: [
...navigation,
addDebugTrack,
m(Button, {
label: 'Copy SQL query',
onclick: () =>
copyToClipboard(this.state.getNonPaginatedSQLQuery()),
}),
m(
PopupMenu2,
{
trigger: m(Button, {
icon: Icons.Menu,
}),
},
m(MenuItem, {
label: 'Duplicate',
icon: 'tab_duplicate',
onclick: () => addSqlTableTabWithState(this.state.clone()),
}),
m(MenuItem, {
label: 'Copy SQL query',
icon: Icons.Copy,
onclick: () =>
copyToClipboard(this.state.getNonPaginatedSQLQuery()),
}),
),
],
},
m(SqlTable, {
Expand All @@ -131,7 +152,7 @@ class SqlTableTab extends BottomTab<SqlTableTabConfig> {
}

private getDisplayName(): string {
return this.config.table.displayName ?? this.config.table.name;
return this.state.config.displayName ?? this.state.config.name;
}

isLoading(): boolean {
Expand Down
12 changes: 9 additions & 3 deletions ui/src/frontend/sql_table_tab_interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
// limitations under the License.

import {Trace} from '../public/trace';
import {type SqlTableTabConfig} from './sql_table_tab';
import {type AddSqlTableTabParams} from './sql_table_tab';

type AddSqlTableTabFunction = (trace: Trace, config: SqlTableTabConfig) => void;
type AddSqlTableTabFunction = (
trace: Trace,
config: AddSqlTableTabParams,
) => void;

// TODO(primiano): this injection is to break the circular dependency cycle that
// there is between DebugSliceTrack and SqlTableTab. The problem is:
Expand All @@ -26,7 +29,10 @@ type AddSqlTableTabFunction = (trace: Trace, config: SqlTableTabConfig) => void;

let addSqlTableTabFunction: AddSqlTableTabFunction;

export function addSqlTableTab(trace: Trace, config: SqlTableTabConfig): void {
export function addSqlTableTab(
trace: Trace,
config: AddSqlTableTabParams,
): void {
addSqlTableTabFunction(trace, config);
}

Expand Down
18 changes: 15 additions & 3 deletions ui/src/frontend/widgets/sql/table/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,15 @@ export class SqlTableState {
constructor(
readonly trace: Trace,
readonly config: SqlTableDescription,
args?: {
private readonly args?: {
initialColumns?: TableColumn[];
additionalColumns?: TableColumn[];
imports?: string[];
filters?: Filter[];
orderBy?: ColumnOrderClause[];
orderBy?: {
column: TableColumn;
direction: SortDirection;
}[];
},
) {
this.additionalImports = args?.imports || [];
Expand Down Expand Up @@ -126,12 +129,21 @@ export class SqlTableState {
}
}

this.orderBy = [];
this.orderBy = args?.orderBy ?? [];

this.request = this.buildRequest();
this.reload();
}

clone(): SqlTableState {
return new SqlTableState(this.trace, this.config, {
initialColumns: this.columns,
imports: this.args?.imports,
filters: this.filters,
orderBy: this.orderBy,
});
}

private getSQLImports() {
const tableImports = this.config.imports || [];
return [...tableImports, ...this.additionalImports]
Expand Down

0 comments on commit 4913d62

Please sign in to comment.