chrome-devtools-frontend
Version:
Chrome DevTools UI
261 lines (232 loc) • 8.01 kB
text/typescript
// 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
=${this.#handleSelectMenuSelected}
=${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;
}
}