1 | 'use strict'
|
2 |
|
3 | const d3 = require('./d3.js')
|
4 | const icons = require('./icons.js')
|
5 | const categories = require('./categories.js')
|
6 | const EventEmitter = require('events')
|
7 |
|
8 | function getTextNodeBoundingRect (textNode) {
|
9 | const range = document.createRange()
|
10 | range.selectNode(textNode)
|
11 | return range.getBoundingClientRect()
|
12 | }
|
13 |
|
14 | class Issue {
|
15 | constructor (id, detected, title) {
|
16 | this.graphId = `graph-${id}`
|
17 | this.detected = detected
|
18 | this.title = title
|
19 | }
|
20 | }
|
21 |
|
22 | class Alert extends EventEmitter {
|
23 | constructor () {
|
24 | super()
|
25 |
|
26 | this.analysis = null
|
27 | this.fullTitleWidth = null
|
28 |
|
29 | this.container = d3.select('#alert')
|
30 | this.container.classed('open', true)
|
31 |
|
32 | this.summary = this.container.append('div')
|
33 | .classed('summary', true)
|
34 |
|
35 | this.alert = this.summary.append('svg')
|
36 | .classed('alert', true)
|
37 | .call(icons.insertIcon('warning'))
|
38 |
|
39 | this.title = this.summary.append('div')
|
40 | .classed('title', true)
|
41 |
|
42 | this.titleTextNode = document.createTextNode('')
|
43 | this.title.node().appendChild(this.titleTextNode)
|
44 |
|
45 | this.details = this.container.append('ul')
|
46 | .classed('details', true)
|
47 | }
|
48 |
|
49 | _setTitleText (title) {
|
50 | this.titleTextNode.textContent = `Detected ${title}`
|
51 | }
|
52 |
|
53 | setData (data) {
|
54 | this.analysis = data.analysis
|
55 |
|
56 |
|
57 | const content = categories.getContent(this.analysis.issueCategory)
|
58 | this.container.classed('has-issue', content.issue)
|
59 |
|
60 |
|
61 | const issues = this.analysis.issues
|
62 | const memory = issues.memory.external !== 'none' ||
|
63 | issues.memory.heapTotal !== 'none' ||
|
64 | issues.memory.heapUsage !== 'none' ||
|
65 | issues.memory.rss !== 'none'
|
66 |
|
67 | const issuesAsData = [
|
68 | new Issue('cpu', issues.cpu !== 'none', 'CPU Usage'),
|
69 | new Issue('memory', memory, 'Memory Usage'),
|
70 | new Issue('delay', issues.delay !== 'none', 'Event Loop Delay'),
|
71 | new Issue('handles', issues.handles !== 'none', 'Active Handles')
|
72 | ].filter((issue) => issue.detected)
|
73 |
|
74 | this.details
|
75 | .selectAll('li')
|
76 | .data(issuesAsData)
|
77 | .enter()
|
78 | .append('li')
|
79 | .on('click', (d) => this.emit('click', d.graphId))
|
80 | .on('mouseover', (d) => this.emit('hover-in', d.graphId))
|
81 | .on('mouseout', (d) => this.emit('hover-out', d.graphId))
|
82 | .append('span')
|
83 | .text((d) => d.title)
|
84 |
|
85 |
|
86 | this._setTitleText(content.title)
|
87 | this.fullTitleWidth = getTextNodeBoundingRect(this.titleTextNode).width
|
88 | }
|
89 |
|
90 | draw () {
|
91 | const content = categories.getContent(this.analysis.issueCategory)
|
92 |
|
93 |
|
94 | const titleNode = this.title.node()
|
95 | if (parseInt(window.getComputedStyle(titleNode).width) < this.fullTitleWidth) {
|
96 | this._setTitleText(content.issue ? 'issue' : 'no issue')
|
97 | } else {
|
98 | this._setTitleText(content.title)
|
99 | }
|
100 | }
|
101 | }
|
102 |
|
103 | module.exports = new Alert()
|