Skip to content

Commit

Permalink
Basic Plugin Support for selecting tracks and track groups (#114)
Browse files Browse the repository at this point in the history
* Basic Plugin Support for selecting tracks and track groups

* Rename addTrackToAreaSelection totoggleTrackInAreaSelection

* Fix UI to show selected state

* Shift modifier functionality for tracks under the same group

* Selecting track group no longer collapses it
  • Loading branch information
ALevansSamsung authored Jul 16, 2024
1 parent defd00c commit 8b257e2
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 29 deletions.
30 changes: 11 additions & 19 deletions ui/src/assets/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ $bottom-tab-padding: 10px;
}

&.selected {
background-color: #ebeef9;
background-color: var(--track-highlight-background);
}

&.alternating-thread-track {
Expand Down Expand Up @@ -456,8 +456,7 @@ $bottom-tab-padding: 10px;
opacity: 1;
}
&.flash {
color:var(--main-background-color);
background-color: var(--track-highlight-background) ;
color: yellow;
}
}
}
Expand Down Expand Up @@ -727,7 +726,6 @@ button.query-ctrl {
.shell {
border-right: 1px solid var(--main-foreground-color);
background-color: var(--collapsed-background);
overflow: hidden;
}
.track-button {
color: rgb(60, 86, 136);
Expand All @@ -737,9 +735,6 @@ button.query-ctrl {
background-color: var(--collapsed-background);
color: var(--main-foreground-color);
font-weight: bold;
.shell {
overflow: hidden;
}
span.chip {
color: #121212;
}
Expand All @@ -753,7 +748,10 @@ button.query-ctrl {
line-height: 1;
width: var(--track-shell-width);
transition: background-color 0.4s;

overflow: hidden;
&.selected {
background-color: var(--track-highlight-background);
}
.track-title {
user-select: text;
}
Expand Down Expand Up @@ -790,22 +788,16 @@ button.query-ctrl {
position: relative;
top: -5px;
grid-area: fold-button;
&:hover{
cursor: pointer;
color: hsl(45, 100%, 48%);
}
}
.track-button {
font-size: 20px;
}
&:hover {
cursor: pointer;
.fold-button {
color: hsl(45, 100%, 48%);
}
}
&.flash {
color:var(--main-background-color);
background-color: var(--track-highlight-background);
}
&.selected {
background-color: #ebeef9;
color: yellow;
}
&.drag {
background-color: #eee;
Expand Down
41 changes: 40 additions & 1 deletion ui/src/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import {
import {TPDuration, TPTime} from './time';
import {STR} from './query_result';
import {remove} from '../base/array_utils';
import {pluginManager} from './plugins';

export const DEBUG_SLICE_TRACK_KIND = 'DebugSliceTrack';

Expand Down Expand Up @@ -1244,7 +1245,7 @@ export const StateActions = {
};
},

toggleTrackSelection(
toggleTrackInAreaSelection(
state: StateDraft, args: {id: string, isTrackGroup: boolean}) {
const selection = state.currentSelection;
if (selection === null || selection.kind !== 'AREA') return;
Expand Down Expand Up @@ -1511,6 +1512,44 @@ export const StateActions = {
args: {filteredTracks: AddTrackLikeArgs[]}) {
state.filteredTracks = [...args.filteredTracks];
},

clearTrackAndGroupSelection(
state: StateDraft,
_: {},
) {
state.selectedTrackIds.clear();
state.selectedTrackGroupIds.clear();
},

toggleTrackSelection(
state: StateDraft,
args: {trackId: string},
) {
if (state.selectedTrackIds.has(args.trackId)) {
state.selectedTrackIds.delete(args.trackId);
} else {
state.selectedTrackIds.add(args.trackId);
state.lastSelectedTrackId = args.trackId;
}
pluginManager.onTrackSelectionChange(
Array.from(state.selectedTrackIds),
Array.from(state.selectedTrackGroupIds));
},

toggleTrackGroupSelection(
state: StateDraft,
args: {trackGroupId: string},
) {
if (state.selectedTrackGroupIds.has(args.trackGroupId)) {
state.selectedTrackGroupIds.delete(args.trackGroupId);
} else {
state.lastSelectedTrackId = undefined;
state.selectedTrackGroupIds.add(args.trackGroupId);
}
pluginManager.onTrackSelectionChange(
Array.from(state.selectedTrackIds),
Array.from(state.selectedTrackGroupIds));
},
};

// When we are on the frontend side, we don't really want to execute the
Expand Down
2 changes: 2 additions & 0 deletions ui/src/common/empty_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,5 +169,7 @@ export function createEmptyState(): State {
},

filteredTracks: [],
selectedTrackGroupIds: new Set<string>(),
selectedTrackIds: new Set<string>(),
};
}
4 changes: 4 additions & 0 deletions ui/src/common/plugin_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ export interface PluginContext {
onDetailsPanelSelectionChange: (newSelection?: Selection) => void): void;
// Register a custom button on the timeline
registerCustomButton(button: CustomButtonArgs): void;

registerOnTrackSelectionChange(
onTrackSelectionChange:
(trackIds: string[], trackGroupIds: string[]) => void): void;
}

export interface PluginInfo {
Expand Down
17 changes: 17 additions & 0 deletions ui/src/common/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {CustomButton, CustomButtonArgs, customButtonRegistry} from '../frontend/
export class PluginContextImpl implements PluginContext {
readonly pluginId: string;
onDetailsPanelSelectionChange?: (newSelection?: Selection) => void;
onTrackSelectionChange?:
(trackIDs: string[], trackGroupIds: string[]) => void;
private trackProviders: TrackProvider[];

constructor(pluginId: string) {
Expand Down Expand Up @@ -67,6 +69,12 @@ export class PluginContextImpl implements PluginContext {
this.onDetailsPanelSelectionChange = onDetailsPanelSelectionChange;
}

registerOnTrackSelectionChange(
onTrackSelectionChange:
(trackIds: string[], trackGroupIds: string[]) => void) {
this.onTrackSelectionChange = onTrackSelectionChange;
}

registerCustomButton(button: CustomButtonArgs): void {
customButtonRegistry.register(new CustomButton(button));
}
Expand Down Expand Up @@ -148,6 +156,15 @@ export class PluginManager {
pluginContext.onDetailsPanelSelectionChange(newSelection);
}
}

onTrackSelectionChange(trackIds?: string[], trackGroupIds?: string[]) {
this.contexts.forEach((context)=>{
if (context === undefined) return;
if (context.onTrackSelectionChange) {
context.onTrackSelectionChange(trackIds || [], trackGroupIds ||[]);
}
});
}
}

// TODO(hjd): Sort out the story for global singletons like these:
Expand Down
5 changes: 5 additions & 0 deletions ui/src/common/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ export interface LogSelection {
trackId: string;
}


export type Selection =
(NoteSelection|SliceSelection|CounterSelection|HeapProfileSelection|
CpuProfileSampleSelection|ChromeSliceSelection|ThreadStateSelection|
Expand Down Expand Up @@ -630,6 +631,10 @@ export interface State {

// Omnibox info.
omniboxState: OmniboxState;

selectedTrackIds: Set<string>;
selectedTrackGroupIds: Set<string>;
lastSelectedTrackId?: string;
}

export const defaultTraceTime = {
Expand Down
19 changes: 13 additions & 6 deletions ui/src/frontend/track_group_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,12 @@ export class TrackGroupPanel extends Panel<Attrs> {
m(`.shell[draggable=true]`,
{
onclick: (e: MouseEvent) => {
globals.dispatch(Actions.toggleTrackGroupCollapsed({
trackGroupId: attrs.trackGroupId,
})),
globals.dispatch(
Actions.toggleTrackGroupSelection(
{trackGroupId: attrs.trackGroupId}));
e.stopPropagation();
},
class: `${highlightClass} ${dragClass} ${dropClass}`,
class: `${highlightClass} ${dragClass} ${dropClass} ${globals.state.selectedTrackGroupIds.has(attrs.trackGroupId)? 'selected': ''}`,
ondragstart: this.ondragstart.bind(this),
ondragenter: (e: DragEvent)=>{
e.preventDefault();
Expand All @@ -209,7 +209,14 @@ export class TrackGroupPanel extends Panel<Attrs> {
},

m('.fold-button',
{...marginStyling},
{...marginStyling,
onclick: (e: MouseEvent) => {
globals.dispatch(Actions.toggleTrackGroupCollapsed({
trackGroupId: attrs.trackGroupId,
}));
e.stopPropagation();
},
},
m('i.material-icons',
this.trackGroupState.collapsed ? CHEVRON_RIGHT : EXPAND_DOWN)),
m('h1.track-title',
Expand All @@ -227,7 +234,7 @@ export class TrackGroupPanel extends Panel<Attrs> {
m('i.material-icons.track-button',
{
onclick: (e: MouseEvent) => {
globals.dispatch(Actions.toggleTrackSelection(
globals.dispatch(Actions.toggleTrackInAreaSelection(
{id: attrs.trackGroupId, isTrackGroup: true}));
e.stopPropagation();
},
Expand Down
53 changes: 50 additions & 3 deletions ui/src/frontend/track_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import {hex} from 'color-convert';
import m from 'mithril';

import {Actions} from '../common/actions';
import {Actions, DeferredAction} from '../common/actions';
import {TrackGroupState, TrackState} from '../common/state';
import {TPTime} from '../common/time';

Expand Down Expand Up @@ -182,7 +182,54 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {
return m(
`.track-shell[draggable=true]`,
{
class: `${highlightClass} ${dragClass} ${dropClass}`,
class: `${highlightClass} ${dragClass} ${dropClass} ${globals.state.selectedTrackIds.has(attrs.trackState.id)? 'selected': ''}`,
onclick: (e: MouseEvent)=>{
if (!e.ctrlKey) {
globals.dispatch(
Actions.clearTrackAndGroupSelection({}));
}
if (e.shiftKey && globals.state.lastSelectedTrackId) {
// Check if parent group of last selected is same as current
// If yes, turn all tracks in range to on
const lastSelectedTrack =
globals.state.tracks[globals.state.lastSelectedTrackId];
if (lastSelectedTrack &&
lastSelectedTrack.trackGroup &&
lastSelectedTrack.trackGroup ===
attrs.trackState.trackGroup) {
const parentGroup =
globals.state.trackGroups[lastSelectedTrack.trackGroup];
if (parentGroup) {
const firstTrackIndex = parentGroup.sortOrder.findIndex(
(value)=>value=== lastSelectedTrack.id);
const secondTrackIndex = parentGroup.sortOrder.findIndex(
(value)=>value=== attrs.trackState.id);
let idsToSelect: string[] = [];
if (firstTrackIndex<secondTrackIndex) {
idsToSelect = parentGroup.sortOrder.slice(
firstTrackIndex,
secondTrackIndex+1,
);
} else {
idsToSelect = parentGroup.sortOrder.slice(
secondTrackIndex,
firstTrackIndex+1,
);
}
const actions: DeferredAction[] = [];
idsToSelect.forEach((trackId)=>{
if (!globals.state.selectedTrackIds.has(trackId)) {
actions.push(Actions.toggleTrackSelection({trackId}));
}
});
globals.dispatchMultiple(actions);
return;
}
}
}
globals.dispatch(
Actions.toggleTrackSelection({trackId: attrs.trackState.id}));
},
ondragstart: this.ondragstart.bind(this),
ondragenter: (e: DragEvent)=>{
e.preventDefault();
Expand Down Expand Up @@ -240,7 +287,7 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {
globals.state.currentSelection.kind === 'AREA' ?
m(TrackButton, {
action: (e: PerfettoMouseEvent) => {
globals.dispatch(Actions.toggleTrackSelection(
globals.dispatch(Actions.toggleTrackInAreaSelection(
{id: attrs.trackState.id, isTrackGroup: false}));
e.stopPropagation();
},
Expand Down

0 comments on commit 8b257e2

Please sign in to comment.