diff --git a/.eslintrc.js b/.eslintrc.js index 86ec975d87..e1f1b2bcfd 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -46,11 +46,6 @@ module.exports = { // See https://github.com/yannickcr/eslint-plugin-react/issues/1561 // 'react/no-unused-prop-types': 'error', 'react/no-unused-state': 'error', - 'react/prefer-stateless-function': 'error', - 'react/prefer-stateless-function': [ - 'error', - { ignorePureComponents: true }, - ], 'react/jsx-no-bind': 'error', 'flowtype/require-valid-file-annotation': [ 'error', 'always', { annotationStyle: 'line' } ], // no-dupe-keys crashes with recent eslint. See diff --git a/res/css/categories.css b/res/css/categories.css new file mode 100644 index 0000000000..64559a8954 --- /dev/null +++ b/res/css/categories.css @@ -0,0 +1,52 @@ +/* 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/. */ + +/** + * This class should be used to create a small color swatch to describe a + * category. It is a global css class as it can be used across the project. + */ +.category-swatch { + display: inline-block; + box-sizing: border-box; + width: 9px; + height: 9px; + border: 0.5px solid rgba(0, 0, 0, 0.1); + margin-right: 3px; +} + +.category-swatch.category-color-transparent { + background-color: transparent; +} + +.category-swatch.category-color-purple { + background-color: var(--purple-70); +} + +.category-swatch.category-color-green { + background-color: var(--green-60); +} + +.category-swatch.category-color-orange { + background-color: var(--orange-50); +} + +.category-swatch.category-color-yellow { + background-color: var(--yellow-50); +} + +.category-swatch.category-color-lightblue { + background-color: var(--blue-40); +} + +.category-swatch.category-color-grey { + background-color: var(--grey-30); +} + +.category-swatch.category-color-blue { + background-color: var(--blue-60); +} + +.category-swatch.category-color-brown { + background-color: var(--magenta-60); +} diff --git a/res/css/style.css b/res/css/style.css index 40d8b99d2f..bce4edda0c 100644 --- a/res/css/style.css +++ b/res/css/style.css @@ -197,42 +197,6 @@ body, color: highlighttext; } -.treeViewCategoryKnob { - display: inline-block; - box-sizing: border-box; - width: 9px; - height: 9px; - border: 0.5px solid rgba(0, 0, 0, 0.1); - margin-right: 3px; -} -.treeViewCategoryKnob.category-color-transparent { - background-color: transparent; -} -.treeViewCategoryKnob.category-color-purple { - background-color: var(--purple-70); -} -.treeViewCategoryKnob.category-color-green { - background-color: var(--green-60); -} -.treeViewCategoryKnob.category-color-orange { - background-color: var(--orange-50); -} -.treeViewCategoryKnob.category-color-yellow { - background-color: var(--yellow-50); -} -.treeViewCategoryKnob.category-color-lightblue { - background-color: var(--blue-40); -} -.treeViewCategoryKnob.category-color-grey { - background-color: var(--grey-30); -} -.treeViewCategoryKnob.category-color-blue { - background-color: var(--blue-60); -} -.treeViewCategoryKnob.category-color-brown { - background-color: var(--magenta-60); -} - .treeViewHighlighting { /* This negative margin enlarges the background to the top, so that it fully * covers the underlying background. There's an underlying background when the diff --git a/src/components/shared/Backtrace.css b/src/components/shared/Backtrace.css index 01ee5e1a70..7c8ebfb0a8 100644 --- a/src/components/shared/Backtrace.css +++ b/src/components/shared/Backtrace.css @@ -1,5 +1,4 @@ .backtrace { - --max-height: 30em; --gradient-height: calc(var(--max-height) - 5em); margin: 5px; diff --git a/src/components/shared/Backtrace.js b/src/components/shared/Backtrace.js index e9b1061dd6..01d259fcf4 100644 --- a/src/components/shared/Backtrace.js +++ b/src/components/shared/Backtrace.js @@ -11,29 +11,29 @@ import { convertStackToCallNodePath, } from '../../profile-logic/profile-data'; -import type { Thread } from '../../types/profile'; -import type { CauseBacktrace } from '../../types/markers'; +import type { Thread, IndexIntoStackTable } from '../../types/profile'; import type { ImplementationFilter } from '../../types/actions'; require('./Backtrace.css'); type Props = {| +thread: Thread, - +cause: CauseBacktrace, + +maxHeight: string | number, + +stackIndex: IndexIntoStackTable, +implementationFilter: ImplementationFilter, |}; function Backtrace(props: Props) { - const { cause, thread, implementationFilter } = props; + const { stackIndex, thread, implementationFilter, maxHeight } = props; const { funcTable, stringTable } = thread; const callNodePath = filterCallNodePathByImplementation( thread, implementationFilter, - convertStackToCallNodePath(thread, cause.stack) + convertStackToCallNodePath(thread, stackIndex) ); return ( -
    +
      {callNodePath.length > 0 ? ( callNodePath.map((func, i) => (
    1. diff --git a/src/components/shared/MarkerTooltipContents.js b/src/components/shared/MarkerTooltipContents.js index c604c56239..8f6b4f3eb6 100644 --- a/src/components/shared/MarkerTooltipContents.js +++ b/src/components/shared/MarkerTooltipContents.js @@ -344,7 +344,8 @@ function _markerBacktrace( First invalidated {formatNumber(causeAge)}ms before the flush, at: diff --git a/src/components/shared/SampleTooltipContents.js b/src/components/shared/SampleTooltipContents.js new file mode 100644 index 0000000000..6495df81f3 --- /dev/null +++ b/src/components/shared/SampleTooltipContents.js @@ -0,0 +1,58 @@ +/* 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/. */ +// @flow + +import * as React from 'react'; +import type { + IndexIntoSamplesTable, + CategoryList, + Thread, +} from '../../types/profile'; +import Backtrace from './Backtrace'; + +type Props = {| + +sampleIndex: IndexIntoSamplesTable, + +categories: CategoryList, + +fullThread: Thread, +|}; + +/** + * This class displays the tooltip contents for a given sample. Typically the user + * will want to know what the function is, and its category. + */ +export default class SampleTooltipContents extends React.PureComponent { + render() { + const { sampleIndex, fullThread, categories } = this.props; + const { samples, stackTable } = fullThread; + const stackIndex = samples.stack[sampleIndex]; + if (stackIndex === null) { + return 'No stack information'; + } + const categoryIndex = stackTable.category[stackIndex]; + const category = categories[categoryIndex]; + + return ( + <> +
      +
      Category:
      +
      + + {category.name} +
      +
      +
      +
      Stack:
      +
      + + + ); + } +} diff --git a/src/components/shared/TreeView.js b/src/components/shared/TreeView.js index eb58f11af8..fba9381a3d 100644 --- a/src/components/shared/TreeView.js +++ b/src/components/shared/TreeView.js @@ -247,7 +247,7 @@ class TreeViewRowScrolledColumns< > {displayData.categoryColor && displayData.categoryName ? ( number, |}; -class ThreadActivityGraph extends PureComponent { +type State = { + hoveredSample: null | IndexIntoSamplesTable, + mouseX: CssPixels, + mouseY: CssPixels, +}; + +class ThreadActivityGraph extends React.PureComponent { _canvas: null | HTMLCanvasElement = null; _resizeListener = () => this.forceUpdate(); _categoryDrawStyles: null | CategoryDrawStyles = null; _fillsQuerier: null | ActivityFillGraphQuerier = null; + state = { + hoveredSample: null, + mouseX: 0, + mouseY: 0, + }; + + _onMouseLeave = () => { + this.setState({ hoveredSample: null }); + }; + + _onMouseMove = (event: SyntheticMouseEvent) => { + const canvas = this._canvas; + if (!canvas) { + return; + } + const rect = canvas.getBoundingClientRect(); + this.setState({ + hoveredSample: this._getSampleAtMouseEvent(event), + mouseX: event.pageX, + // Have the tooltip align to the bottom of the track. + mouseY: rect.bottom - MOUSE_OFFSET, + }); + }; + _takeCanvasRef = (canvas: HTMLCanvasElement | null) => { this._canvas = canvas; }; @@ -186,21 +218,27 @@ class ThreadActivityGraph extends PureComponent { } } - _onMouseUp = (e: SyntheticMouseEvent<>) => { + _getSampleAtMouseEvent( + event: SyntheticMouseEvent<> + ): null | IndexIntoSamplesTable { // Create local variables so that Flow can refine the following to be non-null. const fillsQuerier = this._fillsQuerier; const canvas = this._canvas; if (!canvas || !fillsQuerier) { - return; + return null; } // Re-measure the canvas and get the coordinates and time for the click. const { rangeStart, rangeEnd } = this.props; const rect = canvas.getBoundingClientRect(); - const x = e.pageX - rect.left; - const y = e.pageY - rect.top; + const x = event.pageX - rect.left; + const y = event.pageY - rect.top; const time = rangeStart + x / rect.width * (rangeEnd - rangeStart); - const sample = fillsQuerier.getSampleAtClick(x, y, time, rect); + return fillsQuerier.getSampleAtClick(x, y, time, rect); + } + + _onMouseUp = (event: SyntheticMouseEvent<>) => { + const sample = this._getSampleAtMouseEvent(event); if (sample !== null) { this.props.onSampleClick(sample); } @@ -208,8 +246,14 @@ class ThreadActivityGraph extends PureComponent { render() { this._renderCanvas(); + const { fullThread, categories } = this.props; + const { hoveredSample, mouseX, mouseY } = this.state; return ( -
      +
      { ref={this._takeCanvasRef} onMouseUp={this._onMouseUp} /> + {hoveredSample === null ? null : ( + + + + )}
      ); } diff --git a/src/index.js b/src/index.js index 27c073843a..a11e30f8e5 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,7 @@ import Root from './components/app/Root'; import createStore from './app-logic/create-store'; import 'photon-colors/photon-colors.css'; import '../res/css/style.css'; +import '../res/css/categories.css'; import { addDataToWindowObject, logFriendlyPreamble, diff --git a/src/test/components/__snapshots__/GlobalTrack.test.js.snap b/src/test/components/__snapshots__/GlobalTrack.test.js.snap index 525109284d..5d14e21cd7 100644 --- a/src/test/components/__snapshots__/GlobalTrack.test.js.snap +++ b/src/test/components/__snapshots__/GlobalTrack.test.js.snap @@ -59,6 +59,8 @@ process: \\"tab\\" (222)"
        1. name @@ -1498,7 +1498,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1533,7 +1533,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1568,7 +1568,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1603,7 +1603,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1638,7 +1638,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1673,7 +1673,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1708,7 +1708,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1743,7 +1743,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1778,7 +1778,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1813,7 +1813,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1848,7 +1848,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1883,7 +1883,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1918,7 +1918,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1953,7 +1953,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -1988,7 +1988,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -2027,7 +2027,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -2062,7 +2062,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -2097,7 +2097,7 @@ exports[`calltree/ProfileCallTreeView computes a width for a call tree of a real className="treeViewRowColumn treeViewMainColumn name" > name @@ -2647,7 +2647,7 @@ exports[`calltree/ProfileCallTreeView renders an inverted call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > Z @@ -2682,7 +2682,7 @@ exports[`calltree/ProfileCallTreeView renders an inverted call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > Y @@ -2717,7 +2717,7 @@ exports[`calltree/ProfileCallTreeView renders an inverted call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > X @@ -2752,7 +2752,7 @@ exports[`calltree/ProfileCallTreeView renders an inverted call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > B @@ -2787,7 +2787,7 @@ exports[`calltree/ProfileCallTreeView renders an inverted call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > A @@ -2822,7 +2822,7 @@ exports[`calltree/ProfileCallTreeView renders an inverted call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > C @@ -2857,7 +2857,7 @@ exports[`calltree/ProfileCallTreeView renders an inverted call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > E @@ -3407,7 +3407,7 @@ exports[`calltree/ProfileCallTreeView renders an unfiltered call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > A @@ -3442,7 +3442,7 @@ exports[`calltree/ProfileCallTreeView renders an unfiltered call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > B @@ -3477,7 +3477,7 @@ exports[`calltree/ProfileCallTreeView renders an unfiltered call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > C @@ -3512,7 +3512,7 @@ exports[`calltree/ProfileCallTreeView renders an unfiltered call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > D @@ -3547,7 +3547,7 @@ exports[`calltree/ProfileCallTreeView renders an unfiltered call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > E @@ -3582,7 +3582,7 @@ exports[`calltree/ProfileCallTreeView renders an unfiltered call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > F @@ -3617,7 +3617,7 @@ exports[`calltree/ProfileCallTreeView renders an unfiltered call tree 1`] = ` className="treeViewRowColumn treeViewMainColumn name" > H @@ -4167,7 +4167,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > A @@ -4202,7 +4202,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > B @@ -4237,7 +4237,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > C @@ -4272,7 +4272,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > D @@ -4307,7 +4307,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > E @@ -4342,7 +4342,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > F @@ -4377,7 +4377,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > H @@ -4886,7 +4886,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > A @@ -4921,7 +4921,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > B @@ -4956,7 +4956,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > D @@ -5031,7 +5031,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > E @@ -5066,7 +5066,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > F @@ -5575,7 +5575,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > A @@ -5610,7 +5610,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > B @@ -5645,7 +5645,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > D @@ -5720,7 +5720,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > E @@ -5755,7 +5755,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > F @@ -6182,7 +6182,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > A @@ -6217,7 +6217,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > B @@ -6252,7 +6252,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > A @@ -6759,7 +6759,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > B @@ -6794,7 +6794,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > A @@ -7383,7 +7383,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > B @@ -7418,7 +7418,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > D @@ -7493,7 +7493,7 @@ exports[`calltree/ProfileCallTreeView renders call tree with some search strings className="treeViewRowColumn treeViewMainColumn name" > F diff --git a/src/test/components/__snapshots__/ThreadActivityGraph.test.js.snap b/src/test/components/__snapshots__/ThreadActivityGraph.test.js.snap index 21d7bcdae5..532a29f354 100644 --- a/src/test/components/__snapshots__/ThreadActivityGraph.test.js.snap +++ b/src/test/components/__snapshots__/ThreadActivityGraph.test.js.snap @@ -2604,6 +2604,8 @@ exports[`SelectedThreadActivityGraph matches the component snapshot 1`] = `