chrome-devtools-frontend
Version:
Chrome DevTools UI
234 lines (208 loc) • 9.15 kB
text/typescript
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../../../ui/kit/kit.js';
import '../../../ui/components/menus/menus.js';
import * as Common from '../../../core/common/common.js';
import * as i18n from '../../../core/i18n/i18n.js';
import * as SDK from '../../../core/sdk/sdk.js';
import type * as Menus from '../../../ui/components/menus/menus.js';
import * as UI from '../../../ui/legacy/legacy.js';
import * as Lit from '../../../ui/lit/lit.js';
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
import * as MobileThrottling from '../../mobile_throttling/mobile_throttling.js';
import cpuThrottlingSelectorStyles from './cpuThrottlingSelector.css.js';
const {render, html} = Lit;
const UIStrings = {
/**
* @description Text label for a selection box showing which CPU throttling option is applied.
* @example {No throttling} PH1
*/
cpu: 'CPU: {PH1}',
/**
* @description Text label for a selection box showing which CPU throttling option is applied.
* @example {No throttling} PH1
*/
cpuThrottling: 'CPU throttling: {PH1}',
/**
* @description Text label for a selection box showing that a specific option is recommended.
* @example {4x slowdown} PH1
*/
recommendedThrottling: '{PH1} – recommended',
/**
* @description Text for why user should change a throttling setting.
*/
recommendedThrottlingReason: 'Consider changing setting to simulate real user environments',
/**
* @description Text to prompt the user to run the CPU calibration process.
*/
calibrate: 'Calibrate…',
/**
* @description Text to prompt the user to re-run the CPU calibration process.
*/
recalibrate: 'Recalibrate…',
/**
* @description Label shown above a list of CPU calibration preset options.
*/
labelCalibratedPresets: 'Calibrated presets',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/CPUThrottlingSelector.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
interface CPUThrottlingGroup {
name: string;
items: SDK.CPUThrottlingManager.CPUThrottlingOption[];
showCustomAddOption?: boolean;
}
interface ViewInput {
recommendedOption: SDK.CPUThrottlingManager.CPUThrottlingOption|null;
currentOption: SDK.CPUThrottlingManager.CPUThrottlingOption;
groups: CPUThrottlingGroup[];
throttling: SDK.CPUThrottlingManager.CalibratedCPUThrottling;
onMenuItemSelected: (event: Menus.SelectMenu.SelectMenuItemSelectedEvent) => void;
onCalibrateClick: () => void;
}
export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLElement): void => {
let recommendedInfoEl;
if (input.recommendedOption && input.currentOption === SDK.CPUThrottlingManager.NoThrottlingOption) {
recommendedInfoEl = html`<devtools-icon
title=${i18nString(UIStrings.recommendedThrottlingReason)}
name=info></devtools-icon>`;
}
const selectionTitle = input.currentOption.title();
const hasCalibratedOnce = input.throttling.low || input.throttling.mid;
const calibrationLabel = hasCalibratedOnce ? i18nString(UIStrings.recalibrate) : i18nString(UIStrings.calibrate);
// clang-format off
/* eslint-disable @devtools/no-deprecated-component-usages */
const template = html`
<style>${cpuThrottlingSelectorStyles}</style>
<devtools-select-menu
=${input.onMenuItemSelected}
.showDivider=${true}
.showArrow=${true}
.sideButton=${false}
.showSelectedItem=${true}
.jslogContext=${'cpu-throttling'}
.buttonTitle=${i18nString(UIStrings.cpu, {PH1: selectionTitle})}
.title=${i18nString(UIStrings.cpuThrottling, {PH1: selectionTitle})}
>
${input.groups.map(group => {
return html`
<devtools-menu-group .name=${group.name} .title=${group.name}>
${group.items.map(option => {
const title = option === input.recommendedOption ? i18nString(UIStrings.recommendedThrottling, {PH1: option.title()}) : option.title();
const rate = option.rate();
return html`
<devtools-menu-item
.value=${option.calibratedDeviceType ?? rate}
.selected=${input.currentOption === option}
.disabled=${rate === 0}
.title=${title}
jslog=${VisualLogging.item(option.jslogContext).track({click: true})}
>
${title}
</devtools-menu-item>
`;
})}
${group.name === 'Calibrated presets' ? html`<devtools-menu-item
.value=${-1 /* This won't be displayed unless it has some value. */}
.title=${calibrationLabel}
jslog=${VisualLogging.action('cpu-throttling-selector-calibrate').track({click: true})}
=${input.onCalibrateClick}
>
${calibrationLabel}
</devtools-menu-item>` : Lit.nothing}
</devtools-menu-group>`;
})}
</devtools-select-menu>
${recommendedInfoEl}
`;
// clang-format on
render(template, target);
};
type View = typeof DEFAULT_VIEW;
export class CPUThrottlingSelector extends UI.Widget.Widget {
#currentOption: SDK.CPUThrottlingManager.CPUThrottlingOption;
#recommendedOption: SDK.CPUThrottlingManager.CPUThrottlingOption|null = null;
#groups: CPUThrottlingGroup[] = [];
#calibratedThrottlingSetting: Common.Settings.Setting<SDK.CPUThrottlingManager.CalibratedCPUThrottling>;
readonly #view: View;
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
super(element);
this.#currentOption = SDK.CPUThrottlingManager.CPUThrottlingManager.instance().cpuThrottlingOption();
this.#calibratedThrottlingSetting =
Common.Settings.Settings.instance().createSetting<SDK.CPUThrottlingManager.CalibratedCPUThrottling>(
'calibrated-cpu-throttling', {}, Common.Settings.SettingStorageType.GLOBAL);
this.#resetGroups();
this.#view = view;
}
set recommendedOption(recommendedOption: SDK.CPUThrottlingManager.CPUThrottlingOption|null) {
this.#recommendedOption = recommendedOption;
this.requestUpdate();
}
override wasShown(): void {
super.wasShown();
SDK.CPUThrottlingManager.CPUThrottlingManager.instance().addEventListener(
SDK.CPUThrottlingManager.Events.RATE_CHANGED, this.#onOptionChange, this);
this.#calibratedThrottlingSetting.addChangeListener(this.#onCalibratedSettingChanged, this);
this.#onOptionChange();
}
override willHide(): void {
super.willHide();
this.#calibratedThrottlingSetting.removeChangeListener(this.#onCalibratedSettingChanged, this);
SDK.CPUThrottlingManager.CPUThrottlingManager.instance().removeEventListener(
SDK.CPUThrottlingManager.Events.RATE_CHANGED, this.#onOptionChange, this);
}
#onOptionChange(): void {
this.#currentOption = SDK.CPUThrottlingManager.CPUThrottlingManager.instance().cpuThrottlingOption();
this.requestUpdate();
}
#onCalibratedSettingChanged(): void {
this.#resetGroups();
this.requestUpdate();
}
#onMenuItemSelected(event: Menus.SelectMenu.SelectMenuItemSelectedEvent): void {
let option;
if (typeof event.itemValue === 'string') {
if (event.itemValue === 'low-tier-mobile') {
option = SDK.CPUThrottlingManager.CalibratedLowTierMobileThrottlingOption;
} else if (event.itemValue === 'mid-tier-mobile') {
option = SDK.CPUThrottlingManager.CalibratedMidTierMobileThrottlingOption;
}
} else {
const rate = Number(event.itemValue);
option = MobileThrottling.ThrottlingPresets.ThrottlingPresets.cpuThrottlingPresets.find(
option => !option.calibratedDeviceType && option.rate() === rate);
}
if (option) {
MobileThrottling.ThrottlingManager.throttlingManager().setCPUThrottlingOption(option);
}
}
#onCalibrateClick(): void {
void Common.Revealer.reveal(this.#calibratedThrottlingSetting);
}
#resetGroups(): void {
this.#groups = [
{
name: '',
items: MobileThrottling.ThrottlingPresets.ThrottlingPresets.cpuThrottlingPresets.filter(
option => !option.calibratedDeviceType),
},
{
name: i18nString(UIStrings.labelCalibratedPresets),
items: MobileThrottling.ThrottlingPresets.ThrottlingPresets.cpuThrottlingPresets.filter(
option => option.calibratedDeviceType),
},
];
}
override async performUpdate(): Promise<void> {
const input: ViewInput = {
recommendedOption: this.#recommendedOption,
currentOption: this.#currentOption,
groups: this.#groups,
throttling: this.#calibratedThrottlingSetting.get(),
onMenuItemSelected: this.#onMenuItemSelected.bind(this),
onCalibrateClick: this.#onCalibrateClick.bind(this),
};
this.#view(input, undefined, this.contentElement);
}
}