forked from mirrors/gecko-dev
Depends on D140753 Differential Revision: https://phabricator.services.mozilla.com/D140754
265 lines
7.4 KiB
JavaScript
265 lines
7.4 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
// @ts-check
|
|
|
|
/**
|
|
* @template P
|
|
* @typedef {import("react-redux").ResolveThunks<P>} ResolveThunks<P>
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} StateProps
|
|
* @property {RecordingState} recordingState
|
|
* @property {boolean | null} isSupportedPlatform
|
|
* @property {boolean} recordingUnexpectedlyStopped
|
|
* @property {PageContext} pageContext
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} OwnProps
|
|
* @property {import("../@types/perf").OnProfileReceived} onProfileReceived
|
|
* @property {import("../@types/perf").PerfFront} perfFront
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} ThunkDispatchProps
|
|
* @property {typeof actions.startRecording} startRecording
|
|
* @property {typeof actions.getProfileAndStopProfiler} getProfileAndStopProfiler
|
|
* @property {typeof actions.stopProfilerAndDiscardProfile} stopProfilerAndDiscardProfile
|
|
|
|
*/
|
|
|
|
/**
|
|
* @typedef {ResolveThunks<ThunkDispatchProps>} DispatchProps
|
|
* @typedef {StateProps & DispatchProps & OwnProps} Props
|
|
* @typedef {import("../@types/perf").RecordingState} RecordingState
|
|
* @typedef {import("../@types/perf").State} StoreState
|
|
* @typedef {import("../@types/perf").PageContext} PageContext
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
|
const {
|
|
div,
|
|
button,
|
|
span,
|
|
img,
|
|
} = require("devtools/client/shared/vendor/react-dom-factories");
|
|
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
|
const actions = require("devtools/client/performance-new/store/actions");
|
|
const selectors = require("devtools/client/performance-new/store/selectors");
|
|
const React = require("devtools/client/shared/vendor/react");
|
|
const Localized = React.createFactory(
|
|
require("devtools/client/shared/vendor/fluent-react").Localized
|
|
);
|
|
|
|
/**
|
|
* This component is not responsible for the full life cycle of recording a profile. It
|
|
* is only responsible for the actual act of stopping and starting recordings. It
|
|
* also reacts to the changes of the recording state from external changes.
|
|
*
|
|
* @extends {React.PureComponent<Props>}
|
|
*/
|
|
class RecordingButton extends PureComponent {
|
|
_onStartButtonClick = () => {
|
|
const { startRecording, perfFront } = this.props;
|
|
startRecording(perfFront);
|
|
};
|
|
|
|
_onCaptureButtonClick = async () => {
|
|
const {
|
|
getProfileAndStopProfiler,
|
|
onProfileReceived,
|
|
perfFront,
|
|
} = this.props;
|
|
const profile = await getProfileAndStopProfiler(perfFront);
|
|
onProfileReceived(profile);
|
|
};
|
|
|
|
_onStopButtonClick = () => {
|
|
const { stopProfilerAndDiscardProfile, perfFront } = this.props;
|
|
stopProfilerAndDiscardProfile(perfFront);
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
recordingState,
|
|
isSupportedPlatform,
|
|
recordingUnexpectedlyStopped,
|
|
} = this.props;
|
|
|
|
if (!isSupportedPlatform) {
|
|
return renderButton({
|
|
label: startRecordingLabel(),
|
|
isPrimary: true,
|
|
disabled: true,
|
|
additionalMessage:
|
|
// No need to localize as this string is not displayed to Tier-1 platforms.
|
|
"Your platform is not supported. The Gecko Profiler only " +
|
|
"supports Tier-1 platforms.",
|
|
});
|
|
}
|
|
|
|
switch (recordingState) {
|
|
case "not-yet-known":
|
|
return null;
|
|
|
|
case "available-to-record":
|
|
return renderButton({
|
|
onClick: this._onStartButtonClick,
|
|
isPrimary: true,
|
|
label: startRecordingLabel(),
|
|
additionalMessage: recordingUnexpectedlyStopped
|
|
? Localized(
|
|
{ id: "perftools-status-recording-stopped-by-another-tool" },
|
|
div(null, "The recording was stopped by another tool.")
|
|
)
|
|
: null,
|
|
});
|
|
|
|
case "request-to-stop-profiler":
|
|
return renderButton({
|
|
label: Localized(
|
|
{ id: "perftools-request-to-stop-profiler" },
|
|
"Stopping recording"
|
|
),
|
|
disabled: true,
|
|
});
|
|
|
|
case "request-to-get-profile-and-stop-profiler":
|
|
return renderButton({
|
|
label: Localized(
|
|
{ id: "perftools-request-to-get-profile-and-stop-profiler" },
|
|
"Capturing profile"
|
|
),
|
|
disabled: true,
|
|
});
|
|
|
|
case "request-to-start-recording":
|
|
case "recording":
|
|
return renderButton({
|
|
label: span(
|
|
null,
|
|
Localized(
|
|
{ id: "perftools-button-capture-recording" },
|
|
"Capture recording"
|
|
),
|
|
img({
|
|
className: "perf-button-image",
|
|
alt: "",
|
|
/* This icon is actually the "open in new page" icon. */
|
|
src: "chrome://devtools/skin/images/dock-undock.svg",
|
|
})
|
|
),
|
|
isPrimary: true,
|
|
onClick: this._onCaptureButtonClick,
|
|
disabled: recordingState === "request-to-start-recording",
|
|
additionalButton: {
|
|
label: Localized(
|
|
{ id: "perftools-button-cancel-recording" },
|
|
"Cancel recording"
|
|
),
|
|
onClick: this._onStopButtonClick,
|
|
},
|
|
});
|
|
|
|
default:
|
|
throw new Error("Unhandled recording state");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {{
|
|
* disabled?: boolean,
|
|
* label?: React.ReactNode,
|
|
* onClick?: any,
|
|
* additionalMessage?: React.ReactNode,
|
|
* isPrimary?: boolean,
|
|
* pageContext?: PageContext,
|
|
* additionalButton?: {
|
|
* label: React.ReactNode,
|
|
* onClick: any,
|
|
* },
|
|
* }} buttonSettings
|
|
*/
|
|
function renderButton(buttonSettings) {
|
|
const {
|
|
disabled,
|
|
label,
|
|
onClick,
|
|
additionalMessage,
|
|
isPrimary,
|
|
// pageContext,
|
|
additionalButton,
|
|
} = buttonSettings;
|
|
|
|
const buttonClass = isPrimary ? "primary" : "default";
|
|
|
|
return div(
|
|
{ className: "perf-button-container" },
|
|
div(
|
|
null,
|
|
button(
|
|
{
|
|
className: `perf-photon-button perf-photon-button-${buttonClass} perf-button`,
|
|
disabled,
|
|
onClick,
|
|
},
|
|
label
|
|
),
|
|
additionalButton
|
|
? button(
|
|
{
|
|
className: `perf-photon-button perf-photon-button-default perf-button`,
|
|
onClick: additionalButton.onClick,
|
|
disabled,
|
|
},
|
|
additionalButton.label
|
|
)
|
|
: null
|
|
),
|
|
additionalMessage
|
|
? div({ className: "perf-additional-message" }, additionalMessage)
|
|
: null
|
|
);
|
|
}
|
|
|
|
function startRecordingLabel() {
|
|
return span(
|
|
null,
|
|
Localized({ id: "perftools-button-start-recording" }, "Start recording"),
|
|
img({
|
|
className: "perf-button-image",
|
|
alt: "",
|
|
/* This icon is actually the "open in new page" icon. */
|
|
src: "chrome://devtools/skin/images/dock-undock.svg",
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param {StoreState} state
|
|
* @returns {StateProps}
|
|
*/
|
|
function mapStateToProps(state) {
|
|
return {
|
|
recordingState: selectors.getRecordingState(state),
|
|
isSupportedPlatform: selectors.getIsSupportedPlatform(state),
|
|
recordingUnexpectedlyStopped: selectors.getRecordingUnexpectedlyStopped(
|
|
state
|
|
),
|
|
pageContext: selectors.getPageContext(state),
|
|
};
|
|
}
|
|
|
|
/** @type {ThunkDispatchProps} */
|
|
const mapDispatchToProps = {
|
|
startRecording: actions.startRecording,
|
|
stopProfilerAndDiscardProfile: actions.stopProfilerAndDiscardProfile,
|
|
getProfileAndStopProfiler: actions.getProfileAndStopProfiler,
|
|
};
|
|
|
|
module.exports = connect(mapStateToProps, mapDispatchToProps)(RecordingButton);
|