summaryrefslogtreecommitdiffstats
path: root/devtools/client/memory/components/CensusTreeItem.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/memory/components/CensusTreeItem.js')
-rw-r--r--devtools/client/memory/components/CensusTreeItem.js185
1 files changed, 185 insertions, 0 deletions
diff --git a/devtools/client/memory/components/CensusTreeItem.js b/devtools/client/memory/components/CensusTreeItem.js
new file mode 100644
index 0000000000..39fdbeb052
--- /dev/null
+++ b/devtools/client/memory/components/CensusTreeItem.js
@@ -0,0 +1,185 @@
+/* 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 { isSavedFrame } = require("resource://devtools/shared/DevToolsUtils.js");
+const {
+ Component,
+ createFactory,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+const {
+ L10N,
+ formatNumber,
+ formatPercent,
+} = require("resource://devtools/client/memory/utils.js");
+const Frame = createFactory(
+ require("resource://devtools/client/shared/components/Frame.js")
+);
+const {
+ TREE_ROW_HEIGHT,
+} = require("resource://devtools/client/memory/constants.js");
+const models = require("resource://devtools/client/memory/models.js");
+
+class CensusTreeItem extends Component {
+ static get propTypes() {
+ return {
+ arrow: PropTypes.any,
+ depth: PropTypes.number.isRequired,
+ diffing: models.app.diffing,
+ expanded: PropTypes.bool.isRequired,
+ focused: PropTypes.bool.isRequired,
+ getPercentBytes: PropTypes.func.isRequired,
+ getPercentCount: PropTypes.func.isRequired,
+ inverted: PropTypes.bool,
+ item: PropTypes.object.isRequired,
+ onViewIndividuals: PropTypes.func.isRequired,
+ onViewSourceInDebugger: PropTypes.func.isRequired,
+ };
+ }
+
+ constructor(props) {
+ super(props);
+ this.toLabel = this.toLabel.bind(this);
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return (
+ this.props.item != nextProps.item ||
+ this.props.depth != nextProps.depth ||
+ this.props.expanded != nextProps.expanded ||
+ this.props.focused != nextProps.focused ||
+ this.props.diffing != nextProps.diffing
+ );
+ }
+
+ toLabel(name, onViewSourceInDebugger) {
+ if (isSavedFrame(name)) {
+ return Frame({
+ frame: name,
+ onClick: onViewSourceInDebugger,
+ showFunctionName: true,
+ showHost: true,
+ });
+ }
+
+ if (name === null) {
+ return L10N.getStr("tree-item.root");
+ }
+
+ if (name === "noStack") {
+ return L10N.getStr("tree-item.nostack");
+ }
+
+ if (name === "noFilename") {
+ return L10N.getStr("tree-item.nofilename");
+ }
+
+ return String(name);
+ }
+
+ render() {
+ const {
+ item,
+ depth,
+ arrow,
+ focused,
+ getPercentBytes,
+ getPercentCount,
+ diffing,
+ onViewSourceInDebugger,
+ onViewIndividuals,
+ inverted,
+ } = this.props;
+
+ const bytes = formatNumber(item.bytes, !!diffing);
+ const percentBytes = formatPercent(getPercentBytes(item.bytes), !!diffing);
+
+ const count = formatNumber(item.count, !!diffing);
+ const percentCount = formatPercent(getPercentCount(item.count), !!diffing);
+
+ const totalBytes = formatNumber(item.totalBytes, !!diffing);
+ const percentTotalBytes = formatPercent(
+ getPercentBytes(item.totalBytes),
+ !!diffing
+ );
+
+ const totalCount = formatNumber(item.totalCount, !!diffing);
+ const percentTotalCount = formatPercent(
+ getPercentCount(item.totalCount),
+ !!diffing
+ );
+
+ let pointer;
+ if (inverted && depth > 0) {
+ pointer = dom.span({ className: "children-pointer" }, "↖");
+ } else if (!inverted && item.children?.length) {
+ pointer = dom.span({ className: "children-pointer" }, "↘");
+ }
+
+ let individualsCell;
+ if (!diffing) {
+ let individualsButton;
+ if (item.reportLeafIndex !== undefined) {
+ individualsButton = dom.button(
+ {
+ key: `individuals-button-${item.id}`,
+ title: L10N.getStr("tree-item.view-individuals.tooltip"),
+ className: "devtools-button individuals-button",
+ onClick: e => {
+ // Don't let the event bubble up to cause this item to focus after
+ // we have switched views, which would lead to assertion failures.
+ e.preventDefault();
+ e.stopPropagation();
+
+ onViewIndividuals(item);
+ },
+ },
+ "⁂"
+ );
+ }
+ individualsCell = dom.span(
+ { className: "heap-tree-item-field heap-tree-item-individuals" },
+ individualsButton
+ );
+ }
+
+ return dom.div(
+ { className: `heap-tree-item ${focused ? "focused" : ""}` },
+ dom.span(
+ { className: "heap-tree-item-field heap-tree-item-bytes" },
+ dom.span({ className: "heap-tree-number" }, bytes),
+ dom.span({ className: "heap-tree-percent" }, percentBytes)
+ ),
+ dom.span(
+ { className: "heap-tree-item-field heap-tree-item-count" },
+ dom.span({ className: "heap-tree-number" }, count),
+ dom.span({ className: "heap-tree-percent" }, percentCount)
+ ),
+ dom.span(
+ { className: "heap-tree-item-field heap-tree-item-total-bytes" },
+ dom.span({ className: "heap-tree-number" }, totalBytes),
+ dom.span({ className: "heap-tree-percent" }, percentTotalBytes)
+ ),
+ dom.span(
+ { className: "heap-tree-item-field heap-tree-item-total-count" },
+ dom.span({ className: "heap-tree-number" }, totalCount),
+ dom.span({ className: "heap-tree-percent" }, percentTotalCount)
+ ),
+ individualsCell,
+ dom.span(
+ {
+ className: "heap-tree-item-field heap-tree-item-name",
+ style: { marginInlineStart: depth * TREE_ROW_HEIGHT },
+ },
+ arrow,
+ pointer,
+ this.toLabel(item.name, onViewSourceInDebugger)
+ )
+ );
+ }
+}
+
+module.exports = CensusTreeItem;