UNPKG

chrome-devtools-frontend

Version:
290 lines (265 loc) • 10.7 kB
// Copyright 2023 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/components/report_view/report_view.js'; import '../../../../ui/kit/kit.js'; import * as i18n from '../../../../core/i18n/i18n.js'; import * as Platform from '../../../../core/platform/platform.js'; import * as Buttons from '../../../../ui/components/buttons/buttons.js'; import * as Dialogs from '../../../../ui/components/dialogs/dialogs.js'; import * as UI from '../../../../ui/legacy/legacy.js'; import {html, i18nTemplate, type LitTemplate, nothing, render} from '../../../../ui/lit/lit.js'; import * as VisualLogging from '../../../../ui/visual_logging/visual_logging.js'; import preloadingDisabledInfobarStyles from './preloadingDisabledInfobar.css.js'; const {urlString} = Platform.DevToolsPath; const UIStrings = { /** * @description Infobar text for disabled case */ infobarPreloadingIsDisabled: 'Speculative loading is disabled', /** * @description Infobar text for force-enabled case */ infobarPreloadingIsForceEnabled: 'Speculative loading is force-enabled', /** * @description Title for dialog */ titleReasonsPreventingPreloading: 'Reasons preventing speculative loading', /** * @description Header in dialog */ headerDisabledByPreference: 'User settings or extensions', /** * @description Description in dialog * @example {Preload pages settings (linked to chrome://settings/performance)} PH1 * @example {Extensions settings (linked to chrome://extensions)} PH2 */ descriptionDisabledByPreference: 'Speculative loading is disabled because of user settings or an extension. Go to {PH1} to update your preference. Go to {PH2} to disable any extension that blocks speculative loading.', /** * @description Text of link */ preloadingPagesSettings: 'Preload pages settings', /** * @description Text of link */ extensionsSettings: 'Extensions settings', /** * @description Header in dialog */ headerDisabledByDataSaver: 'Data Saver', /** * @description Description in dialog */ descriptionDisabledByDataSaver: 'Speculative loading is disabled because of the operating system\'s Data Saver mode.', /** * @description Header in dialog */ headerDisabledByBatterySaver: 'Battery Saver', /** * @description Description in dialog */ descriptionDisabledByBatterySaver: 'Speculative loading is disabled because of the operating system\'s Battery Saver mode.', /** * @description Header in dialog */ headerDisabledByHoldbackPrefetchSpeculationRules: 'Prefetch was disabled, but is force-enabled now', /** * @description Description in infobar */ descriptionDisabledByHoldbackPrefetchSpeculationRules: 'Prefetch is forced-enabled because DevTools is open. When DevTools is closed, prefetch will be disabled because this browser session is part of a holdback group used for performance comparisons.', /** * @description Header in dialog */ headerDisabledByHoldbackPrerenderSpeculationRules: 'Prerendering was disabled, but is force-enabled now', /** * @description Description in infobar */ descriptionDisabledByHoldbackPrerenderSpeculationRules: 'Prerendering is forced-enabled because DevTools is open. When DevTools is closed, prerendering will be disabled because this browser session is part of a holdback group used for performance comparisons.', /** * @description Footer link for more details */ footerLearnMore: 'Learn more', } as const; const str_ = i18n.i18n.registerUIStrings('panels/application/preloading/components/PreloadingDisabledInfobar.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); const LINK = 'https://developer.chrome.com/blog/prerender-pages/'; export interface ViewInput { header: Platform.UIString.LocalizedString|null; warnings: Array<{ key: Platform.UIString.LocalizedString, valueId: string, placeholders?: Record<string, { title: Platform.UIString.LocalizedString, href: Platform.DevToolsPath.UrlString, }>, }>; } type ViewOutput = unknown; export type View = (input: ViewInput, output: ViewOutput, target: HTMLElement|DocumentFragment) => void; export const DEFAULT_VIEW: View = (input, _output, target) => { let template: LitTemplate = nothing; if (input.header !== null) { // Disabled until https://crbug.com/1079231 is fixed. // clang-format off template = html` <style>${preloadingDisabledInfobarStyles}</style> <div id="container"> <span id="header">${input.header}</span> <devtools-button-dialog .data=${{ iconName: 'info', variant: Buttons.Button.Variant.ICON, closeButton: true, position: Dialogs.Dialog.DialogVerticalPosition.AUTO, horizontalAlignment: Dialogs.Dialog.DialogHorizontalAlignment.AUTO, closeOnESC: true, closeOnScroll: false, dialogTitle: i18nString(UIStrings.titleReasonsPreventingPreloading), } as Dialogs.ButtonDialog.ButtonDialogData} jslog=${VisualLogging.dialog('preloading-disabled').track({resize: true, keydown: 'Escape'})}> <div id="contents"> <devtools-report> ${input.warnings.map(({key, valueId, placeholders = {}}) => { const value = i18nTemplate( str_, valueId, Object.fromEntries(Object.entries(placeholders).map( ([key, {title, href}]) => [key, html`<devtools-link href=${href}>${title}</devtools-link>`]))); return html` <div class="key">${key}</div> <div class="value">${value}</div> `; })} </devtools-report> <div id="footer"> <devtools-link href=${LINK} jslogcontext="learn-more"> ${i18nString(UIStrings.footerLearnMore)} </devtools-link> </div> </div> </devtools-button-dialog> </div>`; // clang-format on } render(template, target); }; export class PreloadingDisabledInfobar extends UI.Widget.VBox { #view: View; #disabledByPreference = false; #disabledByDataSaver = false; #disabledByBatterySaver = false; #disabledByHoldbackPrefetchSpeculationRules = false; #disabledByHoldbackPrerenderSpeculationRules = false; constructor(view: View = DEFAULT_VIEW) { super({useShadowDom: true}); this.#view = view; } get disabledByPreference(): boolean { return this.#disabledByPreference; } set disabledByPreference(value: boolean) { if (this.#disabledByPreference !== value) { this.#disabledByPreference = value; this.requestUpdate(); } } get disabledByDataSaver(): boolean { return this.#disabledByDataSaver; } set disabledByDataSaver(value: boolean) { if (this.#disabledByDataSaver !== value) { this.#disabledByDataSaver = value; this.requestUpdate(); } } get disabledByBatterySaver(): boolean { return this.#disabledByBatterySaver; } set disabledByBatterySaver(value: boolean) { if (this.#disabledByBatterySaver !== value) { this.#disabledByBatterySaver = value; this.requestUpdate(); } } get disabledByHoldbackPrefetchSpeculationRules(): boolean { return this.#disabledByHoldbackPrefetchSpeculationRules; } set disabledByHoldbackPrefetchSpeculationRules(value: boolean) { if (this.#disabledByHoldbackPrefetchSpeculationRules !== value) { this.#disabledByHoldbackPrefetchSpeculationRules = value; this.requestUpdate(); } } get disabledByHoldbackPrerenderSpeculationRules(): boolean { return this.#disabledByHoldbackPrerenderSpeculationRules; } set disabledByHoldbackPrerenderSpeculationRules(value: boolean) { if (this.#disabledByHoldbackPrerenderSpeculationRules !== value) { this.#disabledByHoldbackPrerenderSpeculationRules = value; this.requestUpdate(); } } override wasShown(): void { super.wasShown(); this.requestUpdate(); } override performUpdate(): void { let header: Platform.UIString.LocalizedString|null = null; if (this.#disabledByPreference || this.#disabledByDataSaver || this.#disabledByBatterySaver) { header = i18nString(UIStrings.infobarPreloadingIsDisabled); } else if (this.#disabledByHoldbackPrefetchSpeculationRules || this.#disabledByHoldbackPrerenderSpeculationRules) { header = i18nString(UIStrings.infobarPreloadingIsForceEnabled); } const warnings = []; if (this.#disabledByPreference) { warnings.push({ key: i18nString(UIStrings.headerDisabledByPreference), valueId: UIStrings.descriptionDisabledByPreference, placeholders: { PH1: { title: i18nString(UIStrings.preloadingPagesSettings), href: urlString`chrome://settings/performance`, }, PH2: { title: i18nString(UIStrings.extensionsSettings), href: urlString`chrome://extensions`, }, }, }); } if (this.#disabledByDataSaver) { warnings.push({ key: i18nString(UIStrings.headerDisabledByDataSaver), valueId: UIStrings.descriptionDisabledByDataSaver, }); } if (this.#disabledByBatterySaver) { warnings.push({ key: i18nString(UIStrings.headerDisabledByBatterySaver), valueId: UIStrings.descriptionDisabledByBatterySaver, }); } if (this.#disabledByHoldbackPrefetchSpeculationRules) { warnings.push({ key: i18nString(UIStrings.headerDisabledByHoldbackPrefetchSpeculationRules), valueId: UIStrings.descriptionDisabledByHoldbackPrefetchSpeculationRules, }); } if (this.#disabledByHoldbackPrerenderSpeculationRules) { warnings.push({ key: i18nString(UIStrings.headerDisabledByHoldbackPrerenderSpeculationRules), valueId: UIStrings.descriptionDisabledByHoldbackPrerenderSpeculationRules, }); } const input: ViewInput = { header, warnings, }; const output: ViewOutput = undefined; this.#view(input, output, this.contentElement); } }