name: 'common/select-list'
out: '<%= pkg.assets %>build/js/common/select-list.js'
+ componentViewer: options:
+ name: 'component-viewer/app'
+ out: '<%= pkg.assets %>build/js/component-viewer/app.js'
+
handlebars:
options:
'<%= pkg.assets %>js/templates/quality-gates.js': [
'<%= pkg.sources %>hbs/quality-gates/**/*.hbs'
]
+ '<%= pkg.assets %>js/templates/component-viewer.js': [
+ '<%= pkg.sources %>hbs/component-viewer/**/*.hbs'
+ ]
clean:
--- /dev/null
+requirejs.config
+ baseUrl: "#{baseUrl}/js"
+
+ paths:
+ 'backbone': 'third-party/backbone'
+ 'backbone.marionette': 'third-party/backbone.marionette'
+ 'handlebars': 'third-party/handlebars'
+ 'jquery.mockjax': 'third-party/jquery.mockjax'
+
+ shim:
+ 'backbone.marionette':
+ deps: ['backbone']
+ exports: 'Marionette'
+ 'backbone':
+ exports: 'Backbone'
+ 'handlebars':
+ exports: 'Handlebars'
+
+
+requirejs [
+ 'component-viewer/main',
+], (
+ ComponentViewer
+) ->
+
+ TEST_RESOURCE_KEY = 'org.codehaus.sonar:sonar-plugin-api:src/main/java/org/sonar/api/resources/ResourceTypeTree.java'
+
+
+ @componentViewer = new ComponentViewer()
+ @componentViewer.render().$el.appendTo '#body'
+
+ @componentViewer.open TEST_RESOURCE_KEY
\ No newline at end of file
--- /dev/null
+define [
+ 'backbone'
+ 'backbone.marionette'
+ 'templates/component-viewer'
+ 'component-viewer/source'
+], (
+ Backbone
+ Marionette
+ Templates
+ SourceView
+) ->
+
+ $ = jQuery
+ API_SOURCES = "#{baseUrl}/api/sources"
+ API_RESOURCES = "#{baseUrl}/api/resources"
+
+
+
+ class ComponentViewer extends Marionette.Layout
+ className: 'component-viewer'
+ template: Templates['layout']
+
+
+ regions:
+ sourceRegion: '.component-viewer-source'
+
+
+ initialize: ->
+ @source = new Backbone.Model()
+ @sourceView = new SourceView model: @source
+
+
+ onRender: ->
+ @sourceRegion.show @sourceView
+
+
+ requestSource: (key) ->
+ $.get API_SOURCES, resource: key, (data) =>
+ @source.set { source: data[0] }, { silent: true }
+
+
+ requestCoverage: (key) ->
+ metrics = 'coverage_line_hits_data,covered_conditions_by_line,conditions_by_line'
+
+ toObj = (data) ->
+ q = {}
+ data.split(';').forEach (item) ->
+ tokens = item.split '='
+ q[tokens[0]] = tokens[1]
+ q
+
+
+ $.get API_RESOURCES, resource: key, metrics: metrics, (data) =>
+ msr = data[0].msr
+ coverage = toObj _.findWhere(msr, key: 'coverage_line_hits_data').data
+ coverageConditions = toObj _.findWhere(msr, key: 'covered_conditions_by_line').data
+ conditions = toObj _.findWhere(msr, key: 'conditions_by_line').data
+ @source.set {
+ coverage: coverage,
+ coverageConditions: coverageConditions
+ conditions: conditions
+ }, { silent: true }
+
+
+ open: (key) ->
+ $.when(@requestSource(key), @requestCoverage(key)).done =>
+ @sourceView.render()
\ No newline at end of file
--- /dev/null
+define [
+ 'backbone.marionette'
+ 'templates/component-viewer'
+ 'common/handlebars-extensions'
+], (
+ Marionette
+ Templates
+) ->
+
+ class SourceView extends Marionette.ItemView
+ template: Templates['source']
+
+
+ modelEvents:
+ 'change': 'render'
+
+
+ serializeData: ->
+ source = @model.get 'source'
+ coverage = @model.get 'coverage'
+ coverageConditions = @model.get 'coverageConditions'
+ conditions = @model.get 'conditions'
+ source = _.map source, (code, line) ->
+ lineCoverage = coverage? && coverage[line]? && coverage[line]
+ lineCoverageConditions = coverageConditions? && coverageConditions[line]? && coverageConditions[line]
+ lineConditions = conditions? && conditions[line]? && conditions[line]
+ lineCoverageStatus = lineCoverage? && if lineCoverage > 0 then 'green' else 'red'
+ lineCoverageConditionsStatus = null
+ if lineCoverageConditions? && conditions?
+ lineCoverageConditionsStatus = 'red' if lineCoverageConditions == 0
+ lineCoverageConditionsStatus = 'orange' if lineCoverageConditions > 0 && lineCoverageConditions < lineConditions
+ lineCoverageConditionsStatus = 'green' if lineCoverageConditions == lineConditions
+
+
+ lineNumber: line
+ code: code
+ coverage: lineCoverage
+ coverageStatus: lineCoverageStatus
+ coverageConditions: lineCoverageConditions
+ conditions: lineConditions
+ coverageConditionsStatus: lineCoverageConditionsStatus
+ source: source
\ No newline at end of file
--- /dev/null
+<div class="component-viewer-source"></div>
\ No newline at end of file
--- /dev/null
+<table class="sources2 code" cellpadding="0" cellspacing="0">
+ {{#each source}}
+ <tr class="row">
+ <td class="coverage {{#if coverage}}coverage-{{coverageStatus}}{{/if}}">
+ {{#if coverage}}<span title="Line is covered by {{coverage}} tests">{{coverage}}</span>{{/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>
+ {{/if}}
+ {{/if}}
+ </td>
+ <td class="lid">{{lineNumber}}</td>
+ <td class="line"><pre>{{{code}}}</pre></td>
+ </tr>
+ {{/each}}
+</table>
\ No newline at end of file
});
Handlebars.registerHelper('sources', function(source, scm, options) {
+ if (options == null) {
+ options = scm;
+ scm = null;
+ }
+
var sources = _.map(source, function(code, line) {
return {
lineNumber: line,
--- /dev/null
+@import "variables";
+@import "mixins";
+
+
+.component-viewer {
+ width: 100%;
+ min-width: 600px;
+}
+
+
+.component-viewer-source {
+
+ .sources2 td.line {
+ padding: 1px 5px;
+
+ pre {
+ padding: 0;
+ font-family: 'inconsolata', monospace;
+ font-size: 13px;
+ }
+ }
+
+ .sources2 td.lid {
+ padding: 1px 5px;
+ border-color: @barBorderColor;
+ background-color: @barBackgroundColor;
+ color: #888;
+ font-size: 11px;
+ }
+
+ .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 .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%); }
+ }
+
+}
+
+
+@font-face {
+ font-family: 'inconsolata-bold';
+ src: url('../fonts/inconsolata-bold-webfont.woff') format('woff'),
+ url('../fonts/inconsolata-bold-webfont.svg#inconsolatabold') format('svg');
+ font-weight: normal;
+ font-style: normal;
+
+}
+
+
+
+
+@font-face {
+ font-family: 'inconsolata';
+ src: url('../fonts/inconsolata-regular-webfont.woff') format('woff'),
+ url('../fonts/inconsolata-regular-webfont.svg#inconsolataregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+
+}
\ No newline at end of file
// Colors
-@navigatorBarBackground: #f3f3f3;
-@navigatorBorderColor: darken(@navigatorBarBackground, 5%);
-@navigatorBorderLightColor: @navigatorBorderColor;
+@navigatorBarBackground: @barBackgroundColor;
+@navigatorBorderColor: @barBorderColor;
+@navigatorBorderLightColor: @barBorderColor;
@navigatorHeaderColor: darken(@blue, 10%);
@contextBorder: lighten(@purple, 30%);
+@barBackgroundColor: #f3f3f3;
+@barBorderColor: darken(@barBackgroundColor, 5%);
+
+
/*
* Icons
*/
--- /dev/null
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+class ComponentViewerController < ApplicationController
+
+ def index
+
+ end
+
+end
--- /dev/null
+<% content_for :script do %>
+ <script data-main="<%= ApplicationController.root_context -%>/js/component-viewer/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
+<% end %>
\ No newline at end of file