/* 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/. */ "use strict"; const { assert } = require("devtools/shared/DevToolsUtils"); const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react"); const { L10N } = require("../utils"); const models = require("../models"); const { viewState } = require("../constants"); module.exports = createClass({ displayName: "Toolbar", propTypes: { censusDisplays: PropTypes.arrayOf(PropTypes.shape({ displayName: PropTypes.string.isRequired, })).isRequired, censusDisplay: PropTypes.shape({ displayName: PropTypes.string.isRequired, }).isRequired, onTakeSnapshotClick: PropTypes.func.isRequired, onImportClick: PropTypes.func.isRequired, onClearSnapshotsClick: PropTypes.func.isRequired, onCensusDisplayChange: PropTypes.func.isRequired, onToggleRecordAllocationStacks: PropTypes.func.isRequired, allocations: models.allocations, filterString: PropTypes.string, setFilterString: PropTypes.func.isRequired, diffing: models.diffingModel, onToggleDiffing: PropTypes.func.isRequired, view: models.view.isRequired, onViewChange: PropTypes.func.isRequired, labelDisplays: PropTypes.arrayOf(PropTypes.shape({ displayName: PropTypes.string.isRequired, })).isRequired, labelDisplay: PropTypes.shape({ displayName: PropTypes.string.isRequired, }).isRequired, onLabelDisplayChange: PropTypes.func.isRequired, treeMapDisplays: PropTypes.arrayOf(PropTypes.shape({ displayName: PropTypes.string.isRequired, })).isRequired, onTreeMapDisplayChange: PropTypes.func.isRequired, snapshots: PropTypes.arrayOf(models.snapshot).isRequired, }, render() { let { onTakeSnapshotClick, onImportClick, onClearSnapshotsClick, onCensusDisplayChange, censusDisplays, censusDisplay, labelDisplays, labelDisplay, onLabelDisplayChange, treeMapDisplays, onTreeMapDisplayChange, onToggleRecordAllocationStacks, allocations, filterString, setFilterString, snapshots, diffing, onToggleDiffing, view, onViewChange, } = this.props; let viewToolbarOptions; if (view.state == viewState.CENSUS || view.state === viewState.DIFFING) { viewToolbarOptions = dom.div( { className: "toolbar-group" }, dom.label( { className: "display-by", title: L10N.getStr("toolbar.displayBy.tooltip"), }, L10N.getStr("toolbar.displayBy"), dom.select( { id: "select-display", className: "select-display", onChange: e => { const newDisplay = censusDisplays.find(b => b.displayName === e.target.value); onCensusDisplayChange(newDisplay); }, value: censusDisplay.displayName, }, censusDisplays.map(({ tooltip, displayName }) => dom.option( { key: `display-${displayName}`, value: displayName, title: tooltip, }, displayName )) ) ), dom.div({ id: "toolbar-spacer", className: "spacer" }), dom.input({ id: "filter", type: "search", className: "devtools-filterinput", placeholder: L10N.getStr("filter.placeholder"), title: L10N.getStr("filter.tooltip"), onChange: event => setFilterString(event.target.value), value: filterString || undefined, }) ); } else if (view.state == viewState.TREE_MAP) { assert(treeMapDisplays.length >= 1, "Should always have at least one tree map display"); // Only show the dropdown if there are multiple display options viewToolbarOptions = treeMapDisplays.length > 1 ? dom.div( { className: "toolbar-group" }, dom.label( { className: "display-by", title: L10N.getStr("toolbar.displayBy.tooltip"), }, L10N.getStr("toolbar.displayBy"), dom.select( { id: "select-tree-map-display", onChange: e => { const newDisplay = treeMapDisplays.find(b => b.displayName === e.target.value); onTreeMapDisplayChange(newDisplay); }, }, treeMapDisplays.map(({ tooltip, displayName }) => dom.option( { key: `tree-map-display-${displayName}`, value: displayName, title: tooltip, }, displayName )) ) ) ) : null; } else { assert(view.state === viewState.DOMINATOR_TREE || view.state === viewState.INDIVIDUALS); viewToolbarOptions = dom.div( { className: "toolbar-group" }, dom.label( { className: "label-by", title: L10N.getStr("toolbar.labelBy.tooltip"), }, L10N.getStr("toolbar.labelBy"), dom.select( { id: "select-label-display", onChange: e => { const newDisplay = labelDisplays.find(b => b.displayName === e.target.value); onLabelDisplayChange(newDisplay); }, value: labelDisplay.displayName, }, labelDisplays.map(({ tooltip, displayName }) => dom.option( { key: `label-display-${displayName}`, value: displayName, title: tooltip, }, displayName )) ) ) ); } let viewSelect; if (view.state !== viewState.DIFFING && view.state !== viewState.INDIVIDUALS) { viewSelect = dom.label( { title: L10N.getStr("toolbar.view.tooltip"), }, L10N.getStr("toolbar.view"), dom.select( { id: "select-view", onChange: e => onViewChange(e.target.value), defaultValue: view, value: view.state, }, dom.option( { value: viewState.TREE_MAP, title: L10N.getStr("toolbar.view.treemap.tooltip"), }, L10N.getStr("toolbar.view.treemap") ), dom.option( { value: viewState.CENSUS, title: L10N.getStr("toolbar.view.census.tooltip"), }, L10N.getStr("toolbar.view.census") ), dom.option( { value: viewState.DOMINATOR_TREE, title: L10N.getStr("toolbar.view.dominators.tooltip"), }, L10N.getStr("toolbar.view.dominators") ) ) ); } return ( dom.div( { className: "devtools-toolbar" }, dom.div( { className: "toolbar-group" }, dom.button({ id: "clear-snapshots", className: "clear-snapshots devtools-button", disabled: !snapshots.length, onClick: onClearSnapshotsClick, title: L10N.getStr("clear-snapshots.tooltip") }), dom.button({ id: "take-snapshot", className: "take-snapshot devtools-button", onClick: onTakeSnapshotClick, title: L10N.getStr("take-snapshot") }), dom.button( { id: "diff-snapshots", className: "devtools-button devtools-monospace" + (!!diffing ? " checked" : ""), disabled: snapshots.length < 2, onClick: onToggleDiffing, title: L10N.getStr("diff-snapshots.tooltip"), } ), dom.button( { id: "import-snapshot", className: "devtools-toolbarbutton import-snapshot devtools-button", onClick: onImportClick, title: L10N.getStr("import-snapshot"), } ) ), dom.label( { id: "record-allocation-stacks-label", title: L10N.getStr("checkbox.recordAllocationStacks.tooltip"), }, dom.input({ id: "record-allocation-stacks-checkbox", type: "checkbox", checked: allocations.recording, disabled: allocations.togglingInProgress, onChange: onToggleRecordAllocationStacks, }), L10N.getStr("checkbox.recordAllocationStacks") ), viewSelect, viewToolbarOptions ) ); } });