@@ -59,6 +59,7 @@ directories=Directories | |||
directory=Directory | |||
display=Display | |||
download_verb=Download | |||
duplications=Duplications | |||
edit=Edit | |||
events=Events | |||
false=False |
@@ -2,10 +2,12 @@ define [ | |||
'backbone.marionette' | |||
'templates/component-viewer' | |||
'component-viewer/popup' | |||
'component-viewer/utils' | |||
], ( | |||
Marionette | |||
Templates | |||
Popup | |||
utils | |||
) -> | |||
$ = jQuery | |||
@@ -21,16 +23,20 @@ define [ | |||
goToFile: (e) -> | |||
key = $(e.currentTarget).data 'key' | |||
@options.main.addTransition key, 'duplication', [ | |||
{ | |||
key: 'org.codehaus.sonar:sonar-plugin-api:src/test/java/org/sonar/api/resources/ResourceTypeTree.java' | |||
name: 'ResourceTypeTree.java' | |||
active: true | |||
} | |||
{ | |||
key: 'org.codehaus.sonar:sonar-batch:src/main/java/org/sonar/batch/phases/PhaseExecutor.java' | |||
name: 'PhaseExecutor.java' | |||
active: false | |||
} | |||
], [] | |||
files = @options.main.source.get('duplicationFiles') | |||
@options.main.addTransition key, 'duplication', @collection.map (item) -> | |||
file = files[item.get('_ref')] | |||
x = utils.splitLongName file.name | |||
key: file.key | |||
name: x.name | |||
subname: x.dir | |||
active: file.key == key | |||
serializeData: -> | |||
files = @options.main.source.get('duplicationFiles') | |||
blocks = _.groupBy _.rest(@collection.toJSON()), '_ref' | |||
duplications = _.map blocks, (blocks, fileRef) -> | |||
blocks: blocks | |||
file: files[fileRef] | |||
duplications: duplications |
@@ -58,6 +58,8 @@ define [ | |||
'click .js-filter-covered-branches-it': 'filterByCoveredBranchesIT' | |||
'click .js-filter-uncovered-branches-it': 'filterByUncoveredBranchesIT' | |||
'click .js-filter-duplications': 'filterByDuplications' | |||
initialize: (options) -> | |||
options.main.settings.on 'change', => @changeSettings() | |||
@@ -176,6 +178,10 @@ define [ | |||
filterByUncoveredBranchesIT: (e) -> @filterLines e, 'filterByUncoveredBranchesIT' | |||
# Duplications | |||
filterByDuplications: (e) -> @filterLines e, 'filterByDuplications' | |||
serializeData: -> | |||
component = @options.main.component.toJSON() | |||
if component.measures |
@@ -5,6 +5,7 @@ define [ | |||
'component-viewer/workspace' | |||
'component-viewer/source' | |||
'component-viewer/header' | |||
'component-viewer/utils' | |||
'component-viewer/mockjax' | |||
], ( | |||
@@ -14,6 +15,7 @@ define [ | |||
WorkspaceView | |||
SourceView | |||
HeaderView | |||
utils | |||
) -> | |||
$ = jQuery | |||
@@ -24,9 +26,11 @@ define [ | |||
API_COVERAGE = "#{baseUrl}/api/coverage/show" | |||
API_SCM = "#{baseUrl}/api/sources/scm" | |||
API_MEASURES = "#{baseUrl}/api/resources" | |||
API_DUPLICATIONS = "#{baseUrl}/api/duplications/show" | |||
LINES_AROUND_ISSUE = 4 | |||
LINES_AROUND_COVERED_LINE = 1 | |||
LINES_AROUND_DUPLICATION = 1 | |||
SOURCE_METRIC_LIST = 'accessors,classes,functions,statements,' + | |||
'ncloc,lines,' + | |||
@@ -104,6 +108,7 @@ define [ | |||
requestComponent: (key) -> | |||
$.get API_COMPONENT, key: key, (data) => | |||
@component.set data | |||
@component.set 'dir', utils.splitLongName(data.path).dir | |||
requestMeasures: (key) -> | |||
@@ -150,6 +155,12 @@ define [ | |||
@source.set coverage: data.coverage | |||
requestDuplications: (key) -> | |||
$.get API_DUPLICATIONS, key: key, (data) => | |||
@source.set duplications: data.duplications | |||
@source.set duplicationFiles: data.files | |||
open: (key) -> | |||
@workspace.reset [ key: key ] | |||
@_open key | |||
@@ -222,7 +233,10 @@ define [ | |||
showDuplications: (store = false) -> | |||
@settings.set 'duplications', true | |||
@storeSettings() if store | |||
@sourceView.render() | |||
unless @source.has 'duplications' | |||
@requestDuplications(@key).done => @sourceView.render() | |||
else | |||
@sourceView.render() | |||
hideDuplications: (store = false) -> | |||
@@ -246,6 +260,12 @@ define [ | |||
@sourceView.render() | |||
showAllLines: -> | |||
@sourceView.resetShowBlocks() | |||
@sourceView.showBlocks.push from: 0, to: _.size @source.get 'source' | |||
@sourceView.render() | |||
filterLinesByIssues: -> | |||
issues = @source.get 'issues' | |||
@sourceView.resetShowBlocks() | |||
@@ -338,9 +358,29 @@ define [ | |||
filterByUncoveredBranchesIT: -> @filterByCoverageIT (c) -> c[3]? && c[4]? && (c[3] > c[4]) | |||
# Duplications | |||
filterByDuplications: -> | |||
unless @source.has 'duplications' | |||
@requestDuplications(@key).done => @_filterByDuplications() | |||
else | |||
@_filterByDuplications() | |||
_filterByDuplications: -> | |||
duplications = @source.get 'duplications' | |||
@settings.set 'duplications', true | |||
@sourceView.resetShowBlocks() | |||
duplications.forEach (d) => | |||
lineFrom = d.blocks[0].from | |||
lineTo = lineFrom + d.blocks[0].size | |||
@sourceView.addShowBlock lineFrom - LINES_AROUND_DUPLICATION, lineTo + LINES_AROUND_DUPLICATION | |||
@sourceView.render() | |||
addTransition: (key, transition, optionsForCurrent, options) -> | |||
if optionsForCurrent? | |||
last = @workspace.at(@workspace.length - 1) | |||
last.set 'options', optionsForCurrent if last | |||
@workspace.add key: key, transition: transition, options: options | |||
@_open key | |||
@_open key | |||
@showAllLines() |
@@ -131,9 +131,11 @@ define [ | |||
showDuplicationPopup: (e) -> | |||
e.stopPropagation() | |||
$('body').click() | |||
index = $(e.currentTarget).data 'index' | |||
popup = new DuplicationPopupView | |||
triggerEl: $(e.currentTarget) | |||
main: @options.main | |||
collection: new Backbone.Collection @model.get('duplications')[index - 1].blocks | |||
popup.render() | |||
@@ -165,8 +167,7 @@ define [ | |||
expandAll: -> | |||
@showBlocks.push from: 0, to: _.size @model.get 'source' | |||
@render() | |||
@options.main.showAllLines() | |||
toggleTimeChangePopup: (e) -> | |||
@@ -196,6 +197,22 @@ define [ | |||
source | |||
augmentWithDuplications: (source) -> | |||
duplications = @model.get 'duplications' | |||
if duplications | |||
duplications.forEach (d, i) -> | |||
lineFrom = d.blocks[0].from | |||
lineTo = d.blocks[0].from + d.blocks[0].size | |||
source.forEach (line) -> | |||
lineDuplications = line.duplications || [] | |||
if line.lineNumber >= lineFrom && (line.lineNumber <= lineTo) | |||
lineDuplications.push i + 1 | |||
else | |||
lineDuplications.push false | |||
line.duplications = lineDuplications | |||
source | |||
getSCMForLine: (lineNumber) -> | |||
scm = @model.get('scm') || [] | |||
closest = -1 | |||
@@ -238,6 +255,8 @@ define [ | |||
if @options.main.settings.get 'coverage' | |||
source = @augmentWithCoverage source | |||
if @options.main.settings.get 'duplications' | |||
source = @augmentWithDuplications source | |||
if @options.main.settings.get 'scm' | |||
source = @augmentWithSCM source | |||
@@ -0,0 +1,6 @@ | |||
define -> | |||
splitLongName: (longName) -> | |||
lastSeparator = longName.lastIndexOf '/' | |||
dir: longName.substr 0, lastSeparator | |||
name: longName.substr lastSeparator + 1 |
@@ -25,7 +25,7 @@ define [ | |||
toggleWorkspace: -> | |||
@options.main.toggleWorkspace() | |||
@options.main.toggleWorkspace true | |||
goToWorkspaceItem: (e) -> |
@@ -1,19 +1,14 @@ | |||
<div class="component-viewer-popup-section"> | |||
<div class="component-viewer-popup-section-title"> | |||
2 duplications | |||
{{#each duplications}} | |||
<div class="component-viewer-popup-section"> | |||
<a class="component-viewer-popup-test-file link-action" data-key="{{file.key}}" title="{{file.name}}"> | |||
{{file.name}} | |||
</a> | |||
<ul class="component-viewer-popup-list"> | |||
{{#each blocks}} | |||
<li>Lines: {{from}} – {{sum from size}}</li> | |||
{{/each}} | |||
</ul> | |||
</div> | |||
<ul class="component-viewer-popup-list"> | |||
<li> | |||
<a data-key="org.codehaus.sonar:sonar-plugin-api:src/main/java/org/sonar/api/resources/ResourceTypeTree.java"> | |||
<span>ResourceTypeTree.java</span> | |||
</a> | |||
</li> | |||
<li> | |||
<a data-key="org.codehaus.sonar:sonar-batch:src/main/java/org/sonar/batch/phases/PhaseExecutor.java"> | |||
<span>PhaseExecutor.java</span> | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
{{/each}} | |||
<div class="component-viewer-popup-arrow"></div> |
@@ -1,17 +1,9 @@ | |||
<div class="component-viewer-header-expanded-bar-section"> | |||
<div class="component-viewer-header-expanded-bar-section-title">Duplications</div> | |||
<ul class="component-viewer-header-expanded-bar-section-list"> | |||
<li><a class="item"> | |||
<span>Lines</span> | |||
<span class="number">76</span> | |||
</a></li> | |||
<li><a class="item"> | |||
<span>Duplicated Lines</span> | |||
<span class="number">16</span> | |||
</a></li> | |||
<li><a class="item"> | |||
<span>Duplicated Blocks</span> | |||
<span class="number">2</span> | |||
</a></li> | |||
</ul> | |||
</div> | |||
{{#with component.msr}} | |||
<div class="component-viewer-header-expanded-bar-section"> | |||
<div class="component-viewer-header-expanded-bar-section-title">{{t 'duplications'}}</div> | |||
<ul class="component-viewer-header-expanded-bar-section-list"> | |||
{{{componentViewerHeaderLink duplicated_blocks 'duplicated_blocks' 'js-filter-duplications'}}} | |||
{{{componentViewerHeaderLink duplicated_lines 'duplicated_lines' 'js-filter-duplications'}}} | |||
</ul> | |||
</div> | |||
{{/with}} |
@@ -22,7 +22,7 @@ | |||
{{#if ../../settings.duplications}} | |||
<td class="stat duplications"> | |||
{{#each duplications}} | |||
<span class="duplication {{#if this}}duplication-exists{{/if}}"></span> | |||
<span class="duplication {{#if this}}duplication-exists{{/if}}" data-index="{{this}}"></span> | |||
{{/each}} | |||
</td> | |||
{{/if}} |
@@ -11,12 +11,15 @@ | |||
{{#eachReverse workspace}} | |||
<li class="component-viewer-workspace-item"> | |||
{{qualifierIcon component.q}} <a data-key="{{key}}">{{component.name}}</a> | |||
{{#if component.dir}} | |||
<div class="text-ellipsis subtitle">{{component.dir}}</div> | |||
{{/if}} | |||
{{#if options}} | |||
<ul class="component-viewer-workspace-options"> | |||
{{#each options}} | |||
<li class="component-viewer-workspace-option {{#if active}}active{{/if}}"> | |||
<a data-workspace-key="{{../key}}" data-key="{{key}}">{{name}}</a> | |||
{{#if subname}}<div class="subtitle">{{subname}}</div>{{/if}} | |||
<a class="text-ellipsis" data-workspace-key="{{../key}}" data-key="{{key}}">{{name}}</a> | |||
{{#if subname}}<div class="text-ellipsis subtitle">{{subname}}</div>{{/if}} | |||
</li> | |||
{{/each}} | |||
</ul> |
@@ -132,6 +132,10 @@ define(['handlebars', 'moment'], function (Handlebars, moment) { | |||
return ret; | |||
}); | |||
Handlebars.registerHelper('sum', function(a, b) { | |||
return a + b; | |||
}); | |||
Handlebars.registerHelper('dashboardUrl', function(componentKey, componentQualifier) { | |||
var url = '/dashboard/index/' + decodeURIComponent(componentKey); | |||
if (componentQualifier === 'FIL' || componentQualifier === 'CLA') { |
@@ -1,7 +1,7 @@ | |||
@import "variables"; | |||
@import "mixins"; | |||
@workspaceWidth: 220px; | |||
@workspaceWidth: 250px; | |||
.component-viewer { | |||
@@ -31,7 +31,7 @@ | |||
position: relative; | |||
display: table-cell; | |||
vertical-align: top; | |||
padding-right: 30px; | |||
min-width: 30px; | |||
border: 1px solid @barBorderColor; | |||
background-color: @barBackgroundColor; | |||
@@ -66,7 +66,7 @@ | |||
.component-viewer-workspace-options { | |||
margin-top: 5px; | |||
margin-left: 21px; | |||
margin-left: 7px; | |||
padding-left: 10px; | |||
border-left: 3px solid darken(@barBorderColor, 10%); | |||
} | |||
@@ -79,7 +79,7 @@ | |||
.component-viewer-workspace-toggle { | |||
position: absolute; | |||
top: 0; right: -30px; | |||
top: 0; right: 0; | |||
.size(30px, 30px); | |||
.trans; | |||
@@ -45,6 +45,12 @@ select, input, button, textarea { | |||
.nowrap { white-space: nowrap; } | |||
.text-ellipsis { | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
} | |||
/* | |||
* Links |