ProfilerDialog.js (5332B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 connect, 9 } = require("resource://devtools/client/shared/vendor/react-redux.js"); 10 const { 11 createFactory, 12 PureComponent, 13 } = require("resource://devtools/client/shared/vendor/react.mjs"); 14 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 15 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 16 17 const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); 18 const Localized = createFactory(FluentReact.Localized); 19 20 const Actions = require("resource://devtools/client/aboutdebugging/src/actions/index.js"); 21 const Types = require("resource://devtools/client/aboutdebugging/src/types/index.js"); 22 const { 23 PROFILER_PAGE_CONTEXT, 24 } = require("resource://devtools/client/aboutdebugging/src/constants.js"); 25 26 /** 27 * This component is a modal dialog containing the performance profiler UI. It uses 28 * the simplified DevTools panel located in devtools/client/performance-new. When 29 * using a custom preset, and editing the settings, the page context switches 30 * to about:profiling, which receives the PerfFront of the remote debuggee. 31 */ 32 class ProfilerDialog extends PureComponent { 33 static get propTypes() { 34 return { 35 runtimeDetails: Types.runtimeDetails.isRequired, 36 profilerContext: PropTypes.string.isRequired, 37 hideProfilerDialog: PropTypes.func.isRequired, 38 switchProfilerContext: PropTypes.func.isRequired, 39 }; 40 } 41 42 hide() { 43 this.props.hideProfilerDialog(); 44 } 45 46 setProfilerIframeDirection(frameWindow) { 47 // Set iframe direction according to the parent document direction. 48 const { documentElement } = document; 49 const dir = window.getComputedStyle(documentElement).direction; 50 frameWindow.document.documentElement.setAttribute("dir", dir); 51 } 52 53 /** 54 * The profiler iframe can either be the simplified devtools recording panel, 55 * or the more detailed about:profiling settings page. 56 */ 57 renderProfilerIframe() { 58 const { 59 runtimeDetails: { clientWrapper }, 60 switchProfilerContext, 61 profilerContext, 62 } = this.props; 63 64 let src, onLoad; 65 66 switch (profilerContext) { 67 case PROFILER_PAGE_CONTEXT.DEVTOOLS_REMOTE: 68 src = clientWrapper.getPerformancePanelUrl(); 69 onLoad = e => { 70 const frameWindow = e.target.contentWindow; 71 this.setProfilerIframeDirection(frameWindow); 72 73 clientWrapper.loadPerformanceProfiler(frameWindow, () => { 74 switchProfilerContext(PROFILER_PAGE_CONTEXT.ABOUTPROFILING_REMOTE); 75 }); 76 }; 77 break; 78 79 case PROFILER_PAGE_CONTEXT.ABOUTPROFILING_REMOTE: 80 src = "about:profiling#remote"; 81 onLoad = e => { 82 const frameWindow = e.target.contentWindow; 83 this.setProfilerIframeDirection(frameWindow); 84 85 clientWrapper.loadAboutProfiling(frameWindow, () => { 86 switchProfilerContext(PROFILER_PAGE_CONTEXT.DEVTOOLS_REMOTE); 87 }); 88 }; 89 break; 90 91 default: 92 throw new Error(`Unhandled profiler context: "${profilerContext}"`); 93 } 94 95 return dom.iframe({ 96 key: profilerContext, 97 className: "profiler-dialog__frame", 98 src, 99 onLoad, 100 }); 101 } 102 103 render() { 104 const { profilerContext, switchProfilerContext } = this.props; 105 const dialogSizeClassName = 106 profilerContext === PROFILER_PAGE_CONTEXT.DEVTOOLS_REMOTE 107 ? "profiler-dialog__inner--medium" 108 : "profiler-dialog__inner--large"; 109 110 return dom.div( 111 { 112 className: "profiler-dialog__mask qa-profiler-dialog-mask", 113 onClick: () => this.hide(), 114 }, 115 dom.article( 116 { 117 className: `profiler-dialog__inner ${dialogSizeClassName} qa-profiler-dialog`, 118 onClick: e => e.stopPropagation(), 119 }, 120 dom.header( 121 { 122 className: "profiler-dialog__header", 123 }, 124 Localized( 125 { 126 id: "about-debugging-profiler-dialog-title2", 127 }, 128 dom.h1( 129 { 130 className: "profiler-dialog__header__title", 131 }, 132 "about-debugging-profiler-dialog-title2" 133 ) 134 ), 135 dom.button( 136 { 137 className: "ghost-button qa-profiler-dialog-close", 138 onClick: () => { 139 if (profilerContext === PROFILER_PAGE_CONTEXT.DEVTOOLS_REMOTE) { 140 this.hide(); 141 } else { 142 switchProfilerContext(PROFILER_PAGE_CONTEXT.DEVTOOLS_REMOTE); 143 } 144 }, 145 }, 146 dom.img({ 147 src: "chrome://devtools/skin/images/close.svg", 148 }) 149 ) 150 ), 151 this.renderProfilerIframe() 152 ) 153 ); 154 } 155 } 156 157 const mapStateToProps = state => { 158 return { 159 profilerContext: state.ui.profilerContext, 160 }; 161 }; 162 163 const mapDispatchToProps = { 164 hideProfilerDialog: Actions.hideProfilerDialog, 165 switchProfilerContext: Actions.switchProfilerContext, 166 }; 167 168 module.exports = connect(mapStateToProps, mapDispatchToProps)(ProfilerDialog);