diff options
Diffstat (limited to 'server/sonar-web/src')
15 files changed, 161 insertions, 36 deletions
diff --git a/server/sonar-web/src/main/coffee/coding-rules/app.coffee b/server/sonar-web/src/main/coffee/coding-rules/app.coffee index 14ab0d938c5..953c0091080 100644 --- a/server/sonar-web/src/main/coffee/coding-rules/app.coffee +++ b/server/sonar-web/src/main/coffee/coding-rules/app.coffee @@ -111,11 +111,8 @@ requirejs [ App = new Marionette.Application - App.getQuery = (includeFacetsQuery = true) -> - query = @filterBarView.getQuery() - if includeFacetsQuery and @codingRulesFacetsView - _.extend query, @codingRulesFacetsView.getQuery() - query + App.getQuery = -> + @filterBarView.getQuery() App.restoreSorting = (params) -> @@ -145,18 +142,17 @@ requirejs [ - App.fetchList = (firstPage, fromFacets = false) -> - pristineQuery = @getQuery(false) - query = @getQuery(fromFacets) + App.fetchList = (firstPage) -> + query = @getQuery() - fetchQuery = _.extend { p: @pageIndex, ps: 25, facets: not fromFacets }, query + fetchQuery = _.extend { p: @pageIndex, ps: 25, facets: firstPage }, query if @codingRules.sorting && @codingRules.sorting.sort _.extend fetchQuery, s: @codingRules.sorting.sort, asc: @codingRules.sorting.asc - @storeQuery pristineQuery, @codingRules.sorting + @storeQuery query, @codingRules.sorting # Optimize requested fields _.extend fetchQuery, f: 'name,lang,status,tags,sysTags' @@ -167,7 +163,7 @@ requirejs [ scrollOffset = 0 @layout.showSpinner 'resultsRegion' - @layout.showSpinner 'facetsRegion' unless fromFacets || !firstPage + @layout.showSpinner 'facetsRegion' if firstPage jQuery.ajax @@ -206,14 +202,15 @@ requirejs [ else @codingRulesListView.selectCurrent() - unless firstPage - jQuery('.navigator-results')[0].scrollTop = scrollOffset - - unless fromFacets + if firstPage @codingRulesFacetsView = new CodingRulesFacetsView app: @ collection: new Backbone.Collection r.facets, comparator: 'property' @layout.facetsRegion.show @codingRulesFacetsView + @filterBarView.restoreFromWsQuery query + @codingRulesFacetsView.restoreFromQuery query + else + jQuery('.navigator-results')[0].scrollTop = scrollOffset @layout.onResize() @@ -224,15 +221,15 @@ requirejs [ App.facetPropertyToLabels[property](value) - App.fetchFirstPage = (fromFacets = false) -> + App.fetchFirstPage = -> @pageIndex = 1 - App.fetchList true, fromFacets + App.fetchList true - App.fetchNextPage = (fromFacets = true) -> + App.fetchNextPage = -> if @pageIndex < @codingRules.paging.pages @pageIndex++ - App.fetchList false, fromFacets + App.fetchList false App.getQualityProfile = -> diff --git a/server/sonar-web/src/main/coffee/coding-rules/router.coffee b/server/sonar-web/src/main/coffee/coding-rules/router.coffee index a6f73769b20..fe49b73dbbd 100644 --- a/server/sonar-web/src/main/coffee/coding-rules/router.coffee +++ b/server/sonar-web/src/main/coffee/coding-rules/router.coffee @@ -33,5 +33,7 @@ define [ loadResults: (params) -> @app.filterBarView.restoreFromQuery(params) + if @app.codingRulesFacetsView + @app.codingRulesFacetsView.restoreFromQuery(params) @app.restoreSorting(params) @app.fetchFirstPage() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee index b0bc3653b67..55b3f0b5720 100644 --- a/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee +++ b/server/sonar-web/src/main/coffee/coding-rules/views/coding-rules-facets-view.coffee @@ -33,18 +33,21 @@ define [ selectOption: (e) -> option = jQuery(e.currentTarget) option.toggleClass 'active' + property = option.closest('.navigator-facets-list-item').data('property') + value = option.data('key') + @options.app.filterBarView.toggle(property, value) @applyOptions() applyOptions: -> - @options.app.fetchFirstPage true + @options.app.fetchFirstPage() - getQuery: -> - q = {} - if @ui.facets.each - @ui.facets.each -> - property = jQuery(@).data 'property' - activeOptions = jQuery(@).find('.active').map(-> jQuery(@).data 'key').get() - q[property] = activeOptions.join ',' if activeOptions.length > 0 - q + restoreFromQuery: (params) -> + @ui.options.each -> + jQuery(@).removeClass('active') + @ui.facets.each -> + property = jQuery(@).data 'property' + if !!params[property] + _(params[property].split(',')).map (value) -> + jQuery('.navigator-facets-list-item[data-property="' + property + '"] .navigator-facets-list-item-option[data-key="' + value + '"]').addClass 'active' diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee index 4c9c455f2ca..b01ee86ab85 100644 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee +++ b/server/sonar-web/src/main/coffee/coding-rules/views/filter-bar-view.coffee @@ -77,3 +77,21 @@ define [ fetchNextPage: -> @options.app.fetchNextPage() + + + restoreFromWsQuery: (query) -> + params = _.map(query, (value, key) -> + 'key': key + 'value': value + ) + @restoreFromQuery params + + + toggle: (property, value) -> + filter = @collection.findWhere(property: property) + unless filter.view.isActive() + @moreCriteriaFilter.view.detailsView.enableByProperty(property) + choice = filter.view.choices.get(value) + choice.set 'checked', !choice.get('checked') + filter.view.detailsView.updateValue() + filter.view.detailsView.updateLists() diff --git a/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee b/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee index 00f379dc605..179df18a253 100644 --- a/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee +++ b/server/sonar-web/src/main/coffee/coding-rules/views/filters/activation-filter-view.coffee @@ -13,6 +13,7 @@ define [ unless @model.get 'value' @choices.each (model) -> model.set 'checked', model.id == 'true' @model.set 'value', ['true'] + @detailsView.updateLists() diff --git a/server/sonar-web/src/main/coffee/design/app.coffee b/server/sonar-web/src/main/coffee/design/app.coffee index 278196d65ed..46bedf28096 100644 --- a/server/sonar-web/src/main/coffee/design/app.coffee +++ b/server/sonar-web/src/main/coffee/design/app.coffee @@ -30,8 +30,26 @@ requirejs [ App = new Marionette.Application + App.noDataAvailable = -> + message = t 'design.noData' + $('#project-design').html "<p class=\"message-alert\"><i class=\"icon-alert-warn\"></i> #{message}</p>" + + App.addInitializer -> - $.get RESOURCES_URL, resource: window.resourceKey, metrics: 'dsm', (rawData) -> + packageTangles = {} + + packageTanglesXHR = $.get RESOURCES_URL, resource: window.resourceKey, depth: 1, metrics: 'package_tangles', (data) -> + data.forEach (component) -> + packageTangles[component.id] = component.msr[0].frmt_val + + dsmXHR = $.get RESOURCES_URL, resource: window.resourceKey, metrics: 'dsm' + dsmXHR.fail -> App.noDataAvailable() + + $.when(packageTanglesXHR, dsmXHR).done -> + rawData = dsmXHR.responseJSON + unless _.isArray(rawData) && rawData.length == 1 && _.isArray(rawData[0].msr) + App.noDataAvailable() + return data = JSON.parse rawData[0].msr[0].data data.forEach (row, rowIndex) -> row.v.forEach (cell, columnIndex) -> @@ -40,7 +58,10 @@ requirejs [ cell.status = 'cycle' else cell.status = 'dependency' - @view = new DesignView app: @, collection: new Backbone.Collection data + collection = new Backbone.Collection data + collection.forEach (model) -> + model.set 'pt', packageTangles[model.get 'i'] + @view = new DesignView app: @, collection: collection $('#project-design').empty().append @view.render().el diff --git a/server/sonar-web/src/main/hbs/design/design.hbs b/server/sonar-web/src/main/hbs/design/design.hbs index f9a7b523066..b81223774e7 100644 --- a/server/sonar-web/src/main/hbs/design/design.hbs +++ b/server/sonar-web/src/main/hbs/design/design.hbs @@ -27,6 +27,9 @@ <tr> <td class="dsm-body-title" title="{{t 'design.rowTooltip'}}"> {{qualifierIcon q}} {{n}} + {{#gt pt 0}} + <span class="dsm-body-title-package-tangles" title="{{t 'metric.package_cycles.name'}}">{{pt}}</span> + {{/gt}} <span class="dsm-body-title-indicator"></span> </td> {{#eachIndex v}} diff --git a/server/sonar-web/src/main/js/common/handlebars-extensions.js b/server/sonar-web/src/main/js/common/handlebars-extensions.js index 351f76a1d16..f6ad6a80e72 100644 --- a/server/sonar-web/src/main/js/common/handlebars-extensions.js +++ b/server/sonar-web/src/main/js/common/handlebars-extensions.js @@ -116,6 +116,10 @@ define(['handlebars'], function (Handlebars) { return v1 != v2 ? options.fn(this) : options.inverse(this); }); + Handlebars.registerHelper('gt', function(v1, v2, options) { + return v1 > v2 ? options.fn(this) : options.inverse(this); + }); + Handlebars.registerHelper('notNull', function(value, options) { return value != null ? options.fn(this) : options.inverse(this); }); diff --git a/server/sonar-web/src/main/js/widgets/timeline.js b/server/sonar-web/src/main/js/widgets/timeline.js index 26faa583c46..23ab743cd23 100644 --- a/server/sonar-web/src/main/js/widgets/timeline.js +++ b/server/sonar-web/src/main/js/widgets/timeline.js @@ -134,7 +134,7 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; }) .reduce(function(p, c) { return p.concat(c); - }, d3.extent(this.events(), function(d) { return d.d; })); + }, []); this.time = d3.time.scale().domain(d3.extent(timeDomain)); @@ -215,6 +215,10 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; // Configure events + this.events(this.events().filter(function (event) { + return event.d >= widget.time.domain()[0]; + })); + this.gevents = this.gWrap.append('g') .attr('class', 'axis events') .selectAll('.event-tick') diff --git a/server/sonar-web/src/main/less/component-viewer-source-colorizer.less b/server/sonar-web/src/main/less/component-viewer-source-colorizer.less index f80ebe3fd83..e11e0e1c402 100644 --- a/server/sonar-web/src/main/less/component-viewer-source-colorizer.less +++ b/server/sonar-web/src/main/less/component-viewer-source-colorizer.less @@ -1,4 +1,5 @@ @import (reference) 'variables'; +@import (reference) 'mixins'; .component-viewer-source { @@ -37,7 +38,12 @@ } .sym { - color: darken(saturate(@green, 10%), 15%); + @symColor: darken(saturate(@green, 10%), 15%); + border-bottom: 1px dotted @symColor; + .trans(color); + + &:hover, + &.highlighted { color: @symColor; } } } diff --git a/server/sonar-web/src/main/less/dsm.less b/server/sonar-web/src/main/less/dsm.less index 35573bd0890..3090de47e53 100644 --- a/server/sonar-web/src/main/less/dsm.less +++ b/server/sonar-web/src/main/less/dsm.less @@ -110,3 +110,13 @@ &.changed { padding-top: 7px; } } } + +.dsm-body-title-package-tangles { + float: right; + margin: 0 -10px 0 10px; + padding: 2px 5px; + border-radius: 20px; + background: @red; + font-size: @smallFontSize; + color: #fff; +} diff --git a/server/sonar-web/src/main/less/style.less b/server/sonar-web/src/main/less/style.less index 994b25358dd..9a888925388 100644 --- a/server/sonar-web/src/main/less/style.less +++ b/server/sonar-web/src/main/less/style.less @@ -2604,9 +2604,11 @@ div.rule-title { .sonar-d3 .treemap-cell-drilldown { cursor: pointer; - .trans(opacity); + .trans; - &:hover { opacity: 0.8; } + &:hover { + .scale(0.95); + } } .sonar-d3 .treemap-inner { diff --git a/server/sonar-web/src/main/less/ui.less b/server/sonar-web/src/main/less/ui.less index eeea142f5c4..710a9157cef 100644 --- a/server/sonar-web/src/main/less/ui.less +++ b/server/sonar-web/src/main/less/ui.less @@ -328,7 +328,17 @@ input[type=button] { .markdown { - a { .underlined-link; } + + table { + margin: 10px 0; + } + + th { + padding-bottom: 5px; + border-bottom: 1px solid @barBackgroundColor; + font-weight: 500; + text-transform: uppercase; + } } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/600_mysql_mediumtext_to_longtext.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/600_mysql_mediumtext_to_longtext.rb new file mode 100644 index 00000000000..2f15f3b09dc --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/600_mysql_mediumtext_to_longtext.rb @@ -0,0 +1,44 @@ +# +# 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. +# + +# +# SonarQube 4.5.1 +# +class MysqlMediumtextToLongtext < ActiveRecord::Migration + + def self.up + if dialect()=='mysql' + apply 'rules', 'description' + apply 'rules', 'note_data' + apply 'snapshot_sources', 'data' + apply 'properties', 'text_value' + apply 'measure_filters', 'data' + apply 'graphs', 'data' + apply 'snapshot_data', 'snapshot_data' + apply 'issue_changes', 'change_data' + apply 'issue_filters', 'data' + apply 'activities', 'data_field' + end + end + + def self.apply(table, column) + ActiveRecord::Base.connection.execute("alter table #{table} modify #{column} longtext") + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/gems/gems/activerecord-jdbc-adapter-1.1.3/lib/arjdbc/mysql/adapter.rb b/server/sonar-web/src/main/webapp/WEB-INF/gems/gems/activerecord-jdbc-adapter-1.1.3/lib/arjdbc/mysql/adapter.rb index 9b3d41f0ddb..163c27c06e7 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/gems/gems/activerecord-jdbc-adapter-1.1.3/lib/arjdbc/mysql/adapter.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/gems/gems/activerecord-jdbc-adapter-1.1.3/lib/arjdbc/mysql/adapter.rb @@ -103,7 +103,7 @@ module ::ArJdbc # But we would like the bigger MEDIUMTEXT for the snapshot_sources table (16777215 characters). # This hack works only for ActiveRecord-JDBC (Jruby use). # See http://www.headius.com/jrubywiki/index.php/Adding_Datatypes_to_ActiveRecord-JDBC - tp[:text] = { :name => "mediumtext" } + tp[:text] = { :name => "longtext" } tp[:binary] = { :name => "longblob" } tp[:big_integer] = { :name => "bigint"} # /SonarQube |