UNPKG

chrome-devtools-frontend

Version:
261 lines (232 loc) • 8.01 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /* eslint-disable rulesdir/no-lit-render-outside-of-view */ import * as Host from '../../../core/host/host.js'; import * as i18n from '../../../core/i18n/i18n.js'; import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js'; import * as Lit from '../../../ui/lit/lit.js'; import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js'; import type * as Extensions from '../extensions/extensions.js'; import type * as Models from '../models/models.js'; import {PlayRecordingSpeed} from '../models/RecordingPlayer.js'; import * as Actions from '../recorder-actions/recorder-actions.js'; import { type SelectButtonClickEvent, type SelectButtonItem, type SelectMenuSelectedEvent, Variant as SelectButtonVariant, } from './SelectButton.js'; const {html} = Lit; const UIStrings = { /** * @description Replay button label */ Replay: 'Replay', /** * @description Button label for the normal speed replay option */ ReplayNormalButtonLabel: 'Normal speed', /** * @description Item label for the normal speed replay option */ ReplayNormalItemLabel: 'Normal (Default)', /** * @description Button label for the slow speed replay option */ ReplaySlowButtonLabel: 'Slow speed', /** * @description Item label for the slow speed replay option */ ReplaySlowItemLabel: 'Slow', /** * @description Button label for the very slow speed replay option */ ReplayVerySlowButtonLabel: 'Very slow speed', /** * @description Item label for the very slow speed replay option */ ReplayVerySlowItemLabel: 'Very slow', /** * @description Button label for the extremely slow speed replay option */ ReplayExtremelySlowButtonLabel: 'Extremely slow speed', /** * @description Item label for the slow speed replay option */ ReplayExtremelySlowItemLabel: 'Extremely slow', /** * @description Label for a group of items in the replay menu that indicate various replay speeds (e.g., Normal, Fast, Slow). */ speedGroup: 'Speed', /** * @description Label for a group of items in the replay menu that indicate various extensions that can be used for replay. */ extensionGroup: 'Extensions', } as const; const items: SelectButtonItem[] = [ { value: PlayRecordingSpeed.NORMAL, buttonIconName: 'play', buttonLabel: () => i18nString(UIStrings.ReplayNormalButtonLabel), label: () => i18nString(UIStrings.ReplayNormalItemLabel), }, { value: PlayRecordingSpeed.SLOW, buttonIconName: 'play', buttonLabel: () => i18nString(UIStrings.ReplaySlowButtonLabel), label: () => i18nString(UIStrings.ReplaySlowItemLabel), }, { value: PlayRecordingSpeed.VERY_SLOW, buttonIconName: 'play', buttonLabel: () => i18nString(UIStrings.ReplayVerySlowButtonLabel), label: () => i18nString(UIStrings.ReplayVerySlowItemLabel), }, { value: PlayRecordingSpeed.EXTREMELY_SLOW, buttonIconName: 'play', buttonLabel: () => i18nString(UIStrings.ReplayExtremelySlowButtonLabel), label: () => i18nString(UIStrings.ReplayExtremelySlowItemLabel), }, ]; const replaySpeedToMetricSpeedMap = { [PlayRecordingSpeed.NORMAL]: Host.UserMetrics.RecordingReplaySpeed.NORMAL, [PlayRecordingSpeed.SLOW]: Host.UserMetrics.RecordingReplaySpeed.SLOW, [PlayRecordingSpeed.VERY_SLOW]: Host.UserMetrics.RecordingReplaySpeed.VERY_SLOW, [PlayRecordingSpeed.EXTREMELY_SLOW]: Host.UserMetrics.RecordingReplaySpeed.EXTREMELY_SLOW, } as const; const str_ = i18n.i18n.registerUIStrings( 'panels/recorder/components/ReplaySection.ts', UIStrings, ); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export class StartReplayEvent extends Event { static readonly eventName = 'startreplay'; constructor( public speed: PlayRecordingSpeed, public extension?: Extensions.ExtensionManager.Extension, ) { super(StartReplayEvent.eventName, {bubbles: true, composed: true}); } } export interface ReplaySectionProps { disabled: boolean; } export interface ReplaySectionData { settings: Models.RecorderSettings.RecorderSettings; replayExtensions: Extensions.ExtensionManager.Extension[]; } const REPLAY_EXTENSION_PREFIX = 'extension'; export class ReplaySection extends HTMLElement { readonly #shadow = this.attachShadow({mode: 'open'}); readonly #props: ReplaySectionProps = {disabled: false}; #settings?: Models.RecorderSettings.RecorderSettings; #replayExtensions: Extensions.ExtensionManager.Extension[] = []; set data(data: ReplaySectionData) { this.#settings = data.settings; this.#replayExtensions = data.replayExtensions; } get disabled(): boolean { return this.#props.disabled; } set disabled(disabled: boolean) { this.#props.disabled = disabled; void ComponentHelpers.ScheduledRender.scheduleRender( this, this.#render, ); } connectedCallback(): void { void ComponentHelpers.ScheduledRender.scheduleRender( this, this.#render, ); } #handleSelectMenuSelected(event: SelectMenuSelectedEvent): void { const speed = event.value as PlayRecordingSpeed; if (this.#settings && event.value) { this.#settings.speed = speed; this.#settings.replayExtension = ''; } Host.userMetrics.recordingReplaySpeed(replaySpeedToMetricSpeedMap[speed]); void ComponentHelpers.ScheduledRender.scheduleRender( this, this.#render, ); } #handleSelectButtonClick(event: SelectButtonClickEvent): void { event.stopPropagation(); if (event.value?.startsWith(REPLAY_EXTENSION_PREFIX)) { if (this.#settings) { this.#settings.replayExtension = event.value; } const extensionIdx = Number( event.value.substring(REPLAY_EXTENSION_PREFIX.length), ); this.dispatchEvent( new StartReplayEvent( PlayRecordingSpeed.NORMAL, this.#replayExtensions[extensionIdx], ), ); void ComponentHelpers.ScheduledRender.scheduleRender( this, this.#render, ); return; } this.dispatchEvent(new StartReplayEvent(this.#settings ? this.#settings.speed : PlayRecordingSpeed.NORMAL)); void ComponentHelpers.ScheduledRender.scheduleRender( this, this.#render, ); } #render(): void { const groups = [{name: i18nString(UIStrings.speedGroup), items}]; if (this.#replayExtensions.length) { groups.push({ name: i18nString(UIStrings.extensionGroup), items: this.#replayExtensions.map((extension, idx) => { return { value: REPLAY_EXTENSION_PREFIX + idx, buttonIconName: 'play', buttonLabel: () => extension.getName(), label: () => extension.getName(), }; }), }); } // clang-format off Lit.render( html` <devtools-select-button @selectmenuselected=${this.#handleSelectMenuSelected} @selectbuttonclick=${this.#handleSelectButtonClick} .variant=${SelectButtonVariant.PRIMARY} .showItemDivider=${false} .disabled=${this.#props.disabled} .action=${Actions.RecorderActions.REPLAY_RECORDING} .value=${this.#settings?.replayExtension || this.#settings?.speed || ''} .buttonLabel=${i18nString(UIStrings.Replay)} .groups=${groups} jslog=${VisualLogging.action(Actions.RecorderActions.REPLAY_RECORDING).track({click: true})} ></devtools-select-button>`, this.#shadow, { host: this }, ); // clang-format on } } customElements.define( 'devtools-replay-section', ReplaySection, ); declare global { interface HTMLElementEventMap { startreplay: StartReplayEvent; } interface HTMLElementTagNameMap { 'devtools-replay-section': ReplaySection; } }