Flow Coverage Report - src/components/SecondaryPanes/Breakpoints.js

FilenamePercentTotalCoveredUncovered
src/components/SecondaryPanes/Breakpoints.js 41 % 319 132 187
x
 
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
5
// @flow
6
import React, { Component } from "react";
7
import { bindActionCreators } from "redux";
8
import { connect } from "react-redux";
9
import * as I from "immutable";
10
import classnames from "classnames";
11
import { createSelector } from "reselect";
12
import { sortBy } from "lodash";
13
14
import actions from "../../actions";
15
import CloseButton from "../shared/Button/Close";
16
import { endTruncateStr } from "../../utils/utils";
17
import { features } from "../../utils/prefs";
18
import { getFilename } from "../../utils/source";
19
import {
20
  getSources,
21
  getSourceInSources,
22
  getBreakpoints,
23
  getPauseReason,
24
  getTopFrame
25
} from "../../selectors";
26
import { isInterrupted } from "../../utils/pause";
27
import { makeLocationId } from "../../utils/breakpoint";
28
import showContextMenu from "./BreakpointsContextMenu";
29
30
import type { Breakpoint, Location } from "../../types";
31
32
import "./Breakpoints.css";
33
34
type LocalBreakpoint = Breakpoint & {
35
  location: any,
36
  isCurrentlyPaused: boolean,
37
  locationId: string
38
};
39
40
type BreakpointsMap = I.Map<string, LocalBreakpoint>;
41
42
type Props = {
43
  breakpoints: BreakpointsMap,
44
  enableBreakpoint: Location => void,
45
  disableBreakpoint: Location => void,
46
  selectLocation: Object => void,
47
  removeBreakpoint: string => void,
48
  removeAllBreakpoints: () => void,
49
  removeBreakpoints: BreakpointsMap => void,
50
  toggleBreakpoints: (boolean, BreakpointsMap) => void,
51
  toggleAllBreakpoints: boolean => void,
52
  toggleDisabledBreakpoint: number => void,
53
  setBreakpointCondition: Location => void,
54
  openConditionalPanel: number => void
55
};
56
57
3x
function isCurrentlyPausedAtBreakpoint(frame, why, breakpoint) {
58
2x
  if (!frame || !isInterrupted(why)) {
59
    return false;
60
  }
61
62
2x
  const bpId = makeLocationId(breakpoint.location);
63
2x
  const pausedId = makeLocationId(frame.location);
64
  return bpId === pausedId;
65
}
66
67
1x
function getBreakpointFilename(source) {
68
5x
  return source && source.toJS ? getFilename(source.toJS()) : "";
69
}
70
71
3x
function renderSourceLocation(source, line, column) {
72
1x
  const filename = getBreakpointFilename(source);
73
5x
  const isWasm = source && source.isWasm;
74
4x
  const columnVal = features.columnBreakpoints && column ? `:${column}` : "";
75
1x
  const bpLocation = isWasm
76
3x
    ? `0x${line.toString(16).toUpperCase()}`
77
1x
    : `${line}${columnVal}`;
78
79
  if (!filename) {
80
    return null;
81
  }
82
83
  return (
84
    <div className="location">
85
      {`${endTruncateStr(filename, 30)}: ${bpLocation}`}
86
    </div>
87
  );
88
}
89
90
class Breakpoints extends Component<Props> {
91
  shouldComponentUpdate(nextProps, nextState) {
92
    const { breakpoints } = this.props;
93
1x
    return breakpoints !== nextProps.breakpoints;
94
  }
95
96
1x
  handleCheckbox(breakpoint) {
97
2x
    if (breakpoint.loading) {
98
      return;
99
    }
100
101
2x
    if (breakpoint.disabled) {
102
2x
      this.props.enableBreakpoint(breakpoint.location);
103
    } else {
104
2x
      this.props.disableBreakpoint(breakpoint.location);
105
    }
106
  }
107
108
1x
  selectBreakpoint(breakpoint) {
109
2x
    this.props.selectLocation(breakpoint.location);
110
  }
111
112
2x
  removeBreakpoint(event, breakpoint) {
113
2x
    event.stopPropagation();
114
2x
    this.props.removeBreakpoint(breakpoint.location);
115
  }
116
117
1x
  renderBreakpoint(breakpoint) {
118
3x
    const locationId = breakpoint.locationId;
119
4x
    const line = breakpoint.location.line;
120
4x
    const column = breakpoint.location.column;
121
3x
    const isCurrentlyPaused = breakpoint.isCurrentlyPaused;
122
3x
    const isDisabled = breakpoint.disabled;
123
5x
    const isConditional = !!breakpoint.condition;
124
3x
    const isHidden = breakpoint.hidden;
125
126
1x
    if (isHidden) {
127
      return;
128
    }
129
130
    return (
131
      <div
132
        className={classnames({
133
1x
          breakpoint,
134
1x
          paused: isCurrentlyPaused,
135
1x
          disabled: isDisabled,
136
1x
          "is-conditional": isConditional
137
        })}
138
1x
        key={locationId}
139
1x
        onClick={() => this.selectBreakpoint(breakpoint)}
140
1x
        onContextMenu={e =>
141
4x
          showContextMenu({ ...this.props, breakpoint, contextMenuEvent: e })
142
        }
143
      >
144
        <input
145
          type="checkbox"
146
          className="breakpoint-checkbox"
147
2x
          checked={!isDisabled}
148
1x
          onChange={() => this.handleCheckbox(breakpoint)}
149
3x
          onClick={ev => ev.stopPropagation()}
150
        />
151
2x
        <label className="breakpoint-label" title={breakpoint.text}>
152
5x
          {renderSourceLocation(breakpoint.location.source, line, column)}
153
        </label>
154
        <CloseButton
155
3x
          handleClick={ev => this.removeBreakpoint(ev, breakpoint)}
156
          tooltip={L10N.getStr("breakpoints.removeBreakpointTooltip")}
157
        />
158
      </div>
159
    );
160
  }
161
162
  render() {
163
    const { breakpoints } = this.props;
164
    const children =
165
2x
      breakpoints.size === 0 ? (
166
        <div className="pane-info">{L10N.getStr("breakpoints.none")}</div>
167
      ) : (
168
3x
        sortBy(
169
5x
          [...breakpoints.valueSeq()],
170
2x
          [
171
6x
            bp => getBreakpointFilename(bp.location.source),
172
6x
            bp => bp.location.line
173
2x
          ]
174
4x
        ).map(bp => this.renderBreakpoint(bp))
175
      );
176
177
    return <div className="pane breakpoints-list">{children}</div>;
178
  }
179
}
180
181
4x
function updateLocation(sources, frame, why, bp): LocalBreakpoint {
182
5x
  const source = getSourceInSources(sources, bp.location.sourceId);
183
3x
  const isCurrentlyPaused = isCurrentlyPausedAtBreakpoint(frame, why, bp);
184
2x
  const locationId = makeLocationId(bp.location);
185
186
5x
  const location = { ...bp.location, source };
187
4x
  const localBP = { ...bp, location, locationId, isCurrentlyPaused };
188
189
1x
  return localBP;
190
}
191
192
3x
const _getBreakpoints = createSelector(
193
1x
  getBreakpoints,
194
2x
  getSources,
195
1x
  getTopFrame,
196
1x
  getPauseReason,
197
5x
  (breakpoints, sources, frame, why) =>
198
4x
    breakpoints
199
8x
      .map(bp => updateLocation(sources, frame, why, bp))
200
12x
      .filter(bp => bp.location.source && !bp.location.source.isBlackBoxed)
201
1x
);
202
203
3x
export default connect(
204
7x
  (state, props) => ({ breakpoints: _getBreakpoints(state) }),
205
7x
  dispatch => bindActionCreators(actions, dispatch)
206
2x
)(Breakpoints);
207