DevToolsPresetSelection.js (6170B)
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 // @ts-check 5 6 /** 7 * @template P 8 * @typedef {import("react-redux").ResolveThunks<P>} ResolveThunks<P> 9 */ 10 11 /** 12 * @typedef {object} StateProps 13 * @property {string} presetName 14 * @property {number} interval 15 * @property {string[]} threads 16 * @property {string[]} features 17 * @property {import("../../@types/perf").Presets} presets 18 */ 19 20 /** 21 * @typedef {object} ThunkDispatchProps 22 * @property {typeof actions.changePreset} changePreset 23 */ 24 25 /** 26 * @typedef {object} OwnProps 27 * @property {() => void} onEditSettingsLinkClicked 28 */ 29 30 /** 31 * @typedef {ResolveThunks<ThunkDispatchProps>} DispatchProps 32 * @typedef {StateProps & DispatchProps & OwnProps} Props 33 * @typedef {import("../../@types/perf").State} StoreState 34 * @typedef {import("../../@types/perf").FeatureDescription} FeatureDescription 35 */ 36 37 "use strict"; 38 39 const { 40 PureComponent, 41 createFactory, 42 } = require("resource://devtools/client/shared/vendor/react.mjs"); 43 const { 44 div, 45 select, 46 option, 47 button, 48 ul, 49 li, 50 span, 51 } = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 52 const { 53 connect, 54 } = require("resource://devtools/client/shared/vendor/react-redux.js"); 55 const actions = require("resource://devtools/client/performance-new/store/actions.js"); 56 const selectors = require("resource://devtools/client/performance-new/store/selectors.js"); 57 const { 58 featureDescriptions, 59 } = require("resource://devtools/client/performance-new/shared/utils.js"); 60 const Localized = createFactory( 61 require("resource://devtools/client/shared/vendor/fluent-react.js").Localized 62 ); 63 64 /** 65 * This component displays the preset selection for the DevTools panel. It should be 66 * basically the same implementation as the popup, but done in React. The popup 67 * is written using vanilla JS and browser chrome elements in order to be more 68 * performant. 69 * 70 * @augments {React.PureComponent<Props>} 71 */ 72 class DevToolsPresetSelection extends PureComponent { 73 /** @param {Props} props */ 74 constructor(props) { 75 super(props); 76 77 /** 78 * Create an object map to easily look up feature description. 79 * 80 * @type {{[key: string]: FeatureDescription}} 81 */ 82 this.featureDescriptionMap = {}; 83 for (const feature of featureDescriptions) { 84 this.featureDescriptionMap[feature.value] = feature; 85 } 86 } 87 88 /** 89 * Handle the select change. 90 * 91 * @param {React.ChangeEvent<HTMLSelectElement>} event 92 */ 93 onPresetChange = event => { 94 const { presets } = this.props; 95 this.props.changePreset(presets, event.target.value); 96 }; 97 98 render() { 99 const { presetName, presets, onEditSettingsLinkClicked } = this.props; 100 101 let presetDescription; 102 const currentPreset = presets[presetName]; 103 if (currentPreset) { 104 // Display the current preset's description. 105 presetDescription = Localized({ 106 id: currentPreset.l10nIds.devtools.description, 107 }); 108 } else { 109 // Build up a display of the details of the custom preset. 110 const { interval, threads, features } = this.props; 111 presetDescription = div( 112 null, 113 ul( 114 { className: "perf-presets-custom" }, 115 li( 116 null, 117 Localized( 118 { id: "perftools-devtools-interval-label" }, 119 span({ className: "perf-presets-custom-bold" }) 120 ), 121 " ", 122 Localized({ 123 id: "perftools-range-interval-milliseconds", 124 $interval: interval, 125 }) 126 ), 127 li( 128 null, 129 Localized( 130 { id: "perftools-devtools-threads-label" }, 131 span({ className: "perf-presets-custom-bold" }) 132 ), 133 " ", 134 threads.join(", ") 135 ), 136 features.map(feature => { 137 const description = this.featureDescriptionMap[feature]; 138 if (!description) { 139 throw new Error( 140 "Could not find the feature description for " + feature 141 ); 142 } 143 return li( 144 { key: feature }, 145 description ? description.name : feature 146 ); 147 }) 148 ) 149 ); 150 } 151 152 return div( 153 { className: "perf-presets" }, 154 div( 155 { className: "perf-presets-settings" }, 156 Localized({ id: "perftools-devtools-settings-label" }) 157 ), 158 div( 159 { className: "perf-presets-details" }, 160 div( 161 { className: "perf-presets-details-row" }, 162 select( 163 { 164 className: "perf-presets-select", 165 onChange: this.onPresetChange, 166 value: presetName, 167 }, 168 Object.entries(presets).map(([name, preset]) => 169 Localized( 170 { id: preset.l10nIds.devtools.label }, 171 option({ key: name, value: name }) 172 ) 173 ), 174 Localized( 175 { id: "perftools-presets-custom-label" }, 176 option({ value: "custom" }) 177 ) 178 ) 179 // The overhead component will go here. 180 ), 181 div( 182 { className: "perf-presets-details-row perf-presets-description" }, 183 presetDescription 184 ), 185 button( 186 { 187 className: "perf-external-link", 188 onClick: onEditSettingsLinkClicked, 189 }, 190 Localized({ id: "perftools-button-edit-settings" }) 191 ) 192 ) 193 ); 194 } 195 } 196 197 /** 198 * @param {StoreState} state 199 * @returns {StateProps} 200 */ 201 function mapStateToProps(state) { 202 return { 203 presetName: selectors.getPresetName(state), 204 presets: selectors.getPresets(state), 205 interval: selectors.getInterval(state), 206 threads: selectors.getThreads(state), 207 features: selectors.getFeatures(state), 208 }; 209 } 210 211 /** 212 * @type {ThunkDispatchProps} 213 */ 214 const mapDispatchToProps = { 215 changePreset: actions.changePreset, 216 }; 217 218 module.exports = connect( 219 mapStateToProps, 220 mapDispatchToProps 221 )(DevToolsPresetSelection);