summaryrefslogtreecommitdiffstats
path: root/devtools/client/performance-new/store/actions.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/performance-new/store/actions.js')
-rw-r--r--devtools/client/performance-new/store/actions.js218
1 files changed, 218 insertions, 0 deletions
diff --git a/devtools/client/performance-new/store/actions.js b/devtools/client/performance-new/store/actions.js
new file mode 100644
index 0000000000..2bb7ce126c
--- /dev/null
+++ b/devtools/client/performance-new/store/actions.js
@@ -0,0 +1,218 @@
+/* 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
+"use strict";
+
+const selectors = require("resource://devtools/client/performance-new/store/selectors.js");
+
+/**
+ * @typedef {import("../@types/perf").Action} Action
+ * @typedef {import("../@types/perf").Library} Library
+ * @typedef {import("../@types/perf").PerfFront} PerfFront
+ * @typedef {import("../@types/perf").SymbolTableAsTuple} SymbolTableAsTuple
+ * @typedef {import("../@types/perf").RecordingState} RecordingState
+ * @typedef {import("../@types/perf").InitializeStoreValues} InitializeStoreValues
+ * @typedef {import("../@types/perf").RecordingSettings} RecordingSettings
+ * @typedef {import("../@types/perf").Presets} Presets
+ * @typedef {import("../@types/perf").PanelWindow} PanelWindow
+ * @typedef {import("../@types/perf").MinimallyTypedGeckoProfile} MinimallyTypedGeckoProfile
+ */
+
+/**
+ * @template T
+ * @typedef {import("../@types/perf").ThunkAction<T>} ThunkAction<T>
+ */
+
+/**
+ * This is the result of the initial questions about the state of the profiler.
+ *
+ * @param {boolean} isActive
+ * @return {Action}
+ */
+exports.reportProfilerReady = isActive => ({
+ type: "REPORT_PROFILER_READY",
+ isActive,
+});
+
+/**
+ * Dispatched when the profiler starting is observed.
+ * @return {Action}
+ */
+exports.reportProfilerStarted = () => ({
+ type: "REPORT_PROFILER_STARTED",
+});
+
+/**
+ * Dispatched when the profiler stopping is observed.
+ * @return {Action}
+ */
+exports.reportProfilerStopped = () => ({
+ type: "REPORT_PROFILER_STOPPED",
+});
+
+/**
+ * Updates the recording settings for the interval.
+ * @param {number} interval
+ * @return {Action}
+ */
+exports.changeInterval = interval => ({
+ type: "CHANGE_INTERVAL",
+ interval,
+});
+
+/**
+ * Updates the recording settings for the entries.
+ * @param {number} entries
+ * @return {Action}
+ */
+exports.changeEntries = entries => ({
+ type: "CHANGE_ENTRIES",
+ entries,
+});
+
+/**
+ * Updates the recording settings for the features.
+ * @param {string[]} features
+ * @return {ThunkAction<void>}
+ */
+exports.changeFeatures = features => {
+ return ({ dispatch, getState }) => {
+ let promptEnvRestart = null;
+ if (selectors.getPageContext(getState()) === "aboutprofiling") {
+ // TODO Bug 1615431 - The old popup supported restarting the browser, but
+ // this hasn't been updated yet for the about:profiling workflow, because
+ // jstracer is disabled for now.
+ if (
+ !Services.env.get("JS_TRACE_LOGGING") &&
+ features.includes("jstracer")
+ ) {
+ promptEnvRestart = "JS_TRACE_LOGGING";
+ }
+ }
+
+ dispatch({
+ type: "CHANGE_FEATURES",
+ features,
+ promptEnvRestart,
+ });
+ };
+};
+
+/**
+ * Updates the recording settings for the threads.
+ * @param {string[]} threads
+ * @return {Action}
+ */
+exports.changeThreads = threads => ({
+ type: "CHANGE_THREADS",
+ threads,
+});
+
+/**
+ * Change the preset.
+ * @param {Presets} presets
+ * @param {string} presetName
+ * @return {Action}
+ */
+exports.changePreset = (presets, presetName) => ({
+ type: "CHANGE_PRESET",
+ presetName,
+ // Also dispatch the preset so that the reducers can pre-fill the values
+ // from a preset.
+ preset: presets[presetName],
+});
+
+/**
+ * Updates the recording settings for the objdirs.
+ * @param {string[]} objdirs
+ * @return {Action}
+ */
+exports.changeObjdirs = objdirs => ({
+ type: "CHANGE_OBJDIRS",
+ objdirs,
+});
+
+/**
+ * Receive the values to initialize the store. See the reducer for what values
+ * are expected.
+ * @param {InitializeStoreValues} values
+ * @return {Action}
+ */
+exports.initializeStore = values => {
+ return {
+ type: "INITIALIZE_STORE",
+ ...values,
+ };
+};
+
+/**
+ * Whenever the preferences are updated, this action is dispatched to update the
+ * redux store.
+ * @param {RecordingSettings} recordingSettingsFromPreferences
+ * @return {Action}
+ */
+exports.updateSettingsFromPreferences = recordingSettingsFromPreferences => {
+ return {
+ type: "UPDATE_SETTINGS_FROM_PREFERENCES",
+ recordingSettingsFromPreferences,
+ };
+};
+
+/**
+ * Start a new recording with the perfFront and update the internal recording state.
+ * @param {PerfFront} perfFront
+ * @return {ThunkAction<void>}
+ */
+exports.startRecording = perfFront => {
+ return ({ dispatch, getState }) => {
+ const recordingSettings = selectors.getRecordingSettings(getState());
+ // In the case of the profiler popup, the startProfiler can be synchronous.
+ // In order to properly allow the React components to handle the state changes
+ // make sure and change the recording state first, then start the profiler.
+ dispatch({ type: "REQUESTING_TO_START_RECORDING" });
+ perfFront.startProfiler(recordingSettings);
+ };
+};
+
+/**
+ * Stops the profiler, and opens the profile in a new window.
+ * @param {PerfFront} perfFront
+ * @return {ThunkAction<Promise<MinimallyTypedGeckoProfile>>}
+ */
+exports.getProfileAndStopProfiler = perfFront => {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: "REQUESTING_PROFILE" });
+ const profile = await perfFront.getProfileAndStopProfiler();
+ dispatch({ type: "OBTAINED_PROFILE" });
+ return profile;
+ };
+};
+
+/**
+ * Stops the profiler, but does not try to retrieve the profile.
+ * @param {PerfFront} perfFront
+ * @return {ThunkAction<void>}
+ */
+exports.stopProfilerAndDiscardProfile = perfFront => {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: "REQUESTING_TO_STOP_RECORDING" });
+
+ try {
+ await perfFront.stopProfilerAndDiscardProfile();
+ } catch (error) {
+ /** @type {any} */
+ const anyWindow = window;
+ /** @type {PanelWindow} - Coerce the window into the PanelWindow. */
+ const { gIsPanelDestroyed } = anyWindow;
+
+ if (gIsPanelDestroyed) {
+ // This error is most likely "Connection closed, pending request" as the
+ // command can race with closing the panel. Do not report an error. It's
+ // most likely fine.
+ } else {
+ throw error;
+ }
+ }
+ };
+};