summaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/coffee/component-viewer/header.coffee3
-rw-r--r--sonar-server/src/main/coffee/component-viewer/header/coverage-header.coffee70
-rw-r--r--sonar-server/src/main/coffee/component-viewer/header/issues-header.coffee1
-rw-r--r--sonar-server/src/main/coffee/component-viewer/header/scm-header.coffee36
-rw-r--r--sonar-server/src/main/coffee/component-viewer/main.coffee37
-rw-r--r--sonar-server/src/main/coffee/component-viewer/mixins/main-coverage.coffee74
-rw-r--r--sonar-server/src/main/coffee/component-viewer/mixins/main-duplications.coffee18
-rw-r--r--sonar-server/src/main/coffee/component-viewer/mixins/main-issues.coffee10
-rw-r--r--sonar-server/src/main/coffee/component-viewer/mixins/main-scm.coffee62
-rw-r--r--sonar-server/src/main/coffee/component-viewer/source.coffee49
-rw-r--r--sonar-server/src/main/coffee/component-viewer/time-changes-popup.coffee1
-rw-r--r--sonar-server/src/main/hbs/component-viewer/header.hbs7
-rw-r--r--sonar-server/src/main/hbs/component-viewer/header/coverage-header.hbs105
-rw-r--r--sonar-server/src/main/hbs/component-viewer/header/issues-header.hbs29
-rw-r--r--sonar-server/src/main/hbs/component-viewer/header/scm-header.hbs5
-rw-r--r--sonar-server/src/main/hbs/component-viewer/source.hbs6
-rw-r--r--sonar-server/src/main/hbs/component-viewer/time-changes-popup.hbs2
-rw-r--r--sonar-server/src/main/js/common/handlebars-extensions.js12
-rw-r--r--sonar-server/src/main/js/translate.js7
-rw-r--r--sonar-server/src/main/less/component-viewer.less5
20 files changed, 385 insertions, 154 deletions
diff --git a/sonar-server/src/main/coffee/component-viewer/header.coffee b/sonar-server/src/main/coffee/component-viewer/header.coffee
index b6f84d4ba0f..f0487c4b8fa 100644
--- a/sonar-server/src/main/coffee/component-viewer/header.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/header.coffee
@@ -6,6 +6,7 @@ define [
'component-viewer/header/issues-header'
'component-viewer/header/coverage-header'
'component-viewer/header/duplications-header'
+ 'component-viewer/header/scm-header'
'component-viewer/header/tests-header'
'common/handlebars-extensions'
@@ -17,6 +18,7 @@ define [
IssuesHeaderView
CoverageHeaderView
DuplicationsHeaderView
+ SCMHeaderView
TestsHeaderView
) ->
@@ -28,6 +30,7 @@ define [
{ scope: 'issues', view: IssuesHeaderView }
{ scope: 'coverage', view: CoverageHeaderView }
{ scope: 'duplications', view: DuplicationsHeaderView }
+ { scope: 'scm', view: SCMHeaderView }
{ scope: 'tests', view: TestsHeaderView }
]
diff --git a/sonar-server/src/main/coffee/component-viewer/header/coverage-header.coffee b/sonar-server/src/main/coffee/component-viewer/header/coverage-header.coffee
index 39f8f8e8189..ecf1b4b0618 100644
--- a/sonar-server/src/main/coffee/component-viewer/header/coverage-header.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/header/coverage-header.coffee
@@ -2,18 +2,24 @@ define [
'backbone.marionette'
'templates/component-viewer'
'component-viewer/header/base-header'
+ 'component-viewer/time-changes-popup'
], (
Marionette
Templates
BaseHeaderView
+ TimeChangesPopupView
) ->
+ $ = jQuery
+
class extends BaseHeaderView
template: Templates['coverage-header']
events:
+ 'click .js-coverage-time-changes': 'coverageTimeChanges'
+
'click .js-filter-lines-to-cover': 'filterByLinesToCover'
'click .js-filter-uncovered-lines': 'filterByUncoveredLines'
'click .js-filter-branches-to-cover': 'filterByBranchesToCover'
@@ -24,16 +30,56 @@ define [
'click .js-filter-uncovered-branches-it': 'filterByUncoveredBranchesIT'
- filterByLinesToCover: (e) -> @header.filterLines e, 'filterByLinesToCover'
- filterByCoveredLines: (e) -> @header.filterLines e, 'filterByCoveredLines'
- filterByUncoveredLines: (e) -> @header.filterLines e, 'filterByUncoveredLines'
- filterByBranchesToCover: (e) -> @header.filterLines e, 'filterByBranchesToCover'
- filterByCoveredBranches: (e) -> @header.filterLines e, 'filterByCoveredBranches'
- filterByUncoveredBranches: (e) -> @header.filterLines e, 'filterByUncoveredBranches'
+ coverageTimeChanges: (e) ->
+ e.stopPropagation()
+ $('body').click()
+ popup = new TimeChangesPopupView
+ triggerEl: $(e.currentTarget)
+ main: @options.main
+ bottom: true
+ popup.render()
+ popup.on 'change', (period) => @main.enableSCMPeriod period
+
+
+ filterByLinesToCover: (e) ->
+ @header.filterLines e, 'filterByLinesToCover'
+ @state.set 'activeHeaderItem', '.js-filter-lines-to-cover'
+
+
+ filterByUncoveredLines: (e) ->
+ @header.filterLines e, 'filterByUncoveredLines'
+ @state.set 'activeHeaderItem', '.js-filter-uncovered-lines'
+
+
+ filterByBranchesToCover: (e) ->
+ @header.filterLines e, 'filterByBranchesToCover'
+ @state.set 'activeHeaderItem', '.js-filter-branches-to-cover'
+
+
+ filterByUncoveredBranches: (e) ->
+ @header.filterLines e, 'filterByUncoveredBranches'
+ @state.set 'activeHeaderItem', '.js-filter-uncovered-branches'
+
+
+ filterByLinesToCoverIT: (e) ->
+ @header.filterLines e, 'filterByLinesToCoverIT'
+ @state.set 'activeHeaderItem', '.js-filter-lines-to-cover-it'
+
+
+ filterByUncoveredLinesIT: (e) ->
+ @header.filterLines e, 'filterByUncoveredLinesIT'
+ @state.set 'activeHeaderItem', '.js-filter-uncovered-lines-it'
+
+
+ filterByBranchesToCoverIT: (e) ->
+ @header.filterLines e, 'filterByBranchesToCoverIT'
+ @state.set 'activeHeaderItem', '.js-filter-branches-to-cover-it'
+
+
+ filterByUncoveredBranchesIT: (e) ->
+ @header.filterLines e, 'filterByUncoveredBranchesIT'
+ @state.set 'activeHeaderItem', '.js-filter-uncovered-branches-it'
+
- filterByLinesToCoverIT: (e) -> @header.filterLines e, 'filterByLinesToCoverIT'
- filterByCoveredLinesIT: (e) -> @header.filterLines e, 'filterByCoveredLinesIT'
- filterByUncoveredLinesIT: (e) -> @header.filterLines e, 'filterByUncoveredLinesIT'
- filterByBranchesToCoverIT: (e) -> @header.filterLines e, 'filterByBranchesToCoverIT'
- filterByCoveredBranchesIT: (e) -> @header.filterLines e, 'filterByCoveredBranchesIT'
- filterByUncoveredBranchesIT: (e) -> @header.filterLines e, 'filterByUncoveredBranchesIT' \ No newline at end of file
+ serializeData: ->
+ _.extend super, period: @state.get('period')?.toJSON() \ No newline at end of file
diff --git a/sonar-server/src/main/coffee/component-viewer/header/issues-header.coffee b/sonar-server/src/main/coffee/component-viewer/header/issues-header.coffee
index 13989aa78d1..f9b20516a87 100644
--- a/sonar-server/src/main/coffee/component-viewer/header/issues-header.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/header/issues-header.coffee
@@ -48,6 +48,7 @@ define [
triggerEl: $(e.currentTarget)
main: @options.main
bottom: true
+ prefix: 'Added'
popup.render()
popup.on 'change', (period) => @main.enableIssuesPeriod period
diff --git a/sonar-server/src/main/coffee/component-viewer/header/scm-header.coffee b/sonar-server/src/main/coffee/component-viewer/header/scm-header.coffee
new file mode 100644
index 00000000000..a44ad648b6c
--- /dev/null
+++ b/sonar-server/src/main/coffee/component-viewer/header/scm-header.coffee
@@ -0,0 +1,36 @@
+define [
+ 'backbone.marionette'
+ 'templates/component-viewer'
+ 'component-viewer/header/base-header'
+ 'component-viewer/time-changes-popup'
+], (
+ Marionette
+ Templates
+ BaseHeaderView
+ TimeChangesPopupView
+) ->
+
+ $ = jQuery
+
+
+ class extends BaseHeaderView
+ template: Templates['scm-header']
+
+
+ events:
+ 'click .js-scm-time-changes': 'scmTimeChanges'
+
+
+ scmTimeChanges: (e) ->
+ e.stopPropagation()
+ $('body').click()
+ popup = new TimeChangesPopupView
+ triggerEl: $(e.currentTarget)
+ main: @options.main
+ bottom: true
+ popup.render()
+ popup.on 'change', (period) => @main.enableSCMPeriod period
+
+
+ serializeData: ->
+ _.extend super, period: @state.get('period')?.toJSON()
diff --git a/sonar-server/src/main/coffee/component-viewer/main.coffee b/sonar-server/src/main/coffee/component-viewer/main.coffee
index ada2780e0a0..8d940e5b519 100644
--- a/sonar-server/src/main/coffee/component-viewer/main.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/main.coffee
@@ -50,6 +50,11 @@ define [
'complexity,function_complexity,' +
'comment_lines,comment_lines_density,public_api,public_undocumented_api,public_documented_api_density'
+ NEW_SOURCE_METRIC_LIST = 'new_accessors,classes,functions,statements,' +
+ 'ncloc,lines,' +
+ 'complexity,function_complexity,' +
+ 'comment_lines,comment_lines_density,public_api,public_undocumented_api,public_documented_api_density'
+
COVERAGE_METRIC_LIST = 'coverage,line_coverage,lines_to_cover,covered_lines,uncovered_lines,' +
'branch_coverage,conditions_to_cover,uncovered_conditions,' +
'it_coverage,it_line_coverage,it_lines_to_cover,it_covered_lines,it_uncovered_lines,' +
@@ -150,15 +155,19 @@ define [
if full
# Periods
@periods.reset [{}]
- data.periods.forEach (p) => @periods.add key: p[0], label: p[1], sinceDate: new Date p[2]
+ data.periods.forEach (p) =>
+ d = new Date p[2]
+ d.setHours 0, 0, 0, 0
+ p = @periods.add key: p[0], label: p[1], sinceDate: d
- requestMeasures: (key) ->
+ requestMeasures: (key, period = null) ->
@state.set 'hasMeasures', true
+ return @requestTrends(key, period) if period?
unless @component.get 'isUnitTest'
metrics = [SOURCE_METRIC_LIST, COVERAGE_METRIC_LIST, ISSUES_METRIC_LIST, DUPLICATIONS_METRIC_LIST].join ','
else
- metrics = [ISSUES_METRIC_LIST, TESTS_METRIC_LIST]
+ metrics = [ISSUES_METRIC_LIST, TESTS_METRIC_LIST].join ','
data = resource: key, metrics: metrics
$.get API_MEASURES, data, (data) =>
measuresList = data[0].msr || []
@@ -168,10 +177,30 @@ define [
@component.set 'measures', measures
+ requestTrends: (key, period) ->
+ unless @component.get 'isUnitTest'
+ metrics = COVERAGE_METRIC_LIST
+ else
+ metrics = ''
+ metrics = metrics.split(',').map((m) -> "new_#{m}").join ','
+ data = resource: key, metrics: metrics, includetrends: true
+ $.get API_MEASURES, data, (data) =>
+ measuresList = data[0].msr || []
+ measures = @component.get 'measures'
+ measuresList.forEach (m) ->
+ key = m.key.substr(4)
+ variation = "var#{period}"
+ measures[key] = m[variation]
+ @component.set 'measures', measures
+
+
requestSource: (key) ->
$.get API_SOURCES, key: key, (data) =>
@source.clear()
- @source.set source: data.sources
+ formattedSource = _.map data.sources, (item) => lineNumber: item[0], code: item[1]
+ @source.set
+ source: data.sources
+ formattedSource: formattedSource
requestTests: (key) ->
diff --git a/sonar-server/src/main/coffee/component-viewer/mixins/main-coverage.coffee b/sonar-server/src/main/coffee/component-viewer/mixins/main-coverage.coffee
index 88b5bb35b4f..c252c3d1f16 100644
--- a/sonar-server/src/main/coffee/component-viewer/mixins/main-coverage.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/mixins/main-coverage.coffee
@@ -9,8 +9,26 @@ define [], () ->
requestCoverage: (key, type = 'UT') ->
$.get API_COVERAGE, key: key, type: type, (data) =>
+ return unless data?.coverage?
@state.set 'hasCoverage', true
@source.set coverage: data.coverage
+ @augmentWithCoverage data.coverage
+
+
+ augmentWithCoverage: (coverage) ->
+ formattedSource = @source.get 'formattedSource'
+ coverage.forEach (c) ->
+ line = _.findWhere formattedSource, lineNumber: c[0]
+ line.coverage =
+ covered: c[1]
+ testCases: c[2]
+ branches: c[3]
+ coveredBranches: c[4]
+ if line.coverage.branches? && line.coverage.coveredBranches?
+ line.coverage.branchCoverageStatus = 'green' if line.coverage.branches == line.coverage.coveredBranches
+ line.coverage.branchCoverageStatus = 'orange' if line.coverage.branches > line.coverage.coveredBranches
+ line.coverage.branchCoverageStatus = 'red' if line.coverage.coveredBranches == 0
+ @source.set 'formattedSource', formattedSource
showCoverage: (store = false) ->
@@ -37,24 +55,54 @@ define [], () ->
_filterByCoverage: (predicate) ->
- coverage = @source.get 'coverage'
+ period = @state.get('period')
+ if period
+ periodDate = period.get 'sinceDate'
+ p = predicate
+ predicate = (line) =>
+ line?.scm?.date? && (new Date(line.scm.date) >= periodDate) && p(line)
+
+ formattedSource = @source.get 'formattedSource'
@settings.set 'coverage', true
@sourceView.resetShowBlocks()
- coverage.forEach (c) =>
- if predicate c
- line = c[0]
- @sourceView.addShowBlock line - LINES_AROUND_COVERED_LINE, line + LINES_AROUND_COVERED_LINE
+ formattedSource.forEach (line) =>
+ if predicate line
+ ln = line.lineNumber
+ @sourceView.addShowBlock ln - LINES_AROUND_COVERED_LINE, ln + LINES_AROUND_COVERED_LINE
@sourceView.render()
# Unit Tests
- filterByLinesToCover: -> @filterByCoverage (c) -> c[1]?
- filterByUncoveredLines: -> @filterByCoverage (c) -> c[1]? && !c[1]
- filterByBranchesToCover: -> @filterByCoverage (c) -> c[3]?
- filterByUncoveredBranches: -> @filterByCoverage (c) -> c[3]? && c[4]? && (c[3] > c[4])
+ filterByLinesToCover: ->
+ @filterByCoverage (line) -> line?.coverage?.covered?
+
+
+ filterByUncoveredLines: ->
+ @filterByCoverage (line) -> line?.coverage?.covered? && !line.coverage.covered
+
+
+ filterByBranchesToCover: ->
+ @filterByCoverage (line) -> line?.coverage?.branches?
+
+
+ filterByUncoveredBranches: ->
+ @filterByCoverage (line) -> line?.coverage?.branches? && line.coverage.coveredBranches? &&
+ line.coverage.branches > line.coverage.coveredBranches
+
# Integration Tests
- filterByLinesToCoverIT: -> @filterByCoverageIT (c) -> c[1]?
- filterByUncoveredLinesIT: -> @filterByCoverageIT (c) -> c[1]? && !c[1]
- filterByBranchesToCoverIT: -> @filterByCoverageIT (c) -> c[3]?
- filterByUncoveredBranchesIT: -> @filterByCoverageIT (c) -> c[3]? && c[4]? && (c[3] > c[4]) \ No newline at end of file
+ filterByLinesToCoverIT: ->
+ @filterByCoverageIT (line) -> line?.coverage?.covered?
+
+
+ filterByUncoveredLinesIT: ->
+ @filterByCoverageIT (line) -> line?.coverage?.covered? && !line.coverage.covered
+
+
+ filterByBranchesToCoverIT: ->
+ @filterByCoverageIT (line) -> line?.coverage?.branches?
+
+
+ filterByUncoveredBranchesIT: ->
+ @filterByCoverageIT (line) -> line?.coverage?.branches? && line.coverage.coveredBranches? &&
+ line.coverage.branches > line.coverage.coveredBranches \ No newline at end of file
diff --git a/sonar-server/src/main/coffee/component-viewer/mixins/main-duplications.coffee b/sonar-server/src/main/coffee/component-viewer/mixins/main-duplications.coffee
index 6be97515951..93d004abfec 100644
--- a/sonar-server/src/main/coffee/component-viewer/mixins/main-duplications.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/mixins/main-duplications.coffee
@@ -9,9 +9,27 @@ define [], () ->
requestDuplications: (key) ->
$.get API_DUPLICATIONS, key: key, (data) =>
+ return unless data?.duplications?
@state.set 'hasDuplications', true
@source.set duplications: data.duplications
@source.set duplicationFiles: data.files
+ @augmentWithDuplications data.duplications
+
+
+ augmentWithDuplications: (duplications) ->
+ formattedSource = @source.get 'formattedSource'
+ formattedSource.forEach (line) ->
+ lineDuplications = []
+ duplications.forEach (d, i) ->
+ duplicated = false
+ d.blocks.forEach (b) ->
+ if b._ref == '1'
+ lineFrom = b.from
+ lineTo = b.from + b.size
+ duplicated = true if line.lineNumber >= lineFrom && line.lineNumber <= lineTo
+ lineDuplications.push if duplicated then i + 1 else false
+ line.duplications = lineDuplications
+ @source.set 'formattedSource', formattedSource
showDuplications: (store = false) ->
diff --git a/sonar-server/src/main/coffee/component-viewer/mixins/main-issues.coffee b/sonar-server/src/main/coffee/component-viewer/mixins/main-issues.coffee
index d29235bc9ca..c396afa3c6c 100644
--- a/sonar-server/src/main/coffee/component-viewer/mixins/main-issues.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/mixins/main-issues.coffee
@@ -37,7 +37,9 @@ define [], () ->
requestIssuesPeriod: (key, period) ->
- $.get API_COMPONENT, key: key, period: period, (data) =>
+ params = key: key
+ params.period = period if period?
+ $.get API_COMPONENT, params, (data) =>
rules = data.rules.map (r) -> key: r[0], name: r[1], count: r[2]
severities = data.severities.map (r) -> key: r[0], name: r[1], count: r[2]
@state.set rules: rules, severities: severities
@@ -46,10 +48,8 @@ define [], () ->
enableIssuesPeriod: (periodKey) ->
period = if periodKey == '' then null else @periods.findWhere key: periodKey
@state.set 'issuesPeriod', period
- if period?
- @requestIssuesPeriod(@key, period.get('key')).done => @headerView.render()
- else
- @requestComponent(@key, false, false).done => @headerView.render()
+ periodKey = if period? then period.get 'key' else null
+ @requestIssuesPeriod(@key, periodKey).done => @headerView.render()
filterLinesByIssues: ->
diff --git a/sonar-server/src/main/coffee/component-viewer/mixins/main-scm.coffee b/sonar-server/src/main/coffee/component-viewer/mixins/main-scm.coffee
index 3e92b7528b5..57833917494 100644
--- a/sonar-server/src/main/coffee/component-viewer/mixins/main-scm.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/mixins/main-scm.coffee
@@ -8,8 +8,28 @@ define [], () ->
requestSCM: (key) ->
$.get API_SCM, key: key, (data) =>
- @state.set 'hasSCM', true
- @source.set scm: data.scm
+ if data?.scm?
+ @state.set 'hasSCM', true
+ @source.set scm: data.scm
+ @augmentWithSCM data.scm
+
+
+ augmentWithSCM: (scm) ->
+ formattedSource = @source.get 'formattedSource'
+ scmLength = scm.length
+ if scmLength > 0
+ scmIndex = 0
+ scmCurrent = scm[scmIndex]
+ scmDetails = {}
+ formattedSource.forEach (line) ->
+ if line.lineNumber == scmCurrent[0]
+ scmDetails = author: scmCurrent[1], date: scmCurrent[2]
+ if scmIndex < scmLength - 1
+ scmIndex++
+ scmCurrent = scm[scmIndex]
+ line.scm = scmDetails
+ @source.set 'formattedSource', formattedSource
+
showSCM: (store = false) ->
@@ -24,4 +44,40 @@ define [], () ->
hideSCM: (store = false) ->
@settings.set 'scm', false
@storeSettings() if store
- @sourceView.render() \ No newline at end of file
+ @sourceView.render()
+
+
+ filterBySCM: ->
+ @requestSCM(@key).done => @_filterBySCM()
+
+
+ _filterBySCM: () ->
+ formattedSource = @source.get 'formattedSource'
+ period = @state.get 'period'
+ unless period?
+ return @showAllLines()
+ else
+ periodDate = period.get 'sinceDate'
+ @settings.set 'scm', true
+ @sourceView.resetShowBlocks()
+ scmBlockLine = 1
+ predicate = false
+ formattedSource.forEach (line) =>
+ scmBlockDate = new Date line.scm.date
+ if scmBlockDate >= periodDate
+ scmBlockLine = line.lineNumber if predicate == false
+ predicate = true
+ else if predicate == true
+ predicate = false
+ @sourceView.addShowBlock scmBlockLine, line.lineNumber - 1
+ if predicate
+ @sourceView.addShowBlock scmBlockLine, _.size @source.get 'source'
+ @sourceView.render()
+
+
+ enableSCMPeriod: (periodKey) ->
+ period = if periodKey == '' then null else @periods.findWhere key: periodKey
+ @state.set 'period', period
+ @requestMeasures(@key, period?.get('key')).done =>
+ @headerView.render()
+ @filterBySCM() unless @state.get('activeHeaderItem') \ No newline at end of file
diff --git a/sonar-server/src/main/coffee/component-viewer/source.coffee b/sonar-server/src/main/coffee/component-viewer/source.coffee
index 0ace43ecefb..2e1b4d8a677 100644
--- a/sonar-server/src/main/coffee/component-viewer/source.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/source.coffee
@@ -174,40 +174,6 @@ define [
@options.main.showAllLines()
- augmentWithCoverage: (source) ->
- coverage = @model.get 'coverage'
- if coverage
- coverage.forEach (s) ->
- line = source[s[0] - 1]
- line.coverage =
- covered: s[1]
- testCases: s[2]
- branches: s[3]
- coveredBranches: s[4]
- if line.coverage.branches? && line.coverage.coveredBranches?
- line.coverage.branchCoverageStatus = 'green' if line.coverage.branches == line.coverage.coveredBranches
- line.coverage.branchCoverageStatus = 'orange' if line.coverage.branches > line.coverage.coveredBranches
- line.coverage.branchCoverageStatus = 'red' if line.coverage.coveredBranches == 0
- source
-
-
- augmentWithDuplications: (source) ->
- duplications = @model.get 'duplications'
- return source unless duplications?
- source.forEach (line) ->
- lineDuplications = []
- duplications.forEach (d, i) ->
- duplicated = false
- d.blocks.forEach (b) ->
- if b._ref == '1'
- lineFrom = b.from
- lineTo = b.from + b.size
- duplicated = true if line.lineNumber >= lineFrom && line.lineNumber <= lineTo
- lineDuplications.push if duplicated then i + 1 else false
- line.duplications = lineDuplications
- source
-
-
getSCMForLine: (lineNumber) ->
scm = @model.get('scm') || []
closest = -1
@@ -244,18 +210,9 @@ define [
prepareSource: ->
- source = @model.get 'source'
- source = _.map source, (item) =>
- lineNumber: item[0], code: item[1]
-
- 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
-
- @augmentWithShow source
+ source = @model.get 'formattedSource'
+ if source?
+ @augmentWithShow source
getStatColumnsCount: ->
diff --git a/sonar-server/src/main/coffee/component-viewer/time-changes-popup.coffee b/sonar-server/src/main/coffee/component-viewer/time-changes-popup.coffee
index a677ee7dd5b..2e1cad33c72 100644
--- a/sonar-server/src/main/coffee/component-viewer/time-changes-popup.coffee
+++ b/sonar-server/src/main/coffee/component-viewer/time-changes-popup.coffee
@@ -27,3 +27,4 @@ define [
serializeData: ->
component: @options.main.component.toJSON()
periods: @options.main.periods.toJSON()
+ prefix: @options.prefix || 'Δ'
diff --git a/sonar-server/src/main/hbs/component-viewer/header.hbs b/sonar-server/src/main/hbs/component-viewer/header.hbs
index a3733bf8285..c20b5896ed8 100644
--- a/sonar-server/src/main/hbs/component-viewer/header.hbs
+++ b/sonar-server/src/main/hbs/component-viewer/header.hbs
@@ -114,13 +114,14 @@
{{#inArray state.tabs 'scm'}}
<div class="component-viewer-header-measures-scope">
- <span data-scope="scm" class="component-viewer-header-measures-expand">
+ <a data-scope="scm" class="component-viewer-header-measures-expand">
<div class="component-viewer-header-measure">
<span class="component-viewer-header-measure-value"><i class="icon-calendar"></i></span>
<span class="component-viewer-header-measure-label">SCM</span>
</div>
- </span>
- <a data-scope="scm" title="{{t 'component_viewer.header.toggle_duplications'}}"
+ <i class="icon-dropdown"></i>
+ </a>
+ <a data-scope="scm" title="{{t 'component_viewer.header.toggle_scm'}}"
class="js-toggle-scm component-viewer-header-measures-toggle-scope {{#if settings.scm}}active{{/if}}"></a>
</div>
{{/inArray}}
diff --git a/sonar-server/src/main/hbs/component-viewer/header/coverage-header.hbs b/sonar-server/src/main/hbs/component-viewer/header/coverage-header.hbs
index 2e2e4a492b5..c2b0a87ab81 100644
--- a/sonar-server/src/main/hbs/component-viewer/header/coverage-header.hbs
+++ b/sonar-server/src/main/hbs/component-viewer/header/coverage-header.hbs
@@ -1,52 +1,63 @@
-{{#with component.measures}}
- <div class="component-viewer-header-expanded-bar-section">
- <div class="component-viewer-header-expanded-bar-section-title">
- {{t 'component_viewer.measure_section.unit_tests'}}
- </div>
- <ul class="component-viewer-header-expanded-bar-section-list">
- {{{componentViewerHeaderItem coverage 'coverage'}}}
- {{{componentViewerHeaderItem line_coverage 'line_coverage'}}}
- {{{componentViewerHeaderLink lines_to_cover 'lines_to_cover' 'js-filter-lines-to-cover'}}}
- {{{componentViewerHeaderLink uncovered_lines 'uncovered_lines' 'js-filter-uncovered-lines'}}}
- </ul>
- </div>
+<div class="component-viewer-header-time-changes">
+ <a class="highlighted-link js-coverage-time-changes">
+ {{#if period}}Δ {{period.label}}{{else}}<i class="icon-period"></i> Time Changes{{/if}}
+ </a>
+</div>
- {{#any branch_coverage conditions_to_cover covered_conditions uncovered_conditions}}
- <div class="component-viewer-header-expanded-bar-section">
- <div class="component-viewer-header-expanded-bar-section-title">&nbsp;</div>
- <ul class="component-viewer-header-expanded-bar-section-list">
- <li><span class="item">&nbsp;</span></li>
- {{{componentViewerHeaderItem branch_coverage 'branch_coverage'}}}
- {{{componentViewerHeaderLink conditions_to_cover 'conditions_to_cover' 'js-filter-branches-to-cover'}}}
- {{{componentViewerHeaderLink uncovered_conditions 'uncovered_conditions' 'js-filter-uncovered-branches'}}}
- </ul>
- </div>
- {{/any}}
+{{#with component.measures}}
+ <span class="nowrap">
+ {{#any coverage line_coverage lines_to_cover covered_lines uncovered_lines}}
+ <div class="component-viewer-header-expanded-bar-section">
+ <div class="component-viewer-header-expanded-bar-section-title">
+ {{t 'component_viewer.measure_section.unit_tests'}}
+ </div>
+ <ul class="component-viewer-header-expanded-bar-section-list">
+ {{{componentViewerHeaderItem coverage 'coverage'}}}
+ {{{componentViewerHeaderItem line_coverage 'line_coverage'}}}
+ {{{componentViewerHeaderLink lines_to_cover 'lines_to_cover' 'js-filter-lines-to-cover'}}}
+ {{{componentViewerHeaderLink uncovered_lines 'uncovered_lines' 'js-filter-uncovered-lines'}}}
+ </ul>
+ </div>
+ {{/any}}
+ {{#any branch_coverage conditions_to_cover covered_conditions uncovered_conditions}}
+ <div class="component-viewer-header-expanded-bar-section">
+ <div class="component-viewer-header-expanded-bar-section-title">&nbsp;</div>
+ <ul class="component-viewer-header-expanded-bar-section-list">
+ <li><span class="item">&nbsp;</span></li>
+ {{{componentViewerHeaderItem branch_coverage 'branch_coverage'}}}
+ {{{componentViewerHeaderLink conditions_to_cover 'conditions_to_cover' 'js-filter-branches-to-cover'}}}
+ {{{componentViewerHeaderLink uncovered_conditions 'uncovered_conditions' 'js-filter-uncovered-branches'}}}
+ </ul>
+ </div>
+ {{/any}}
+ </span>
- {{#any it_coverage it_line_coverage it_lines_to_cover it_covered_lines it_uncovered_lines}}
- <div class="component-viewer-header-expanded-bar-section">
- <div class="component-viewer-header-expanded-bar-section-title">
- {{t 'component_viewer.measure_section.integration_tests'}}
+ <span class="nowrap">
+ {{#any it_coverage it_line_coverage it_lines_to_cover it_covered_lines it_uncovered_lines}}
+ <div class="component-viewer-header-expanded-bar-section">
+ <div class="component-viewer-header-expanded-bar-section-title">
+ {{t 'component_viewer.measure_section.integration_tests'}}
+ </div>
+ <ul class="component-viewer-header-expanded-bar-section-list">
+ {{{componentViewerHeaderItem it_coverage 'coverage'}}}
+ {{{componentViewerHeaderItem it_line_coverage 'line_coverage'}}}
+ {{{componentViewerHeaderLink it_lines_to_cover 'lines_to_cover' 'js-filter-lines-to-cover-it'}}}
+ {{{componentViewerHeaderLink it_uncovered_lines 'uncovered_lines' 'js-filter-uncovered-lines-it'}}}
+ </ul>
</div>
- <ul class="component-viewer-header-expanded-bar-section-list">
- {{{componentViewerHeaderItem it_coverage 'coverage'}}}
- {{{componentViewerHeaderItem it_line_coverage 'line_coverage'}}}
- {{{componentViewerHeaderLink it_lines_to_cover 'lines_to_cover' 'js-filter-lines-to-cover-it'}}}
- {{{componentViewerHeaderLink it_uncovered_lines 'uncovered_lines' 'js-filter-uncovered-lines-it'}}}
- </ul>
- </div>
- {{/any}}
+ {{/any}}
- {{#any it_branch_coverage it_conditions_to_cover it_covered_conditions it_uncovered_conditions}}
- <div class="component-viewer-header-expanded-bar-section">
- <div class="component-viewer-header-expanded-bar-section-title">&nbsp;</div>
- <ul class="component-viewer-header-expanded-bar-section-list">
- <li><span class="item">&nbsp;</span></li>
- {{{componentViewerHeaderItem it_branch_coverage 'branch_coverage'}}}
- {{{componentViewerHeaderLink it_conditions_to_cover 'conditions_to_cover' 'js-filter-branches-to-cover-it'}}}
- {{{componentViewerHeaderLink it_uncovered_conditions 'uncovered_conditions' 'js-filter-uncovered-branches-it'}}}
- </ul>
- </div>
- {{/any}}
-{{/with}} \ No newline at end of file
+ {{#any it_branch_coverage it_conditions_to_cover it_covered_conditions it_uncovered_conditions}}
+ <div class="component-viewer-header-expanded-bar-section">
+ <div class="component-viewer-header-expanded-bar-section-title">&nbsp;</div>
+ <ul class="component-viewer-header-expanded-bar-section-list">
+ <li><span class="item">&nbsp;</span></li>
+ {{{componentViewerHeaderItem it_branch_coverage 'branch_coverage'}}}
+ {{{componentViewerHeaderLink it_conditions_to_cover 'conditions_to_cover' 'js-filter-branches-to-cover-it'}}}
+ {{{componentViewerHeaderLink it_uncovered_conditions 'uncovered_conditions' 'js-filter-uncovered-branches-it'}}}
+ </ul>
+ </div>
+ {{/any}}
+ </span>
+{{/with}}
diff --git a/sonar-server/src/main/hbs/component-viewer/header/issues-header.hbs b/sonar-server/src/main/hbs/component-viewer/header/issues-header.hbs
index c4632830440..bca87c9c4a0 100644
--- a/sonar-server/src/main/hbs/component-viewer/header/issues-header.hbs
+++ b/sonar-server/src/main/hbs/component-viewer/header/issues-header.hbs
@@ -1,3 +1,9 @@
+<div class="component-viewer-header-time-changes">
+ <a class="highlighted-link js-issues-time-changes">
+ {{#if period}}Added {{period.label}}{{else}}<i class="icon-period"></i> Time Changes{{/if}}
+ </a>
+</div>
+
{{#ifNotEmpty state.severities}}
<div class="component-viewer-header-expanded-bar-section">
<div class="component-viewer-header-expanded-bar-section-title">
@@ -59,18 +65,13 @@
</ul>
</div>
- <div class="component-viewer-header-expanded-bar-section component-viewer-header-expanded-bar-section-actions">
- <div class="component-viewer-header-expanded-bar-section-title">&nbsp;</div>
- <ul class="component-viewer-header-expanded-bar-section-list">
- <li><a class="link-action js-issues-time-changes">
- <span><i class="icon-period"></i>
- {{#if period}}Added {{period.label}}{{else}}Time Changes{{/if}}</span>
-
+<div class="component-viewer-header-expanded-bar-section component-viewer-header-expanded-bar-section-actions">
+ <div class="component-viewer-header-expanded-bar-section-title">&nbsp;</div>
+ <ul class="component-viewer-header-expanded-bar-section-list">
+ {{#if state.canBulkChange}}
+ <li><a class="link-action js-issues-bulk-change">
+ <span><i class="icon-bulk-change"></i> {{t 'bulk_change'}}</span>
</a></li>
- {{#if state.canBulkChange}}
- <li><a class="link-action js-issues-bulk-change">
- <span><i class="icon-bulk-change"></i> {{t 'bulk_change'}}</span>
- </a></li>
- {{/if}}
- </ul>
- </div>
+ {{/if}}
+ </ul>
+</div>
diff --git a/sonar-server/src/main/hbs/component-viewer/header/scm-header.hbs b/sonar-server/src/main/hbs/component-viewer/header/scm-header.hbs
new file mode 100644
index 00000000000..8f60976ae3b
--- /dev/null
+++ b/sonar-server/src/main/hbs/component-viewer/header/scm-header.hbs
@@ -0,0 +1,5 @@
+<div class="component-viewer-header-time-changes">
+ <a class="highlighted-link js-scm-time-changes">
+ {{#if period}}Δ {{period.label}}{{else}}<i class="icon-period"></i> Time Changes{{/if}}
+ </a>
+</div> \ No newline at end of file
diff --git a/sonar-server/src/main/hbs/component-viewer/source.hbs b/sonar-server/src/main/hbs/component-viewer/source.hbs
index 7f290b8cbc2..b4f9c67709f 100644
--- a/sonar-server/src/main/hbs/component-viewer/source.hbs
+++ b/sonar-server/src/main/hbs/component-viewer/source.hbs
@@ -30,8 +30,10 @@
{{#if ../../settings.scm}}
<td class="stat {{#if scm}}scm{{/if}}">
{{#if scm}}
- <span class="scm-date">{{scm.date}}</span>
- <span class="scm-author" title="{{scm.author}}">{{scm.author}}</span>
+ {{#ifSCMChanged ../../../../source ../../../lineNumber}}
+ <span class="scm-date">{{scm.date}}</span>
+ <span class="scm-author" title="{{scm.author}}">{{scm.author}}</span>
+ {{/ifSCMChanged}}
{{/if}}
</td>
{{/if}}
diff --git a/sonar-server/src/main/hbs/component-viewer/time-changes-popup.hbs b/sonar-server/src/main/hbs/component-viewer/time-changes-popup.hbs
index 748bd4d9145..615164e48cf 100644
--- a/sonar-server/src/main/hbs/component-viewer/time-changes-popup.hbs
+++ b/sonar-server/src/main/hbs/component-viewer/time-changes-popup.hbs
@@ -2,7 +2,7 @@
<ul class="component-viewer-popup-list">
{{#each periods}}
- <li><a class="link-action" data-period="{{key}}">{{label}}</a></li>
+ <li><a class="link-action" data-period="{{key}}">{{#if key}}{{../../prefix}}{{/if}} {{label}}</a></li>
{{/each}}
</ul>
diff --git a/sonar-server/src/main/js/common/handlebars-extensions.js b/sonar-server/src/main/js/common/handlebars-extensions.js
index 8d7ada4f526..bc43649e1db 100644
--- a/sonar-server/src/main/js/common/handlebars-extensions.js
+++ b/sonar-server/src/main/js/common/handlebars-extensions.js
@@ -315,4 +315,16 @@ define(['handlebars', 'moment'], function (Handlebars, moment) {
}
});
+ Handlebars.registerHelper('ifSCMChanged', function(source, line, options) {
+ var currentLine = _.findWhere(source, { lineNumber: line }),
+ prevLine = _.findWhere(source, { lineNumber: line - 1 }),
+ changed = true;
+ if (currentLine && prevLine && currentLine.scm && prevLine.scm) {
+ changed = (currentLine.scm.author !== prevLine.scm.author)
+ || (currentLine.scm.date !== prevLine.scm.date)
+ || (!prevLine.show);
+ }
+ return changed ? options.fn(this) : options.inverse(this);
+ });
+
});
diff --git a/sonar-server/src/main/js/translate.js b/sonar-server/src/main/js/translate.js
index eba86383eee..2d5883bf444 100644
--- a/sonar-server/src/main/js/translate.js
+++ b/sonar-server/src/main/js/translate.js
@@ -89,9 +89,10 @@
var apiUrl = baseUrl + '/api/l10n/index';
return jQuery.ajax({
- 'url': apiUrl,
- 'data': params,
- 'statusCode': {
+ url: apiUrl,
+ data: params,
+ dataType: 'json',
+ statusCode: {
304: function() {
// NOP, use cached messages
}
diff --git a/sonar-server/src/main/less/component-viewer.less b/sonar-server/src/main/less/component-viewer.less
index 98143dca240..e5e1bc33ca4 100644
--- a/sonar-server/src/main/less/component-viewer.less
+++ b/sonar-server/src/main/less/component-viewer.less
@@ -512,11 +512,14 @@
&:hover { background-color: @barBackgroundColor; }
}
-
.component-viewer-header-decoration {
margin-top: 10px;
}
+.component-viewer-header-time-changes {
+ padding: 10px;
+}
+
@popupArrowSize: 8px;