Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions ui/src/assets/topbar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@
}
}

// Zen mode: hide topbar by default, show when it has focus or when explicitly shown
&.pf-zen-mode {
display: none;

// Show topbar when explicitly marked to show (has text, pending focus, or non-search mode)
&.pf-zen-mode--show {
display: flex;
}

// Always show topbar when it has focus (user is interacting with omnibox)
&:focus-within {
display: flex;
}
}

&__error-box {
position: absolute;
right: 10px;
Expand Down
11 changes: 11 additions & 0 deletions ui/src/core/app_impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export class AppImpl implements App {
readonly startupCommandsSetting: Setting<CommandInvocation[]>;
readonly enforceStartupCommandAllowlistSetting: Setting<boolean>;
private _isInternalUser?: boolean;
private _zenModeEnabled = false;

// This constructor is invoked only once, when frontend/index.ts invokes
// AppMainImpl.initialize().
Expand Down Expand Up @@ -197,6 +198,16 @@ export class AppImpl implements App {
};
}

get zenModeEnabled(): boolean {
return this._zenModeEnabled;
}

toggleZenMode(): void {
this._zenModeEnabled = !this._zenModeEnabled;
// Zen mode controls sidebar existence
this.sidebar.toggleEnabled();
}

openTraceFromFile(file: File) {
return this.openTrace({type: 'FILE', file});
}
Expand Down
20 changes: 17 additions & 3 deletions ui/src/core/sidebar_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ export type SidebarMenuItemInternal = SidebarMenuItem & {
};

export class SidebarManagerImpl implements SidebarManager {
readonly enabled: boolean;
private _enabled: boolean;
private _visible: boolean;
private lastId = 0;

readonly menuItems = new Registry<SidebarMenuItemInternal>((m) => m.id);

constructor(args: {disabled?: boolean; hidden?: boolean}) {
this.enabled = !args.disabled;
this._enabled = !args.disabled;
this._visible = !args.hidden;
}

Expand All @@ -39,12 +39,26 @@ export class SidebarManagerImpl implements SidebarManager {
return this.menuItems.register(itemInt);
}

public get enabled() {
return this._enabled;
}

public get visible() {
return this._visible;
}

public toggleEnabled() {
this._enabled = !this._enabled;
}

public toggleVisibility() {
if (!this.enabled) return;
// When sidebar is disabled, just enable it and make it visible
// (This typically happens when exiting zen mode via sidebar commands)
if (!this._enabled) {
this._enabled = true;
this._visible = true;
return;
}
this._visible = !this._visible;
}
}
8 changes: 8 additions & 0 deletions ui/src/core/trace_impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,14 @@ export class TraceImpl implements Trace, Disposable {
return this.app.isInternalUser;
}

get zenModeEnabled(): boolean {
return this.app.zenModeEnabled;
}

toggleZenMode(): void {
this.app.toggleZenMode();
}

get perfDebugging() {
return this.app.perfDebugging;
}
Expand Down
37 changes: 37 additions & 0 deletions ui/src/core_plugins/dev.perfetto.CoreCommands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,43 @@ export default class CoreCommands implements PerfettoPlugin {
icon: 'folder_open',
});

ctx.commands.registerCommand({
id: 'dev.perfetto.ToggleSidebar',
name: 'Toggle sidebar',
callback: () => {
const app = AppImpl.instance;
// If in zen mode, exit zen mode instead of just toggling sidebar
if (app.zenModeEnabled) {
app.toggleZenMode();
} else {
app.sidebar.toggleEnabled();
}
},
});

ctx.commands.registerCommand({
id: 'dev.perfetto.ToggleSidebarVisibility',
name: 'Toggle sidebar visibility',
callback: () => {
const app = AppImpl.instance;
// If in zen mode, exit zen mode instead of just toggling visibility
if (app.zenModeEnabled) {
app.toggleZenMode();
} else {
app.sidebar.toggleVisibility();
}
},
});

ctx.commands.registerCommand({
id: 'dev.perfetto.ToggleZenMode',
name: 'Toggle zen mode',
defaultHotkey: 'Shift+Z',
callback: () => {
AppImpl.instance.toggleZenMode();
},
});

const OPEN_LEGACY_COMMAND_ID = 'dev.perfetto.OpenTraceInLegacyUi';
ctx.commands.registerCommand({
id: OPEN_LEGACY_COMMAND_ID,
Expand Down
6 changes: 4 additions & 2 deletions ui/src/frontend/omnibox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ export class Omnibox implements m.ClassComponent<OmniboxAttrs> {
}

private renderPromptOmnibox(): m.Children {
const omnibox = AppImpl.instance.omnibox;
const app = AppImpl.instance;
const omnibox = app.omnibox;
const prompt = assertExists(omnibox.pendingPrompt);

let options: OmniboxOption[] | undefined = undefined;
Expand Down Expand Up @@ -120,7 +121,8 @@ export class Omnibox implements m.ClassComponent<OmniboxAttrs> {

private renderCommandOmnibox(): m.Children {
// Fuzzy-filter commands by the filter string.
const {commands, omnibox} = AppImpl.instance;
const app = AppImpl.instance;
const {commands, omnibox} = app;
const filteredCmds = commands.fuzzyFilterCommands(omnibox.text);

// Create an array of commands with attached heuristics from the recent
Expand Down
4 changes: 3 additions & 1 deletion ui/src/frontend/timeline_page/timeline_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ class TimelinePage implements m.ClassComponent<TimelinePageAttrs> {

view({attrs}: m.CVnode<TimelinePageAttrs>) {
const {trace} = attrs;
const zenMode = AppImpl.instance.zenModeEnabled;
const showOverview = OVERVIEW_PANEL_FLAG.get() && !zenMode;
return m(
'.pf-timeline-page',
m(
TabPanel,
{trace},
OVERVIEW_PANEL_FLAG.get() &&
showOverview &&
m(Minimap, {
trace,
className: 'pf-timeline-page__overview',
Expand Down
4 changes: 3 additions & 1 deletion ui/src/frontend/topbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,18 @@ class TraceErrorIcon implements m.ClassComponent<TraceImplAttrs> {

export interface TopbarAttrs {
readonly trace?: TraceImpl;
readonly className?: string;
}

export class Topbar implements m.ClassComponent<TopbarAttrs> {
view({attrs}: m.Vnode<TopbarAttrs>) {
const {trace} = attrs;
const {trace, className} = attrs;
return m(
'.pf-topbar',
{
className: classNames(
!AppImpl.instance.sidebar.visible && 'pf-topbar--hide-sidebar',
className,
),
},
m(Omnibox, {trace}),
Expand Down
24 changes: 21 additions & 3 deletions ui/src/frontend/ui_main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
// limitations under the License.

import m from 'mithril';
import {classNames} from '../base/classnames';
import {AppImpl} from '../core/app_impl';
import {CookieConsent} from '../core/cookie_consent';
import {featureFlags} from '../core/feature_flags';
import {OmniboxMode} from '../core/omnibox_manager';
import {LinearProgress} from '../widgets/linear_progress';
import {maybeRenderFullscreenModalDialog} from '../widgets/modal';
import {initCssConstants} from './css_constants';
Expand Down Expand Up @@ -57,17 +59,33 @@ export class UiMain implements m.ClassComponent {
(trace?.engine.numRequestsPending ?? 0) > 0 ||
taskTracker.hasPendingTasks();

const zenMode = app.zenModeEnabled;
const showStatusBar = showStatusBarFlag.get() && !zenMode;

// In zen mode, topbar visibility is controlled by CSS classes
// Show topbar when: not in search mode, has text, or should focus
const shouldShowTopbarInZenMode =
app.omnibox.mode !== OmniboxMode.Search ||
app.omnibox.text.length > 0 ||
app.omnibox.focusOmniboxNextRender;

return m('main.pf-ui-main', [
m(Sidebar),
m(Topbar, {trace}),
app.sidebar.enabled && m(Sidebar),
m(Topbar, {
trace,
className: classNames(
zenMode && 'pf-zen-mode',
zenMode && shouldShowTopbarInZenMode && 'pf-zen-mode--show',
),
}),
m(LinearProgress, {
className: 'pf-ui-main__loading',
state: isSomethingLoading ? 'indeterminate' : 'none',
}),
m('.pf-ui-main__page-container', app.pages.renderPageForCurrentRoute()),
m(CookieConsent),
maybeRenderFullscreenModalDialog(),
showStatusBarFlag.get() && renderStatusBar(trace),
showStatusBar && renderStatusBar(trace),
app.perfDebugging.renderPerfStats(),
]);
}
Expand Down
10 changes: 10 additions & 0 deletions ui/src/public/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ export interface App {
// certain internal links or expose certain experimental features by default.
readonly isInternalUser: boolean;

// True if zen mode is enabled. Zen mode hides the sidebar, overview,
// and status bar to provide a distraction-free viewing experience.
readonly zenModeEnabled: boolean;

/**
* Toggle zen mode on/off. Zen mode hides the sidebar, overview,
* and status bar to provide a distraction-free viewing experience.
*/
toggleZenMode(): void;

/**
* Navigate to a new page.
*/
Expand Down
19 changes: 16 additions & 3 deletions ui/src/public/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export const SIDEBAR_SECTIONS = {
export type SidebarSections = keyof typeof SIDEBAR_SECTIONS;

export interface SidebarManager {
/**
* Whether the sidebar is enabled (rendered in DOM).
* When false, the sidebar is completely removed from rendering.
*/
readonly enabled: boolean;

/**
Expand All @@ -53,13 +57,22 @@ export interface SidebarManager {
addMenuItem(menuItem: SidebarMenuItem): void;

/**
* Gets the current visibility of the sidebar.
* Gets the current visibility of the sidebar (CSS visibility).
* Different from enabled - when visible=false, sidebar is hidden but still in DOM.
*/
get visible(): boolean;

/**
* Toggles the visibility of the sidebar. Can only be called when
* `sidebarEnabled` returns `ENABLED`.
* Toggles whether the sidebar is enabled (rendered in DOM).
* When disabled, the sidebar is completely removed from rendering.
*/
toggleEnabled(): void;

/**
* Toggles the visibility of the sidebar (CSS visibility).
* If the sidebar is disabled, this will enable it and make it visible.
* Otherwise, toggles between visible and hidden states.
* Note: When in zen mode, use the zen mode toggle commands instead.
*/
toggleVisibility(): void;
}
Expand Down
Loading