diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2014-04-22 18:08:45 +0600 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2014-04-22 18:08:54 +0600 |
commit | 1315fe1d47399c821a12d647e4c62b1fd54113fc (patch) | |
tree | 610ff11e6de749825ebe93ea6c338bc5b69c36a3 | |
parent | 617bd05a326531e8d64faa8ba0bf54fbe0bce421 (diff) | |
download | sonarqube-1315fe1d47399c821a12d647e4c62b1fd54113fc.tar.gz sonarqube-1315fe1d47399c821a12d647e4c62b1fd54113fc.zip |
Component Viewer: ui improvements
15 files changed, 244 insertions, 124 deletions
diff --git a/sonar-server/src/main/coffee/coding-rules/app.coffee b/sonar-server/src/main/coffee/coding-rules/app.coffee index 9d1393c46b2..149e9f44838 100644 --- a/sonar-server/src/main/coffee/coding-rules/app.coffee +++ b/sonar-server/src/main/coffee/coding-rules/app.coffee @@ -180,7 +180,7 @@ requirejs [ # Construct header App.addInitializer -> @codingRulesHeaderView = new CodingRulesHeaderView app: @ - @layout.headerRegion.show @codingRulesHeaderView + @layout.workspaceRegion.show @codingRulesHeaderView # Define coding rules diff --git a/sonar-server/src/main/coffee/component-viewer/coverage-popup.coffee b/sonar-server/src/main/coffee/component-viewer/coverage-popup.coffee index c225a07b428..cc5ba87677c 100644 --- a/sonar-server/src/main/coffee/component-viewer/coverage-popup.coffee +++ b/sonar-server/src/main/coffee/component-viewer/coverage-popup.coffee @@ -20,9 +20,7 @@ define [ onRender: -> @$el.detach().appendTo $('body') - @$el.css - top: @options.triggerEl.offset().top - left: @options.triggerEl.offset().left + @options.triggerEl.outerWidth() + @$el.css 'top', @options.triggerEl.offset().top $('body').on 'click.coverage-popup', => $('body').off 'click.coverage-popup' diff --git a/sonar-server/src/main/coffee/component-viewer/main.coffee b/sonar-server/src/main/coffee/component-viewer/main.coffee index c207d8c3f87..2471f3fa1ea 100644 --- a/sonar-server/src/main/coffee/component-viewer/main.coffee +++ b/sonar-server/src/main/coffee/component-viewer/main.coffee @@ -2,13 +2,13 @@ define [ 'backbone' 'backbone.marionette' 'templates/component-viewer' - 'component-viewer/header' + 'component-viewer/workspace' 'component-viewer/source' ], ( Backbone Marionette Templates - HeaderView + WorkspaceView SourceView ) -> @@ -24,25 +24,27 @@ define [ regions: - headerRegion: '.component-viewer-header' + workspaceRegion: '.component-viewer-workspace' sourceRegion: '.component-viewer-source' initialize: -> @workspace = new Backbone.Collection() @component = new Backbone.Model() - @headerView = new HeaderView - model: @component + @workspaceView = new WorkspaceView + collection: @workspace main: @ @source = new Backbone.Model() - @sourceView = new SourceView model: @source, main: @ + @sourceView = new SourceView + model: @source + main: @ @settings = new Backbone.Model issues: false, coverage: true, duplications: false onRender: -> - @headerRegion.show @headerView + @workspaceRegion.show @workspaceView @sourceRegion.show @sourceView @@ -92,6 +94,7 @@ define [ showCoverage: -> + @settings.set 'coverage', true unless @source.has 'coverage' metrics = 'coverage_line_hits_data,covered_conditions_by_line,conditions_by_line' @requestComponent(@key, metrics).done (data) => @@ -102,7 +105,8 @@ define [ hideCoverage: -> - @sourceView.hideCoverage() + @settings.set 'coverage', false + @sourceView.render() addTransition: (key, transition) -> diff --git a/sonar-server/src/main/coffee/component-viewer/source.coffee b/sonar-server/src/main/coffee/component-viewer/source.coffee index e4ea8c7502a..27f72f9da40 100644 --- a/sonar-server/src/main/coffee/component-viewer/source.coffee +++ b/sonar-server/src/main/coffee/component-viewer/source.coffee @@ -17,42 +17,61 @@ define [ events: - 'click .coverage a': 'showCoveragePopup' + 'click .settings-toggle button': 'toggleSettings' + 'change #source-coverage': 'toggleCoverage' + 'click .coverage-tests': 'showCoveragePopup' onRender: -> @delegateEvents() + @showSettings = false showSpinner: -> @$el.html '<div style="padding: 10px;"><i class="spinner"></i></div>' - hideCoverage: -> - @$('.coverage').hide() + + toggleSettings: -> + @$('.settings-toggle button').toggleClass 'open' + @$('.component-viewer-source-settings').toggleClass 'open' + + + toggleCoverage: (e) -> + active = $(e.currentTarget).is ':checked' + @showSettings = true + if active then @options.main.showCoverage() else @options.main.hideCoverage() showCoveragePopup: (e) -> e.stopPropagation() $('body').click() popup = new CoveragePopupView - triggerEl: $(e.currentTarget).closest('td') + triggerEl: $(e.currentTarget) main: @options.main popup.render() - serializeData: -> + prepareSource: -> source = @model.get 'source' coverage = @model.get 'coverage' coverageConditions = @model.get 'coverageConditions' conditions = @model.get 'conditions' - source = _.map source, (code, line) -> + _.map source, (code, line) -> lineCoverage = coverage? && coverage[line]? && coverage[line] + lineCoverage = +lineCoverage if _.isString lineCoverage lineCoverageConditions = coverageConditions? && coverageConditions[line]? && coverageConditions[line] + lineCoverageConditions = +lineCoverageConditions if _.isString lineCoverageConditions lineConditions = conditions? && conditions[line]? && conditions[line] - lineCoverageStatus = lineCoverage? && if lineCoverage > 0 then 'green' else 'red' + lineConditions = +lineConditions if _.isString lineConditions + + lineCoverageStatus = null + if _.isNumber lineCoverage + lineCoverageStatus = 'red' if lineCoverage == 0 + lineCoverageStatus = 'green' if lineCoverage > 0 + lineCoverageConditionsStatus = null - if lineCoverageConditions? && conditions? + if _.isNumber(lineCoverageConditions) && _.isNumber(conditions) lineCoverageConditionsStatus = 'red' if lineCoverageConditions == 0 lineCoverageConditionsStatus = 'orange' if lineCoverageConditions > 0 && lineCoverageConditions < lineConditions lineCoverageConditionsStatus = 'green' if lineCoverageConditions == lineConditions @@ -63,5 +82,10 @@ define [ coverageStatus: lineCoverageStatus coverageConditions: lineCoverageConditions conditions: lineConditions - coverageConditionsStatus: lineCoverageConditionsStatus - source: source
\ No newline at end of file + coverageConditionsStatus: lineCoverageConditionsStatus || lineCoverageStatus + + + serializeData: -> + source: @prepareSource() + settings: @options.main.settings.toJSON() + showSettings: @showSettings
\ No newline at end of file diff --git a/sonar-server/src/main/coffee/component-viewer/header.coffee b/sonar-server/src/main/coffee/component-viewer/workspace.coffee index e64f546d43e..4eaf851fa72 100644 --- a/sonar-server/src/main/coffee/component-viewer/header.coffee +++ b/sonar-server/src/main/coffee/component-viewer/workspace.coffee @@ -9,13 +9,12 @@ define [ $ = jQuery - class HeaderView extends Marionette.ItemView - template: Templates['header'] + class WorkspaceView extends Marionette.ItemView + template: Templates['workspace'] events: 'click .component-viewer-workspace-item [data-key]': 'goToWorkspaceItem' - 'click [data-option=coverage]': 'toggleCoverage' onRender: -> @@ -31,13 +30,6 @@ define [ @options.main.addTransition workspaceItem.get('key'), workspaceItem.get('transition') - toggleCoverage: (e) -> - el = $(e.currentTarget) - active = el.is '.active' - el.toggleClass 'active' - if active then @options.main.hideCoverage() else @options.main.showCoverage() - - serializeData: -> _.extend super, workspace: @options.main.workspace.toJSON() diff --git a/sonar-server/src/main/coffee/quality-gate/layout.coffee b/sonar-server/src/main/coffee/quality-gate/layout.coffee index 0b5941655d5..0edc32c223e 100644 --- a/sonar-server/src/main/coffee/quality-gate/layout.coffee +++ b/sonar-server/src/main/coffee/quality-gate/layout.coffee @@ -25,7 +25,7 @@ define [ updateLayout: -> empty = @options.app.qualityGates.length == 0 - @$(@headerRegion.el).toggle !empty + @$(@workspaceRegion.el).toggle !empty @$(@detailsRegion.el).toggle !empty diff --git a/sonar-server/src/main/coffee/quality-gate/router.coffee b/sonar-server/src/main/coffee/quality-gate/router.coffee index f21161a97bf..834da1bf9ca 100644 --- a/sonar-server/src/main/coffee/quality-gate/router.coffee +++ b/sonar-server/src/main/coffee/quality-gate/router.coffee @@ -28,7 +28,7 @@ define [ qualityGateDetailHeaderView = new QualityGateDetailHeaderView app: @app model: qualityGate - @app.layout.headerRegion.show qualityGateDetailHeaderView + @app.layout.workspaceRegion.show qualityGateDetailHeaderView qualityGateDetailView = new QualityGateDetailView app: @app diff --git a/sonar-server/src/main/hbs/component-viewer/coveragePopup.hbs b/sonar-server/src/main/hbs/component-viewer/coveragePopup.hbs index 1e8d81aa27d..d11d2221090 100644 --- a/sonar-server/src/main/hbs/component-viewer/coveragePopup.hbs +++ b/sonar-server/src/main/hbs/component-viewer/coveragePopup.hbs @@ -1,7 +1,7 @@ <div class="component-viewer-popup-section"> <a data-key="org.codehaus.sonar:sonar-plugin-api:src/test/java/org/sonar/api/resources/ResourceTypeTreeTest.java" class="component-viewer-popup-section-title"> - src/test/java/org/sonar/api/resources/ResourceTypeTreeTest.java + ResourceTypeTreeTest.java </a> <ul class="component-viewer-popup-list"> <li><i class="icon-alert-ok"></i> 216ms forbidDuplicatedType</li> @@ -12,7 +12,7 @@ <div class="component-viewer-popup-section"> <a data-key="org.codehaus.sonar:sonar-plugin-api:src/test/java/org/sonar/api/resources/ResourceTypesTest.java" class="component-viewer-popup-section-title"> - src/test/java/org/sonar/api/resources/ResourceTypesTest.java + ResourceTypesTest.java </a> <ul class="component-viewer-popup-list"> <li><i class="icon-alert-ok"></i> 115ms fail_on_duplicated_qualifier</li> diff --git a/sonar-server/src/main/hbs/component-viewer/header.hbs b/sonar-server/src/main/hbs/component-viewer/header.hbs deleted file mode 100644 index 0e05fdf6a2b..00000000000 --- a/sonar-server/src/main/hbs/component-viewer/header.hbs +++ /dev/null @@ -1,26 +0,0 @@ -<div class="component-viewer-workspace"> - <ul class="component-viewer-workspace-list"> - {{#each workspace}} - <li class="component-viewer-workspace-item"> - {{#if transition}} - <span class="component-viewer-workspace-transition"> - <i class="icon-move-right"></i> - </span> - {{/if}} - <a data-key="{{key}}">{{qualifierIcon component.qualifier}} {{component.name}}</a> - </li> - {{/each}} - </ul> -</div> - -<div class="component-viewer-options button-group"> - <button data-option="issues" {{#if settings.issues}}class="active"{{/if}}> - <i class="icon-issue"></i> Issues - </button> - <button data-option="coverage" {{#if settings.coverage}}class="active"{{/if}}> - <i class="icon-coverage"></i> Coverage - </button> - <button data-option="duplications" {{#if settings.duplications}}class="active"{{/if}}> - <i class="icon-duplications"></i> Duplications - </button> -</div>
\ No newline at end of file diff --git a/sonar-server/src/main/hbs/component-viewer/layout.hbs b/sonar-server/src/main/hbs/component-viewer/layout.hbs index 78b06dad147..853611d0a30 100644 --- a/sonar-server/src/main/hbs/component-viewer/layout.hbs +++ b/sonar-server/src/main/hbs/component-viewer/layout.hbs @@ -1,2 +1,2 @@ -<div class="component-viewer-header"></div> +<div class="component-viewer-workspace"></div> <div class="component-viewer-source"></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 5692d126f2a..151109a45b4 100644 --- a/sonar-server/src/main/hbs/component-viewer/source.hbs +++ b/sonar-server/src/main/hbs/component-viewer/source.hbs @@ -1,20 +1,59 @@ <table class="sources2 code" cellpadding="0" cellspacing="0"> - {{#each source}} - <tr class="row"> - <td class="coverage {{#if coverage}}coverage-{{coverageStatus}}{{/if}}"> - {{#if coverage}}<a title="Line is covered by {{coverage}} tests">{{coverage}}</a>{{/if}} - </td> - <td class="coverage {{#if coverageConditions}}coverage-{{coverageConditionsStatus}}{{/if}}"> - {{#if coverageConditions}} - {{#if conditions}} - <span title="{{coverageConditions}} branches are covered by tests"> - {{coverageConditions}}/{{conditions}} - </span> + <thead> + <tr> + {{#if settings.coverage}} + <th class="stat"></th> + <th class="stat"></th> + {{/if}} + <th class="stat settings-toggle"> + <button class="button-clean"> + <i class="icon-settings"></i></i> + </button> + </th> + <th class="stat settings"> + <ul class="component-viewer-source-settings {{#if showSettings}}open{{/if}}"> + <li> + <input id="source-issues" type="checkbox" {{#if settings.issues}}checked{{/if}}> + <label for="source-issues">Issues</label> + </li> + <li> + <input id="source-coverage" type="checkbox" {{#if settings.coverage}}checked{{/if}}> + <label for="source-coverage">Coverage</label> + </li> + <li> + <input id="source-duplications" type="checkbox" {{#if settings.duplications}}checked{{/if}}> + <label for="source-duplications">Duplications</label> + </li> + </ul> + </th> + </tr> + </thead> + <tbody> + {{#each source}} + <tr class="row {{#if ../settings.coverage}}{{#if coverageStatus}}coverage-{{coverageStatus}}{{/if}}{{/if}}"> + + {{#if ../settings.coverage}} + <td class="stat coverage-tests"> + {{#if coverage}} + <span title="Line is covered by {{coverage}} tests">{{coverage}}</span> {{/if}} - {{/if}} - </td> - <td class="lid">{{lineNumber}}</td> - <td class="line"><pre>{{{code}}}</pre></td> - </tr> - {{/each}} + </td> + + <td class="stat coverage-conditions"> + {{#if coverageConditions}} + {{#if conditions}} + <span title="{{coverageConditions}} branches are covered by tests"> + {{coverageConditions}}/{{conditions}} + </span> + {{/if}} + {{/if}} + </td> + {{/if}} + + <td class="stat lid">{{lineNumber}}</td> + + <td class="line"><pre>{{{code}}}</pre></td> + </tr> + {{/each}} + </tbody> </table>
\ No newline at end of file diff --git a/sonar-server/src/main/hbs/component-viewer/workspace.hbs b/sonar-server/src/main/hbs/component-viewer/workspace.hbs new file mode 100644 index 00000000000..f25d693d3ac --- /dev/null +++ b/sonar-server/src/main/hbs/component-viewer/workspace.hbs @@ -0,0 +1,12 @@ +<ul class="component-viewer-workspace-list"> + {{#each workspace}} + <li class="component-viewer-workspace-item"> + {{#if transition}} + <span> + <i class="icon-move-right"></i> + </span> + {{/if}} + <a data-key="{{key}}">{{qualifierIcon component.qualifier}} {{component.name}}</a> + </li> + {{/each}} +</ul>
\ No newline at end of file diff --git a/sonar-server/src/main/js/issues/app.js b/sonar-server/src/main/js/issues/app.js index 24bcceea5ad..86dc3f5794c 100644 --- a/sonar-server/src/main/js/issues/app.js +++ b/sonar-server/src/main/js/issues/app.js @@ -53,7 +53,7 @@ requirejs( NavigatorApp.addRegions({ - headerRegion: '.navigator-header', + workspaceRegion: '.navigator-header', filtersRegion: '.navigator-filters', resultsRegion: '.navigator-results', actionsRegion: '.navigator-actions', @@ -85,7 +85,7 @@ requirejs( app: this, model: this.favoriteFilter }); - this.headerRegion.show(this.issuesHeaderView); + this.workspaceRegion.show(this.issuesHeaderView); this.issuesView = new Extra.IssuesView({ app: this, diff --git a/sonar-server/src/main/less/component-viewer.less b/sonar-server/src/main/less/component-viewer.less index f8b175635ee..03adee5ec97 100644 --- a/sonar-server/src/main/less/component-viewer.less +++ b/sonar-server/src/main/less/component-viewer.less @@ -1,6 +1,8 @@ @import "variables"; @import "mixins"; +@workspaceWidth: 260px; + .component-viewer { width: 100%; @@ -10,41 +12,69 @@ } -.component-viewer-header { - position: relative; - height: 40px; - padding: 0 10px; - border-bottom: 1px solid @barBorderColor; - background-color: @barBackgroundColor; -} - - .component-viewer-workspace { - height: 40px; - line-height: 40px; - font-size: 0; + float: left; + width: @workspaceWidth; + .box-sizing(border-box); } .component-viewer-workspace-item { - display: inline-block; - vertical-align: middle; - font-size: @baseFontSize; + height: 30px; + line-height: 30px; + padding: 0 10px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; - &:last-child { font-weight: bold; } -} + &:first-child { + border-bottom: 1px solid @barBorderColor; + } -.component-viewer-workspace-transition { - padding: 0 10px; + &:last-child { + font-weight: bold; + } } +.component-viewer-workspace-transition { -.component-viewer-options { - position: absolute; - top: 8px; right: 10px; } .component-viewer-source { + border-left: @workspaceWidth solid @barBackgroundColor; + + .sources2 { + border-left: 1px solid @barBorderColor; + } + + .sources2 th { + height: 30px; + .box-sizing(border-box); + + &.stat { + padding-top: 4px; + padding-bottom: 4px; + border-left: none; + border-right: none; + border-bottom: 1px solid @barBorderColor; + } + + &.lid { + border-right: 1px solid @barBorderColor; + } + + &.settings { + text-align: left; + } + + &.settings-toggle { + border-right: 1px solid @barBorderColor; + text-align: center; + white-space: nowrap; + + .icon-settings { font-size: @iconSmallFontSize; } + } + } .sources2 td.line { padding: 1px 5px; @@ -56,45 +86,83 @@ } } - .sources2 td.lid { + .sources2 .stat { + min-width: 12px; padding: 1px 5px; - border-color: @barBorderColor; + border-left: 1px solid @barBorderColor; + border-right: 1px solid @barBorderColor; background-color: @barBackgroundColor; color: #888; font-size: 11px; + text-align: right; + cursor: default; } - .sources2 td.coverage { - padding: 1px 5px; - background-color: @barBackgroundColor; - color: #fff; - - &.coverage-green { background-color: @green;} - &.coverage-red { background-color: @red; } - &.coverage-orange { background-color: @orange; } + .sources2 .lid { + min-width: 18px; + padding-right: 10px; + } - a { color: #fff; } + .sources2 .coverage-tests { + cursor: pointer; } - .sources2 .row:hover { - td.lid { background-color: darken(@barBackgroundColor, 5%); } - td.line { background-color: @barBackgroundColor; } - td.coverage { background-color: darken(@barBackgroundColor, 5%); } - td.coverage.coverage-green { background-color: darken(@green, 5%); } - td.coverage.coverage-red { background-color: darken(@red, 5%); } - td.coverage.coverage-orange { background-color: darken(@orange, 5%); } + .sources2 .row { + + &.coverage-green td.stat { + background-color: lighten(@green, 15%); + border-color: lighten(@green, 7%); + color: @baseFontColor; + + &.lid { border-right-color: lighten(@green, 15%); } + } + + &.coverage-red td.stat { + background-color: lighten(@red, 15%); + border-color: lighten(@red, 10%); + color: @baseFontColor; + + &.lid { border-right-color: lighten(@red, 15%); } + } + + &:hover { + td.line { background-color: @barBackgroundColor; } + + td.stat { + background-color: darken(@barBackgroundColor, 3%); + color: @baseFontColor; + } + + &.coverage-green td.stat { background-color: lighten(@green, 10%); } + &.coverage-red td.stat { background-color: lighten(@red, 10%); } + } } } +.component-viewer-source-settings { + visibility: hidden; + + &.open { visibility: visible; } + + & > li { + display: inline; + margin-right: 10px; + } +} + + .component-viewer-popup { position: absolute; z-index: 100; + left: 0; + width: @workspaceWidth; padding: 10px; - border: 1px solid @barBorderColor; + border-top: 1px solid @barBorderColor; + border-bottom: 1px solid @barBorderColor; + .box-sizing(border-box); background-color: @white; - box-shadow: @defaultShadow; } .component-viewer-popup-section + .component-viewer-popup-section { diff --git a/sonar-server/src/main/less/ui.less b/sonar-server/src/main/less/ui.less index 9d904c6aeaa..b688616dc5b 100644 --- a/sonar-server/src/main/less/ui.less +++ b/sonar-server/src/main/less/ui.less @@ -95,6 +95,15 @@ input[type=button] { } } +.button-clean, +.button-clean:hover, +.button-clean:focus { + padding: 0; + border: none; + background: transparent; + color: @baseFontColor; +} + .button-group { display: inline-block; vertical-align: middle; |