Commit 6cba996a authored by Greg Tatum's avatar Greg Tatum
Browse files

Bug 1597376 - Change the isPopup flag to a PageContext; r=julienw

The new about:profiling page creates some more complexity around what
the page context is. It is simpler to handle the different cases with
a union, rather than booleans.

Differential Revision: https://phabricator.services.mozilla.com/D55008

--HG--
extra : moz-landing-system : lando
parent 805e67f3
...@@ -96,6 +96,11 @@ export type RecordingState = ...@@ -96,6 +96,11 @@ export type RecordingState =
// Profiling is not available when in private browsing mode. // Profiling is not available when in private browsing mode.
| "locked-by-private-browsing"; | "locked-by-private-browsing";
// We are currently migrating to a new UX workflow with about:profiling.
// This type provides an easy way to change the implementation based
// on context.
export type PageContext = "popup" | "devtools" | "aboutprofiling";
export interface State { export interface State {
recordingState: RecordingState; recordingState: RecordingState;
recordingUnexpectedlyStopped: boolean; recordingUnexpectedlyStopped: boolean;
...@@ -205,9 +210,8 @@ export interface InitializedValues { ...@@ -205,9 +210,8 @@ export interface InitializedValues {
receiveProfile: ReceiveProfile; receiveProfile: ReceiveProfile;
// A function to set the recording settings. // A function to set the recording settings.
setRecordingPreferences: SetRecordingPreferences; setRecordingPreferences: SetRecordingPreferences;
// A boolean value that sets lets the UI know if it is in the popup window // Determine the current page context.
// or inside of devtools. pageContext: PageContext;
isPopup: boolean;
// The popup and devtools panel use different codepaths for getting symbol tables. // The popup and devtools panel use different codepaths for getting symbol tables.
getSymbolTableGetter: (profile: object) => GetSymbolTableCallback; getSymbolTableGetter: (profile: object) => GetSymbolTableCallback;
// The list of profiler features that the current target supports. Note that // The list of profiler features that the current target supports. Note that
...@@ -260,7 +264,7 @@ export type Action = ...@@ -260,7 +264,7 @@ export type Action =
perfFront: PerfFront; perfFront: PerfFront;
receiveProfile: ReceiveProfile; receiveProfile: ReceiveProfile;
setRecordingPreferences: SetRecordingPreferences; setRecordingPreferences: SetRecordingPreferences;
isPopup: boolean; pageContext: PageContext;
recordingSettingsFromPreferences: RecordingStateFromPreferences; recordingSettingsFromPreferences: RecordingStateFromPreferences;
getSymbolTableGetter: (profile: object) => GetSymbolTableCallback; getSymbolTableGetter: (profile: object) => GetSymbolTableCallback;
supportedFeatures: string[] | null; supportedFeatures: string[] | null;
...@@ -270,7 +274,7 @@ export interface InitializeStoreValues { ...@@ -270,7 +274,7 @@ export interface InitializeStoreValues {
perfFront: PerfFront; perfFront: PerfFront;
receiveProfile: ReceiveProfile; receiveProfile: ReceiveProfile;
setRecordingPreferences: SetRecordingPreferences; setRecordingPreferences: SetRecordingPreferences;
isPopup: boolean; pageContext: PageContext;
recordingPreferences: RecordingStateFromPreferences; recordingPreferences: RecordingStateFromPreferences;
supportedFeatures: string[] | null; supportedFeatures: string[] | null;
getSymbolTableGetter: (profile: object) => GetSymbolTableCallback; getSymbolTableGetter: (profile: object) => GetSymbolTableCallback;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
/** /**
* @typedef {Object} StateProps * @typedef {Object} StateProps
* @property {boolean?} isSupportedPlatform * @property {boolean?} isSupportedPlatform
* @property {boolean?} isPopup * @property {PageContext} pageContext
* @property {string | null} promptEnvRestart * @property {string | null} promptEnvRestart
*/ */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* @typedef {StateProps} Props * @typedef {StateProps} Props
* @typedef {import("../@types/perf").State} StoreState * @typedef {import("../@types/perf").State} StoreState
* @typedef {import("../@types/perf").PanelWindow} PanelWindow * @typedef {import("../@types/perf").PanelWindow} PanelWindow
* @typedef {import("../@types/perf").PageContext} PageContext
*/ */
"use strict"; "use strict";
...@@ -72,17 +73,15 @@ class DevToolsAndPopup extends PureComponent { ...@@ -72,17 +73,15 @@ class DevToolsAndPopup extends PureComponent {
} }
render() { render() {
const { isSupportedPlatform, isPopup, promptEnvRestart } = this.props; const { isSupportedPlatform, pageContext, promptEnvRestart } = this.props;
if (isSupportedPlatform === null) { if (isSupportedPlatform === null) {
// We don't know yet if this is a supported platform, wait for a response. // We don't know yet if this is a supported platform, wait for a response.
return null; return null;
} }
const additionalClassName = isPopup ? "perf-popup" : "perf-devtools";
return div( return div(
{ className: `perf ${additionalClassName}` }, { className: `perf perf-${pageContext}` },
promptEnvRestart promptEnvRestart
? div( ? div(
{ className: "perf-env-restart" }, { className: "perf-env-restart" },
...@@ -106,7 +105,7 @@ class DevToolsAndPopup extends PureComponent { ...@@ -106,7 +105,7 @@ class DevToolsAndPopup extends PureComponent {
: null, : null,
RecordingButton(), RecordingButton(),
Settings(), Settings(),
isPopup ? null : Description() pageContext === "devtools" ? Description() : null
); );
} }
} }
...@@ -118,7 +117,7 @@ class DevToolsAndPopup extends PureComponent { ...@@ -118,7 +117,7 @@ class DevToolsAndPopup extends PureComponent {
function mapStateToProps(state) { function mapStateToProps(state) {
return { return {
isSupportedPlatform: selectors.getIsSupportedPlatform(state), isSupportedPlatform: selectors.getIsSupportedPlatform(state),
isPopup: selectors.getIsPopup(state), pageContext: selectors.getPageContext(state),
promptEnvRestart: selectors.getPromptEnvRestart(state), promptEnvRestart: selectors.getPromptEnvRestart(state),
}; };
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* @property {PerfFront} perfFront * @property {PerfFront} perfFront
* @property {RecordingState} recordingState * @property {RecordingState} recordingState
* @property {boolean?} isSupportedPlatform * @property {boolean?} isSupportedPlatform
* @property {boolean?} isPopup * @property {PageContext} pageContext
* @property {string | null} promptEnvRestart * @property {string | null} promptEnvRestart
*/ */
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
* @typedef {import("../@types/perf").PerfFront} PerfFront * @typedef {import("../@types/perf").PerfFront} PerfFront
* @typedef {import("../@types/perf").RecordingState} RecordingState * @typedef {import("../@types/perf").RecordingState} RecordingState
* @typedef {import("../@types/perf").State} StoreState * @typedef {import("../@types/perf").State} StoreState
* @typedef {import("../@types/perf").PageContext} PageContext
*/ */
/** /**
...@@ -41,6 +42,7 @@ const { PureComponent } = require("devtools/client/shared/vendor/react"); ...@@ -41,6 +42,7 @@ const { PureComponent } = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux"); const { connect } = require("devtools/client/shared/vendor/react-redux");
const actions = require("devtools/client/performance-new/store/actions"); const actions = require("devtools/client/performance-new/store/actions");
const selectors = require("devtools/client/performance-new/store/selectors"); const selectors = require("devtools/client/performance-new/store/selectors");
const { UnhandledCaseError } = require("devtools/client/performance-new/utils");
/** /**
* This component state changes for the performance recording. e.g. If the profiler * This component state changes for the performance recording. e.g. If the profiler
...@@ -64,7 +66,7 @@ class ProfilerEventHandling extends PureComponent { ...@@ -64,7 +66,7 @@ class ProfilerEventHandling extends PureComponent {
} }
componentDidMount() { componentDidMount() {
const { perfFront, reportProfilerReady, isPopup } = this.props; const { perfFront, reportProfilerReady, pageContext } = this.props;
// Ask for the initial state of the profiler. // Ask for the initial state of the profiler.
Promise.all([ Promise.all([
...@@ -85,9 +87,22 @@ class ProfilerEventHandling extends PureComponent { ...@@ -85,9 +87,22 @@ class ProfilerEventHandling extends PureComponent {
if (isLockedForPrivateBrowsing) { if (isLockedForPrivateBrowsing) {
recordingState = "locked-by-private-browsing"; recordingState = "locked-by-private-browsing";
} else if (isActive) { } else if (isActive) {
// The popup is a global control for the recording, so allow it to take switch (pageContext) {
// control of it. case "popup":
recordingState = isPopup ? "recording" : "other-is-recording"; case "aboutprofiling":
// These page contexts are in global control of the profiler, so allow it
// to take control of recording.
recordingState = "recording";
break;
case "devtools":
// The DevTools performance recording shouldn't take control of others
// use of the Gecko Profiler, since it's more interested in the current
// page.
recordingState = "other-is-recording";
break;
default:
throw new UnhandledCaseError(pageContext, "PageContext");
}
} else { } else {
recordingState = "available-to-record"; recordingState = "available-to-record";
} }
...@@ -142,7 +157,7 @@ class ProfilerEventHandling extends PureComponent { ...@@ -142,7 +157,7 @@ class ProfilerEventHandling extends PureComponent {
} }
handleProfilerStarting() { handleProfilerStarting() {
const { changeRecordingState, recordingState, isPopup } = this.props; const { changeRecordingState, recordingState, pageContext } = this.props;
switch (recordingState) { switch (recordingState) {
case "not-yet-known": case "not-yet-known":
// We couldn't have started it yet, so it must have been someone // We couldn't have started it yet, so it must have been someone
...@@ -153,14 +168,21 @@ class ProfilerEventHandling extends PureComponent { ...@@ -153,14 +168,21 @@ class ProfilerEventHandling extends PureComponent {
// We requested to stop the profiler, but someone else already started // We requested to stop the profiler, but someone else already started
// it up. (fallthrough) // it up. (fallthrough)
case "request-to-get-profile-and-stop-profiler": case "request-to-get-profile-and-stop-profiler":
if (isPopup) { switch (pageContext) {
// The profiler popup doesn't care who is recording. It will take control case "popup":
// of it. case "aboutprofiling":
// These page contexts are in global control of the profiler, so allow it
// to take control of recording.
changeRecordingState("recording"); changeRecordingState("recording");
} else { break;
// Someone re-started the profiler while we were asking for the completed case "devtools":
// profile. // The DevTools performance recording shouldn't take control of others
// use of the Gecko Profiler, since it's more interested in the current
// page.
changeRecordingState("other-is-recording"); changeRecordingState("other-is-recording");
break;
default:
throw new UnhandledCaseError(pageContext, "PageContext");
} }
break; break;
...@@ -265,7 +287,7 @@ function mapStateToProps(state) { ...@@ -265,7 +287,7 @@ function mapStateToProps(state) {
perfFront: selectors.getPerfFront(state), perfFront: selectors.getPerfFront(state),
recordingState: selectors.getRecordingState(state), recordingState: selectors.getRecordingState(state),
isSupportedPlatform: selectors.getIsSupportedPlatform(state), isSupportedPlatform: selectors.getIsSupportedPlatform(state),
isPopup: selectors.getIsPopup(state), pageContext: selectors.getPageContext(state),
promptEnvRestart: selectors.getPromptEnvRestart(state), promptEnvRestart: selectors.getPromptEnvRestart(state),
}; };
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* @property {RecordingState} recordingState * @property {RecordingState} recordingState
* @property {boolean} isSupportedPlatform * @property {boolean} isSupportedPlatform
* @property {boolean} recordingUnexpectedlyStopped * @property {boolean} recordingUnexpectedlyStopped
* @property {boolean} isPopup * @property {PageContext} pageContext
*/ */
/** /**
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
* @typedef {StateProps & DispatchProps} Props * @typedef {StateProps & DispatchProps} Props
* @typedef {import("../@types/perf").RecordingState} RecordingState * @typedef {import("../@types/perf").RecordingState} RecordingState
* @typedef {import("../@types/perf").State} StoreState * @typedef {import("../@types/perf").State} StoreState
* @typedef {import("../@types/perf").PageContext} PageContext
*/ */
"use strict"; "use strict";
...@@ -65,7 +66,7 @@ class RecordingButton extends PureComponent { ...@@ -65,7 +66,7 @@ class RecordingButton extends PureComponent {
* onClick?: any, * onClick?: any,
* additionalMessage?: React.ReactNode, * additionalMessage?: React.ReactNode,
* isPrimary?: boolean, * isPrimary?: boolean,
* isPopup?: boolean, * pageContext?: PageContext,
* additionalButton?: { * additionalButton?: {
* label: string, * label: string,
* onClick: any, * onClick: any,
...@@ -79,12 +80,12 @@ class RecordingButton extends PureComponent { ...@@ -79,12 +80,12 @@ class RecordingButton extends PureComponent {
onClick, onClick,
additionalMessage, additionalMessage,
isPrimary, isPrimary,
isPopup, pageContext,
additionalButton, additionalButton,
} = buttonSettings; } = buttonSettings;
const nbsp = "\u00A0"; const nbsp = "\u00A0";
const showAdditionalMessage = isPopup && additionalMessage; const showAdditionalMessage = pageContext === "popup" && additionalMessage;
const buttonClass = isPrimary ? "primary" : "default"; const buttonClass = isPrimary ? "primary" : "default";
return div( return div(
...@@ -223,7 +224,7 @@ function mapStateToProps(state) { ...@@ -223,7 +224,7 @@ function mapStateToProps(state) {
recordingUnexpectedlyStopped: selectors.getRecordingUnexpectedlyStopped( recordingUnexpectedlyStopped: selectors.getRecordingUnexpectedlyStopped(
state state
), ),
isPopup: selectors.getIsPopup(state), pageContext: selectors.getPageContext(state),
}; };
} }
......
...@@ -91,7 +91,7 @@ async function gInit(perfFront, preferenceFront) { ...@@ -91,7 +91,7 @@ async function gInit(perfFront, preferenceFront) {
receiveProfile, receiveProfile,
recordingPreferences, recordingPreferences,
supportedFeatures, supportedFeatures,
isPopup: false, pageContext: "devtools",
// Go ahead and hide the implementation details for the component on how the // Go ahead and hide the implementation details for the component on how the
// preference information is stored // preference information is stored
......
...@@ -106,7 +106,7 @@ async function gInit() { ...@@ -106,7 +106,7 @@ async function gInit() {
// The popup doesn't need to support remote symbol tables from the debuggee. // The popup doesn't need to support remote symbol tables from the debuggee.
// Only get the symbols from this browser. // Only get the symbols from this browser.
getSymbolTableGetter: () => getSymbolsFromThisBrowser, getSymbolTableGetter: () => getSymbolsFromThisBrowser,
isPopup: true, pageContext: "popup",
}) })
); );
......
...@@ -107,7 +107,7 @@ exports.changeEntries = entries => ...@@ -107,7 +107,7 @@ exports.changeEntries = entries =>
exports.changeFeatures = features => { exports.changeFeatures = features => {
return (dispatch, getState) => { return (dispatch, getState) => {
let promptEnvRestart = null; let promptEnvRestart = null;
if (selectors.getIsPopup(getState())) { if (selectors.getPageContext(getState()) === "popup") {
// The popup supports checks to restart the browser for environment // The popup supports checks to restart the browser for environment
// variables. // variables.
if ( if (
......
...@@ -152,7 +152,7 @@ function initializedValues(state = null, action) { ...@@ -152,7 +152,7 @@ function initializedValues(state = null, action) {
perfFront: action.perfFront, perfFront: action.perfFront,
receiveProfile: action.receiveProfile, receiveProfile: action.receiveProfile,
setRecordingPreferences: action.setRecordingPreferences, setRecordingPreferences: action.setRecordingPreferences,
isPopup: Boolean(action.isPopup), pageContext: action.pageContext,
getSymbolTableGetter: action.getSymbolTableGetter, getSymbolTableGetter: action.getSymbolTableGetter,
supportedFeatures: action.supportedFeatures, supportedFeatures: action.supportedFeatures,
}; };
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* @typedef {import("../@types/perf").GetSymbolTableCallback} GetSymbolTableCallback * @typedef {import("../@types/perf").GetSymbolTableCallback} GetSymbolTableCallback
* @typedef {import("../@types/perf").RestartBrowserWithEnvironmentVariable} RestartBrowserWithEnvironmentVariable * @typedef {import("../@types/perf").RestartBrowserWithEnvironmentVariable} RestartBrowserWithEnvironmentVariable
* @typedef {import("../@types/perf").GetEnvironmentVariable} GetEnvironmentVariable * @typedef {import("../@types/perf").GetEnvironmentVariable} GetEnvironmentVariable
* @typedef {import("../@types/perf").PageContext} PageContext
*/ */
/** /**
* @template S * @template S
...@@ -85,8 +86,8 @@ const getReceiveProfileFn = state => getInitializedValues(state).receiveProfile; ...@@ -85,8 +86,8 @@ const getReceiveProfileFn = state => getInitializedValues(state).receiveProfile;
const getSetRecordingPreferencesFn = state => const getSetRecordingPreferencesFn = state =>
getInitializedValues(state).setRecordingPreferences; getInitializedValues(state).setRecordingPreferences;
/** @type {Selector<boolean>} */ /** @type {Selector<PageContext>} */
const getIsPopup = state => getInitializedValues(state).isPopup; const getPageContext = state => getInitializedValues(state).pageContext;
/** @type {Selector<(profile: Object) => GetSymbolTableCallback>} */ /** @type {Selector<(profile: Object) => GetSymbolTableCallback>} */
const getSymbolTableGetter = state => const getSymbolTableGetter = state =>
...@@ -114,7 +115,7 @@ module.exports = { ...@@ -114,7 +115,7 @@ module.exports = {
getPerfFront, getPerfFront,
getReceiveProfileFn, getReceiveProfileFn,
getSetRecordingPreferencesFn, getSetRecordingPreferencesFn,
getIsPopup, getPageContext,
getSymbolTableGetter, getSymbolTableGetter,
getPromptEnvRestart, getPromptEnvRestart,
getSupportedFeatures, getSupportedFeatures,
......
...@@ -224,7 +224,7 @@ function createPerfComponent() { ...@@ -224,7 +224,7 @@ function createPerfComponent() {
recordingPreferences: getRecordingPreferencesFromBrowser(), recordingPreferences: getRecordingPreferencesFromBrowser(),
setRecordingPreferences: recordingPreferencesMock, setRecordingPreferences: recordingPreferencesMock,
getSymbolTableGetter: () => noop, getSymbolTableGetter: () => noop,
isPopup: false, pageContext: "devtools",
supportedFeatures: perfFrontMock.getSupportedFeatures(), supportedFeatures: perfFrontMock.getSupportedFeatures(),
}) })
); );
......
...@@ -247,10 +247,22 @@ function withCommonPathPrefixRemoved(pathArray) { ...@@ -247,10 +247,22 @@ function withCommonPathPrefixRemoved(pathArray) {
); );
} }
class UnhandledCaseError extends Error {
/**
* @param {never} value - Check that
* @param {string} typeName - A friendly type name.
*/
constructor(value, typeName) {
super(`There was an unhandled case for "${typeName}": ${value}`);
this.name = "UnhandledCaseError";
}
}
module.exports = { module.exports = {
formatFileSize, formatFileSize,
makeExponentialScale, makeExponentialScale,
scaleRangeWithClamping, scaleRangeWithClamping,
calculateOverhead, calculateOverhead,
withCommonPathPrefixRemoved, withCommonPathPrefixRemoved,
UnhandledCaseError,
}; };
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment