diff --git a/src/components/calltree/CallTree.js b/src/components/calltree/CallTree.js index 7e52202b11..464efc9bf1 100644 --- a/src/components/calltree/CallTree.js +++ b/src/components/calltree/CallTree.js @@ -20,6 +20,7 @@ import { getScrollToSelectionGeneration, getFocusCallTreeGeneration, getPreviewSelection, + getCategories, } from 'firefox-profiler/selectors/profile'; import { selectedThreadSelectors } from 'firefox-profiler/selectors/per-thread'; import { @@ -37,6 +38,7 @@ import type { ImplementationFilter, ThreadsKey, CallNodeInfo, + CategoryList, IndexIntoCallNodeTable, CallNodeDisplayData, WeightType, @@ -54,6 +56,7 @@ type StateProps = {| +focusCallTreeGeneration: number, +tree: CallTreeType, +callNodeInfo: CallNodeInfo, + +categories: CategoryList, +selectedCallNodeIndex: IndexIntoCallNodeTable | null, +rightClickedCallNodeIndex: IndexIntoCallNodeTable | null, +expandedCallNodeIndexes: Array, @@ -233,13 +236,23 @@ class CallTreeImpl extends PureComponent { maybeProcureInterestingInitialSelection() { // Expand the heaviest callstack up to a certain depth and select the frame // at that depth. - const { tree, expandedCallNodeIndexes, selectedCallNodeIndex } = this.props; + const { + tree, + expandedCallNodeIndexes, + selectedCallNodeIndex, + callNodeInfo: { callNodeTable }, + categories, + } = this.props; if (selectedCallNodeIndex !== null || expandedCallNodeIndexes.length > 0) { // Let's not change some existing state. return; } + const idleCategoryIndex = categories.findIndex( + (category) => category.name === 'Idle' + ); + const newExpandedCallNodeIndexes = expandedCallNodeIndexes.slice(); const maxInterestingDepth = 17; // scientifically determined let currentCallNodeIndex = tree.getRoots()[0]; @@ -253,13 +266,22 @@ class CallTreeImpl extends PureComponent { if (children.length === 0) { break; } - currentCallNodeIndex = children[0]; + + // Let's find if there's a non idle children. + const firstNonIdleNode = children.find( + (nodeIndex) => callNodeTable.category[nodeIndex] !== idleCategoryIndex + ); + + // If there's a non idle children, use it; otherwise use the first + // children (that will be idle). + currentCallNodeIndex = + firstNonIdleNode !== undefined ? firstNonIdleNode : children[0]; newExpandedCallNodeIndexes.push(currentCallNodeIndex); } this._onExpandedCallNodesChange(newExpandedCallNodeIndexes); - const category = tree.getDisplayData(currentCallNodeIndex).categoryName; - if (category !== 'Idle') { + const categoryIndex = callNodeTable.category[currentCallNodeIndex]; + if (categoryIndex !== idleCategoryIndex) { // If we selected the call node with a "idle" category, we'd have a // completely dimmed activity graph because idle stacks are not drawn in // this graph. Because this isn't probably what the average user wants we @@ -316,6 +338,7 @@ export const CallTree = explicitConnect<{||}, StateProps, DispatchProps>({ focusCallTreeGeneration: getFocusCallTreeGeneration(state), tree: selectedThreadSelectors.getCallTree(state), callNodeInfo: selectedThreadSelectors.getCallNodeInfo(state), + categories: getCategories(state), selectedCallNodeIndex: selectedThreadSelectors.getSelectedCallNodeIndex(state), rightClickedCallNodeIndex: diff --git a/src/test/components/ProfileCallTreeView.test.js b/src/test/components/ProfileCallTreeView.test.js index b34583a37b..c20103221d 100644 --- a/src/test/components/ProfileCallTreeView.test.js +++ b/src/test/components/ProfileCallTreeView.test.js @@ -315,8 +315,9 @@ describe('calltree/ProfileCallTreeView', function () { B C[cat:Idle] C[cat:Idle] C[cat:Idle] D E E `); - const { container } = setup(profile); - expect(container.querySelector('.treeViewRow.isSelected')).toBeFalsy(); + const { getRowElement } = setup(profile); + expect(getRowElement('E', { selected: true })).toHaveClass('isSelected'); + expect(getRowElement('B', { expanded: true })).toBeInTheDocument(); }); });