Skip to content

Commit 8f8e777

Browse files
committed
Updated the package list and treemap to support the backend data provider.
Since the data for the package list is being provided by the backend with self nodes generated and no classes/methods, the PackageController needed to be updated to handle that. Also, instead of loading the full tree on page load, the front end now requests a "projected" tree from the backend when the selection state changes. This used to be the responsibility of the TreeProjector(.js), but is now handled by the scala side of things.
1 parent 53814ff commit 8f8e777

File tree

7 files changed

+231
-322
lines changed

7 files changed

+231
-322
lines changed

codepulse/src/main/resources/toserve/pages/traces/PackageController.js

Lines changed: 88 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -31,31 +31,27 @@
3131

3232
var widgets = {}
3333

34-
function eligibleForWidget(node){
35-
if(!node) return false
36-
37-
return node.kind == 'package' ||
38-
node.kind == 'group' ||
39-
node.kind == 'root'
40-
}
34+
// build this into a Map[node.id -> packageNode]
35+
// Note: the package tree doesn't include all nodes; instead, it includes
36+
// an 'otherDescendantIds' array, to represent all of the 'direct' descendants
37+
// of each package|group.
38+
var nodePackageParents = {}
4139

4240
// Get the partial selection state for the trace instrumentation flag, for nodes that
4341
// would exist in the package list. Note that <self> nodes will take their original
4442
// node's `id` and `traced` properties, and the original's `traced` will be set to
4543
// undefined. This function sets a `partialTraceSelection` value on nodes recursively,
4644
// with `1 = fully selected`, `0 = unselected`, and `undefined = partially selected`.
47-
(function calculatePartialTraceSelections(node){
45+
;(function calculatePartialTraceSelections(node){
4846
var isFullSelected = true,
4947
isPartialSelected = false
5048

5149
if(node.traced == 0) isFullSelected = false
5250

5351
node.children.forEach(function(kid){
54-
if(eligibleForWidget(kid)){
55-
var kidSelection = calculatePartialTraceSelections(kid)
56-
if(!kidSelection) isFullSelected = false
57-
if(kidSelection || kidSelection == undefined) isPartialSelected = true
58-
}
52+
var kidSelection = calculatePartialTraceSelections(kid)
53+
if(!kidSelection) isFullSelected = false
54+
if(kidSelection || kidSelection == undefined) isPartialSelected = true
5955
})
6056

6157
var selectionValue = isFullSelected ? 1 : isPartialSelected ? undefined : 0
@@ -66,69 +62,89 @@
6662
// special case: the root is never selected
6763
treeData.root.partialTraceSelection = 0
6864

65+
// walk the tree in order to calculate the `nodePackageParents` map.
66+
;(function calculateNodePackageParents(node, parent){
67+
if(parent) nodePackageParents[node.id] = parent
68+
69+
node.children.forEach(function(child){
70+
calculateNodePackageParents(child, node)
71+
})
72+
73+
if(node.otherDescendantIds) node.otherDescendantIds.forEach(function(childId){
74+
nodePackageParents[childId] = node
75+
})
76+
77+
})(treeData.root, undefined)
78+
6979
// initialize the `stateTemplate` and `widgets` maps
7080
// based on the package nodes in `treeData`
7181
;(function setupTreeHierarchy(packageParentNode, node){
72-
if(eligibleForWidget(node)){
7382

74-
var pw = new PackageWidget()
75-
widgets[node.id] = pw
83+
var pw = new PackageWidget()
84+
widgets[node.id] = pw
7685

77-
pw.instrumentationSelected(node.partialTraceSelection)
86+
pw.instrumentationSelected(node.partialTraceSelection)
7887

79-
pw.collapseChildren(/* collapsed = */true, /* animate = */false)
88+
pw.collapseChildren(/* collapsed = */true, /* animate = */false)
8089

81-
stateTemplate[node.id] = pw.selectedProp
82-
pw.selectionClicks.onValue(function(){
83-
handleSelectionClick(node, pw)
84-
})
90+
stateTemplate[node.id] = pw.selectedProp
91+
pw.selectionClicks.onValue(function(){
92+
handleSelectionClick(node, pw)
93+
})
8594

86-
instrumentedTemplate[node.id] = pw.instrumentationSelectedProp
87-
pw.instrumentationSelectedClicks.onValue(function(){
88-
handleInstrumentationSelectionClick(node, pw)
89-
})
95+
instrumentedTemplate[node.id] = pw.instrumentationSelectedProp
96+
pw.instrumentationSelectedClicks.onValue(function(){
97+
handleInstrumentationSelectionClick(node, pw)
98+
})
9099

91-
pw.uiParts.collapser.click(function(event){
92-
pw.collapseChildren('toggle', true)
93-
event.stopPropagation()
94-
})
100+
pw.uiParts.collapser.click(function(event){
101+
pw.collapseChildren('toggle', true)
102+
event.stopPropagation()
103+
})
95104

96-
if(node.kind == 'root'){
97-
pw.uiParts.main.appendTo($totalsContainer)
98-
pw.abbreviatedLabel('Overall Coverage')
99-
pw.selectable(false)
100-
pw.instrumentationSelectable(false)
101-
}
102105

103-
if(node.kind == 'group' || node.kind == 'package'){
104-
if(packageParentNode){
105-
widgets[packageParentNode.id].children.add(pw)
106-
} else {
107-
pw.uiParts.main.appendTo($container)
108-
}
106+
if(node.kind == 'root'){
107+
pw.uiParts.main.appendTo($totalsContainer)
108+
pw.abbreviatedLabel('Overall Coverage')
109+
pw.selectable(false)
110+
pw.instrumentationSelectable(false)
111+
112+
var totalMethodCount = 0
113+
node.children.forEach(function(child){
114+
totalMethodCount += child.methodCount
115+
})
116+
pw.methodCount(totalMethodCount)
117+
} else {
118+
119+
pw.methodCount(node.methodCount)
109120

110-
if(node.isSelfNode){
111-
pw.fullLabel(node.name).abbreviatedLabel(node.name)
112-
} else {
113-
var abbrevName
121+
if(packageParentNode){
122+
widgets[packageParentNode.id].children.add(pw)
123+
} else {
124+
pw.uiParts.main.appendTo($container)
125+
}
114126

115-
if (node.kind != 'group' && packageParentNode && packageParentNode.kind == 'group')
116-
abbrevName = node.name
117-
else {
118-
var parentName = packageParentNode ? packageParentNode.name : '',
119-
abbrevName = node.name.substr(parentName.length)
120-
}
127+
if(node.isSelfNode){
128+
pw.fullLabel(node.label).abbreviatedLabel(node.label)
129+
} else {
130+
var abbrevName
121131

122-
pw.fullLabel(node.name).abbreviatedLabel(abbrevName)
132+
if (node.kind != 'group' && packageParentNode && packageParentNode.kind == 'group')
133+
abbrevName = node.label
134+
else {
135+
var parentName = packageParentNode ? packageParentNode.label : '',
136+
abbrevName = node.label.substr(parentName.length)
123137
}
138+
139+
pw.fullLabel(node.label).abbreviatedLabel(abbrevName)
124140
}
125141
}
126142

127-
;(node.children || [])
143+
node.children
128144
.sort(function(a,b){
129-
// alphabetic sort by node.name
130-
var an = a.name.toUpperCase(),
131-
bn = b.name.toUpperCase()
145+
// alphabetic sort by node.label
146+
var an = a.label.toUpperCase(),
147+
bn = b.label.toUpperCase()
132148

133149
if(an < bn) return -1
134150
if(an > bn) return 1
@@ -141,19 +157,12 @@
141157

142158
})(undefined, treeData.root)
143159

144-
function hasPackageChild(node){
145-
var found = false
146-
;(node.children || []).forEach(function(child){
147-
if(child.kind == 'package') found = true
148-
})
149-
return found
150-
}
151-
152160
// Disable all of the widgets while the trace is running
153161
Trace.running.onValue(function(isRunning){
154162
for(var id in widgets){
155163
var pw = widgets[id],
156164
node = treeData.getNode(id)
165+
157166
if(node.kind != 'root'){
158167
pw.instrumentationSelectable(!isRunning)
159168
}
@@ -219,9 +228,6 @@
219228
/*set*/ function(w,s){ return w.instrumentationSelected(s) }
220229
)
221230

222-
// set the `methodCount` property for all widgets
223-
applyMethodCounts(treeData, widgets)
224-
225231
/**
226232
* Exposes the selection state of each of the widgets, as a
227233
* Map[package.id -> isSelected]
@@ -270,61 +276,20 @@
270276
}
271277

272278
this.highlightPackages = function(methodIds){
273-
highlightPackages(treeData, widgets, methodIds)
279+
highlightPackages(treeData, widgets, methodIds, nodePackageParents)
274280
}
275281

276282
this.applyMethodCoverage = function(coverageRecords, activeRecordings){
277-
applyMethodCoverage(treeData, widgets, coverageRecords, activeRecordings)
278-
}
279-
}
280-
281-
// Returns an array of package-kind Tree Nodes.
282-
function findPackages(treeData){
283-
var a = []
284-
a.push(treeData.root)
285-
treeData.forEachNode(function(node){
286-
if(node.kind == 'package'){
287-
a.push(node)
288-
}
289-
})
290-
return a
291-
}
292-
293-
// Compute and set the `methodCount` property for all of the widgets
294-
function applyMethodCounts(treeData, widgets){
295-
function recurse(node){
296-
var count = 0
297-
298-
if(node.kind == 'method') ++count
299-
300-
;(node.children || []).forEach(function(kid){
301-
count += recurse(kid)
302-
})
303-
304-
if(widgets[node.id]) widgets[node.id].methodCount(count)
305-
306-
return count
307-
308-
/* Alternate Strategy:
309-
* Only count methods that fall directly beneath each package;
310-
* This means that 'com.foo' would not include methods defined in
311-
* 'com.foo.bar'. To do this, uncomment the following, and comment
312-
* out the above return statement.
313-
*/
314-
/*
315-
if(node.kind == 'package') return 0
316-
else return count
317-
*/
283+
applyMethodCoverage(treeData, widgets, coverageRecords, activeRecordings, nodePackageParents)
318284
}
319-
recurse(treeData.root)
320285
}
321286

322287
// Trigger a `flashHighlight` on the appropriate package widgets
323288
//
324289
// @param treeData - the tree structure being managed
325290
// @param widgets - a Map[packageNode.id -> PackageWidget]
326291
// @param methodIds - an Array[method.id]
327-
function highlightPackages(treeData, widgets, methodIds){
292+
function highlightPackages(treeData, widgets, methodIds, nodePackageParents){
328293
var toHighlight = {}
329294

330295

@@ -343,7 +308,9 @@
343308
}
344309

345310
methodIds.forEach(function(id){
346-
bubbleUp(treeData.getNode(id))
311+
var bubbleFrom = treeData.getNode(id) || nodePackageParents[id]
312+
// bubbleUp(treeData.getNode(id))
313+
bubbleUp(bubbleFrom)
347314
})
348315

349316
for(var id in toHighlight){
@@ -365,14 +332,14 @@
365332
* @param activeRecordings - A set of recording IDs. Coverage only
366333
* counts if the recording that covered a method was selected.
367334
*/
368-
function applyMethodCoverage(treeData, widgets, coverageRecords, activeRecordings){
335+
function applyMethodCoverage(treeData, widgets, coverageRecords, activeRecordings, nodePackageParents){
369336

370337
// If anything is selected, use that selection to determine coverage.
371338
// If nothing is selected, all coverage data counts (i.e. 'all activity' is what's covered)
372339
var noSelectedRecordings = activeRecordings.empty()
373340

374-
function isCoveredBySelectedRecording(node){
375-
var records = coverageRecords[node.id]
341+
function isCoveredBySelectedRecording(nodeId){
342+
var records = coverageRecords[nodeId]
376343
if(!records) return false
377344

378345
if(noSelectedRecordings){
@@ -393,7 +360,11 @@
393360
// if(coverageRecords[node.id] && coverageRecords[node.id].length){
394361
// coverage += 1
395362
// }
396-
coverage += isCoveredBySelectedRecording(node)
363+
coverage += isCoveredBySelectedRecording(node.id)
364+
365+
if(node.otherDescendantIds) node.otherDescendantIds.forEach(function(id){
366+
coverage += isCoveredBySelectedRecording(id)
367+
})
397368

398369
// also include the sum of the childrens' coverages (recursive)
399370
;(node.children || []).forEach(function(kid){

codepulse/src/main/resources/toserve/pages/traces/TraceAPI.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@
151151
function requestStart(){ postCommand('/start') }
152152
function requestEnd(){ postCommand('/end') }
153153

154+
155+
154156
exports.TraceAPI = {
155157
'requestStart': function(){ postCommand('/start') },
156158
'requestEnd': function(){ postCommand('/end') },
@@ -190,8 +192,17 @@
190192
return repeatingGetCommand({ url: commandPath('/accumulation'), getData: null, interval: interval })
191193
},
192194

193-
'loadTreemap': function(callback){
194-
d3.json(commandPath('/treemap.json'), callback)
195+
'loadPackageTree': function(callback){
196+
d3.json(commandPath('/packageTree'), function(trees){
197+
callback(new TreeData(trees))
198+
})
199+
},
200+
201+
'projectTreeMap': function(nodesArray, callback){
202+
var nodesString = nodesArray.join(',')
203+
postCommand('/treemap', {nodes: nodesString}, function(trees){
204+
callback(new TreeData(trees))
205+
})
195206
},
196207

197208
'renameTrace': function(newName, callback){

0 commit comments

Comments
 (0)