From: Stas Vilchik Date: Thu, 14 Aug 2014 07:46:43 +0000 (+0600) Subject: SONAR-4406 Rework design page X-Git-Tag: 4.5-RC1~161 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=0e1e8ae3ed99f02373e2bf76c7205c8d54133428;p=sonarqube.git SONAR-4406 Rework design page --- diff --git a/server/sonar-web/src/main/coffee/design/info-view.coffee b/server/sonar-web/src/main/coffee/design/info-view.coffee new file mode 100644 index 00000000000..8020d88f52b --- /dev/null +++ b/server/sonar-web/src/main/coffee/design/info-view.coffee @@ -0,0 +1,11 @@ +define [ + 'backbone.marionette', + 'templates/design' +], ( + Marionette, + Templates +) -> + + + class extends Marionette.ItemView + template: Templates['dsm-info'] diff --git a/server/sonar-web/src/main/coffee/design/view.coffee b/server/sonar-web/src/main/coffee/design/view.coffee index 6d788a39bbb..10f24f8a752 100644 --- a/server/sonar-web/src/main/coffee/design/view.coffee +++ b/server/sonar-web/src/main/coffee/design/view.coffee @@ -1,58 +1,118 @@ define [ 'backbone.marionette', + 'design/info-view', 'templates/design' ], ( Marionette, + InfoView Templates ) -> $ = jQuery + API_DEPENDECIES = "#{baseUrl}/api/dependencies" - class AppLayout extends Marionette.Layout + class extends Marionette.Layout template: Templates['design'] className: 'dsm' + regions: + infoRegion: '.dsm-info' + + ui: titles: '.dsm-body-title' + cells: '.dsm-body-cell' + dependencies: '.dsm-body-dependency' events: 'click @ui.titles': 'highlightComponent' + 'dblclick @ui.titles': 'goToComponent' + 'click @ui.cells': 'highlightCell' + 'dblclick @ui.dependencies': 'showDependencies' + + + clearCells: -> + @ui.titles.removeClass 'dsm-body-highlighted dsm-body-usage dsm-body-dependency' + @ui.cells.removeClass 'dsm-body-highlighted dsm-body-usage dsm-body-dependency' highlightComponent: (e) -> - e.preventDefault() index = @ui.titles.index $(e.currentTarget) - @$('.dsm-body-highlighted').removeClass 'dsm-body-highlighted' - @$('.dsm-body-usage').removeClass 'dsm-body-usage' - @$('.dsm-body-dependency').removeClass 'dsm-body-dependency' + @clearCells() @highlightRow index @highlightColumn index @highlightUsages index @highlightDependencies index + highlightCell: (e) -> + cell = $(e.currentTarget) + column = cell.parent().children().index(cell) - 1 + row = cell.parent().parent().children().index cell.parent() + @clearCells() + if row == column + @highlightRow row + @highlightColumn row + @highlightUsages row + @highlightDependencies row + else + @highlightRow column, 'dsm-body-usage' + @highlightColumn column, 'dsm-body-usage' + @highlightRow row, 'dsm-body-dependency' + @highlightColumn row, 'dsm-body-dependency' + - highlightRow: (index) -> - @$(".dsm-body tr:eq(#{index}) td").addClass 'dsm-body-highlighted' + highlightRow: (index, c = 'dsm-body-highlighted') -> + @$(".dsm-body tr:eq(#{index}) td").addClass c - highlightColumn: (index) -> + highlightColumn: (index, c = 'dsm-body-highlighted') -> @$(".dsm-body tr").each -> - $(this).find("td:eq(#{index + 1})").addClass 'dsm-body-highlighted' + $(this).find("td:eq(#{index + 1})").addClass c highlightUsages: (index) -> @collection.at(index).get('v').forEach (d, i) => if i < index && d.w? - @$("tr:eq(#{i})").addClass 'dsm-body-usage' + @$("tr:eq(#{i}) .dsm-body-title").addClass 'dsm-body-usage' highlightDependencies: (index) -> @collection.forEach (model, i) => if model.get('v')[index].w? - @$("tr:eq(#{i})").addClass 'dsm-body-dependency' + @$("tr:eq(#{i}) .dsm-body-title").addClass 'dsm-body-dependency' + + + goToComponent: (e) -> + cell = $(e.currentTarget) + row = cell.parent().parent().children().index cell.parent() + model = @collection.at(row) + page = if model.get('q') == 'CLA' || model.get('q') == 'FIL' then 'dashboard' else 'design' + window.location = "#{baseUrl}/#{page}/index/#{model.get 'i'}" + + + showDependencies: (e) -> + cell = $(e.currentTarget) + column = cell.parent().children().index(cell) - 1 + row = cell.parent().parent().children().index cell.parent() + id = @collection.at(row).get('v')[column].i + @showInfoViewSpinner() + @scrollToInfoView() + $.get API_DEPENDECIES, parent: id, (data) => + @infoRegion.show new InfoView + collection: new Backbone.Collection data + @scrollToInfoView() + + + showInfoViewSpinner: -> + @infoRegion.reset() + @$(@infoRegion.el).html '' + + scrollToInfoView: -> + delta = @$(@infoRegion.el).offset().top - 40 + $('html, body').animate { scrollTop: delta }, 500 diff --git a/server/sonar-web/src/main/hbs/design/design.hbs b/server/sonar-web/src/main/hbs/design/design.hbs index cbb30d4f668..743c4db6ebd 100644 --- a/server/sonar-web/src/main/hbs/design/design.hbs +++ b/server/sonar-web/src/main/hbs/design/design.hbs @@ -23,23 +23,21 @@
- {{#each items}} + {{#eachIndex items}} - - {{#each v}} - - {{/each}} + {{/eachIndex}} - {{/each}} + {{/eachIndex}}
- - {{qualifierIcon q}} {{n}} - - + + {{qualifierIcon q}} {{n}} + -
- {{w}} -
+ {{#eachIndex v}} +
+ {{#eq index ../index}}–{{else}}{{w}}{{/eq}}
+ +
diff --git a/server/sonar-web/src/main/hbs/design/dsm-info.hbs b/server/sonar-web/src/main/hbs/design/dsm-info.hbs new file mode 100644 index 00000000000..b02c3238a72 --- /dev/null +++ b/server/sonar-web/src/main/hbs/design/dsm-info.hbs @@ -0,0 +1,17 @@ + + + {{#each items}} + + + + + + {{/each}} + +
+ {{qualifierIcon fq}} + {{fn}} + {{u}} + {{qualifierIcon tq}} + {{tn}} +
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 7846b606990..9b0a2e65bf4 100644 --- a/server/sonar-web/src/main/js/common/handlebars-extensions.js +++ b/server/sonar-web/src/main/js/common/handlebars-extensions.js @@ -88,6 +88,15 @@ define(['handlebars'], function (Handlebars) { } }); + Handlebars.registerHelper('eachIndex', function (context, options) { + var ret = ''; + context.forEach(function (d, i) { + var c = _.extend({ index: i }, d); + ret += options.fn(c); + }); + return ret; + }); + Handlebars.registerHelper('eq', function(v1, v2, options) { return v1 == v2 ? options.fn(this) : options.inverse(this); }); diff --git a/server/sonar-web/src/main/less/dsm.less b/server/sonar-web/src/main/less/dsm.less index 5f7d1ef8511..6b5f7229c3a 100644 --- a/server/sonar-web/src/main/less/dsm.less +++ b/server/sonar-web/src/main/less/dsm.less @@ -2,7 +2,7 @@ @import (reference) 'mixins'; @import (reference) 'ui'; -@cellSize: 18px; +@cellSize: 22px; .dsm { @@ -28,9 +28,9 @@ &.gray { background-color: @grey; } &.red { background-color: @red; } - &.green { background-color: @green; } + &.green { .dsm-usage-mixin; } &.blue { background-color: @blue; } - &.yellow { background-color: @orange; } + &.yellow { .dsm-dependency-mixin; } } .dsm-legend-label { @@ -40,54 +40,66 @@ } -.dsm-body { - td { - padding: 4px; - border: 1px solid @barBorderColor; - .trans(background-color); - } +.dsm-body td { + border: 1px solid @barBorderColor; } + .dsm-body-title { position: relative; - display: block; - height: @cellSize + 8px; - line-height: @cellSize + 8px; - margin: -4px; - padding: 0 15px 0 5px; + vertical-align: middle; + padding: 2px 15px 2px 4px; + border-right: 2px solid darken(@barBorderColor, 8%) !important; color: @baseFontColor; + cursor: pointer; .link-no-underline; + .trans(background-color); - &:hover, &:focus { background-color: @barBackgroundColor; } -} - -.dsm-body-title-indicator { - position: absolute; - top: 0; right: 0; - .size(10px, 26px); - - .dsm-body-usage & { background-color: @green; } - .dsm-body-dependency & { background-color: @orange; } - .dsm-body-usage.dsm-body-dependency & { background-color: @red; } + &:hover { background-color: @barBackgroundColor; } } .dsm-body-cell { - min-width: @cellSize; - height: @cellSize; - line-height: @cellSize; - padding: 0 2px; + min-width: 23px; + padding: 2px 4px; .box-sizing(border-box); text-align: center; + cursor: pointer; + .trans(background-color); +} + +.dsm-body-cell-dependency { + background-color: @grey; +} + +.dsm-body-cell-cycle { + background-color: @red !important; + color: #fff !important; } -.dsm-body-cell-dependency { background-color: @grey; } -.dsm-body-cell-cycle { background-color: @red; color: #fff; } .dsm-body-highlighted { - background-color: @lightBlue; + background-color: #dff2fd; - .dsm-body-title:hover, - .dsm-body-title:focus { - background-color: @lightBlue; + &:hover { background-color: #dff2fd; } +} + +.dsm-body-usage, .dsm-body-usage:hover { .dsm-usage-mixin; } +.dsm-body-dependency, .dsm-body-dependency:hover { .dsm-dependency-mixin; } + + +.dsm-usage-mixin() { + background-color: #e2ffbe; +} + +.dsm-dependency-mixin() { + background-color: #fde9cc; +} + + +.dsm-info { + margin-top: 15px; + + td { + padding: 2px 5px; } } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/design_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/design_controller.rb index 7ab8c83c379..5a873242d81 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/design_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/design_controller.rb @@ -31,9 +31,7 @@ class DesignController < ApplicationController def load_resource @resource=Project.by_key(params[:id]) - return redirect_to(home_path) unless @resource - access_denied unless has_role?(:admin, @resource) - @snapshot=@resource.last_snapshot + redirect_to(home_path) unless @resource end end