diff options
Diffstat (limited to 'sonar-server')
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"> </div> - <ul class="component-viewer-header-expanded-bar-section-list"> - <li><span class="item"> </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"> </div> + <ul class="component-viewer-header-expanded-bar-section-list"> + <li><span class="item"> </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"> </div> - <ul class="component-viewer-header-expanded-bar-section-list"> - <li><span class="item"> </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"> </div> + <ul class="component-viewer-header-expanded-bar-section-list"> + <li><span class="item"> </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"> </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"> </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; |