ui: move "Open in default workspace" button into the selection tab Render the button once in CurrentSelectionTab, the single host through which every selection's details panel is rendered, instead of adding it to individual panels. It is merged into the details panel's DetailsShell for track_event and track selections whose track is in a non-default workspace but also exists in the default one. Change-Id: I899ddfd8b9151dea07d20c461263bd69f3336b55
diff --git a/ui/src/components/details/thread_slice_details_tab.ts b/ui/src/components/details/thread_slice_details_tab.ts index b797ff7..d29ecba 100644 --- a/ui/src/components/details/thread_slice_details_tab.ts +++ b/ui/src/components/details/thread_slice_details_tab.ts
@@ -285,10 +285,7 @@ { title: 'Slice', description: slice.name, - buttons: [ - this.renderOpenInDefaultWorkspaceButton(), - this.renderContextButton(slice), - ], + buttons: this.renderContextButton(slice), }, m( GridLayout, @@ -552,27 +549,6 @@ ); } - // Shown only when the selected slice is in a non-default workspace and the same - // track also exists in the default workspace: switches to the default - // workspace and scrolls to the slice there. - private renderOpenInDefaultWorkspaceButton(): m.Children { - const {workspaces, selection} = this.trace; - if (workspaces.currentWorkspace === workspaces.defaultWorkspace) return; - const sel = selection.selection; - if (sel.kind !== 'track_event') return; - if (workspaces.defaultWorkspace.getTrackByUri(sel.trackUri) === undefined) { - return; - } - return m(Button, { - label: 'Open in default workspace', - icon: Icons.GoTo, - onclick: () => { - workspaces.switchWorkspace(workspaces.defaultWorkspace); - selection.scrollToSelection('focus'); - }, - }); - } - private renderContextButton(sliceInfo: SliceDetails): m.Children { const contextMenuItems = getSliceContextMenuItems(sliceInfo); if (contextMenuItems.length > 0) {
diff --git a/ui/src/core_plugins/dev.perfetto.Timeline/current_selection_tab.ts b/ui/src/core_plugins/dev.perfetto.Timeline/current_selection_tab.ts index acd976a..6c4a485 100644 --- a/ui/src/core_plugins/dev.perfetto.Timeline/current_selection_tab.ts +++ b/ui/src/core_plugins/dev.perfetto.Timeline/current_selection_tab.ts
@@ -26,6 +26,7 @@ TrackSelection, } from '../../public/selection'; import {assertUnreachable} from '../../base/assert'; +import {Icons} from '../../base/semantic_icons'; import {Button, ButtonBar} from '../../widgets/button'; import {NoteEditor} from './note_editor'; import {Gate} from '../../base/mithril_utils'; @@ -90,7 +91,7 @@ if (detailsPanel) { return { isLoading: detailsPanel.isLoading, - content: detailsPanel.render(), + content: this.withWorkspaceButton(trace, detailsPanel.render()), }; } else { return { @@ -151,6 +152,50 @@ }; } + // A button, shown for any selection whose track lives in a non-default + // workspace but also exists in the default one, that jumps back to the default + // workspace and scrolls to the selection there. + private renderOpenInDefaultWorkspaceButton(trace: TraceImpl): m.Children { + const {currentWorkspace, defaultWorkspace, workspaces, selection} = trace; + if (currentWorkspace === defaultWorkspace) return; + const sel = selection.selection; + const trackUri = + sel.kind === 'track_event' || sel.kind === 'track' + ? sel.trackUri + : undefined; + if (trackUri === undefined) return; + if (defaultWorkspace.getTrackByUri(trackUri) === undefined) return; + return m(Button, { + label: 'Open in default workspace', + icon: Icons.GoTo, + onclick: () => { + workspaces.switchWorkspace(defaultWorkspace); + selection.scrollToSelection('focus'); + }, + }); + } + + // Details panels render their own DetailsShell, so merge the button into its + // header buttons rather than adding it to every panel individually. + private withWorkspaceButton( + trace: TraceImpl, + content: m.Children, + ): m.Children { + const button = this.renderOpenInDefaultWorkspaceButton(trace); + if (button === undefined) return content; + if ( + content == null || + typeof content !== 'object' || + Array.isArray(content) || + ((content as m.Vnode).tag as unknown) !== DetailsShell + ) { + return content; + } + const shell = content as m.Vnode<{buttons?: m.Children}>; + shell.attrs.buttons = [shell.attrs.buttons, button]; + return shell; + } + private renderNoteSelection(trace: TraceImpl, selection: NoteSelection) { return { isLoading: false, @@ -163,7 +208,11 @@ if (track) { return m( DetailsShell, - {title: 'Track', description: track.uri}, + { + title: 'Track', + description: track.uri, + buttons: this.renderOpenInDefaultWorkspaceButton(trace), + }, m( GridLayout, m(