From 7c15d25b58f612dfa2224f5320d116a0a5c803cb Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Tue, 8 Jul 2014 17:21:44 +0600 Subject: [PATCH] SONAR-5207 Add breadcrumbs. Zooming in both directions. --- .../measures/measure_filter_treemap.html.erb | 1 + .../src/main/coffee/widgets/treemap.coffee | 114 ++++++++++++------ sonar-server/src/main/less/icons.less | 4 + sonar-server/src/main/less/style.less | 18 +++ 4 files changed, 102 insertions(+), 35 deletions(-) diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/measures/measure_filter_treemap.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/measures/measure_filter_treemap.html.erb index 67d2bd13cfb..36334a8e333 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/measures/measure_filter_treemap.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/measures/measure_filter_treemap.html.erb @@ -42,6 +42,7 @@ .metricsPriority(metrics) .options({ heightInPercents: '<%= widget_properties['heightInPercents'] -%>', + maxItems: <%= maxItems -%>, maxItemsReachedMessage: '<%= message("widget.measure_filter_histogram.max_items_reached", :params => [maxItems]) -%>', baseUrl: baseUrl + '/dashboard/index/', noData: '<%= message('no_data') -%>' diff --git a/sonar-server/src/main/coffee/widgets/treemap.coffee b/sonar-server/src/main/coffee/widgets/treemap.coffee index 91ebfa623e1..6b2ce67acca 100644 --- a/sonar-server/src/main/coffee/widgets/treemap.coffee +++ b/sonar-server/src/main/coffee/widgets/treemap.coffee @@ -1,7 +1,7 @@ class Treemap extends window.SonarWidgets.BaseWidget sizeLow: 11 sizeMedium: 13 - sizeHigh: 24 + sizeHigh: 20 constructor: -> @@ -31,19 +31,23 @@ class Treemap extends window.SonarWidgets.BaseWidget @cellsInner = @box.selectAll('.treemap-inner').data nodes @cellsInner.text (d) -> d.longName -# cellsLink = cellsEnter.append('a').classed 'treemap-dashboard', true -# cellsLink.attr 'href', (d) => -# url = @options().baseUrl + encodeURIComponent(d.key) -# url += '?metric=' + encodeURIComponent(@colorMetric.key) if d.qualifier == 'CLA' || d.qualifier == 'FIL' -# url -# cellsLink.append('i').attr 'class', (d) -> "icon-qualifier-#{d.qualifier.toLowerCase()}" - @attachEvents cellsEnter + # Show maxResultsReached message + @maxResultsReachedLabel.style 'display', if @maxResultsReached() then 'block' else 'none' + + + updateTreemap: (components, maxResultsReached) -> + @components components + @maxResultsReached maxResultsReached + + @renderTreemap() + @positionCells() + attachEvents: (cells) -> cells.on 'click', (d) => - @requestChildren d.key + @requestChildren d positionCells: -> @@ -53,8 +57,6 @@ class Treemap extends window.SonarWidgets.BaseWidget @cells.style 'height', (d) -> "#{d.dy}px" @cells.style 'line-height', (d) -> "#{d.dy}px" @cells.style 'font-size', (d) => "#{@size d.dx}px" -# @cells.classed 'treemap-cell-small', (d) -> d.dy < 60 -# @cells.classed 'treemap-cell-very-small', (d) -> d.dx < 20 || d.dy < 20 renderLegend: (box) -> @@ -64,10 +66,43 @@ class Treemap extends window.SonarWidgets.BaseWidget @legend.append('span').classed('legend-text', true).html "Size: #{@sizeMetric.name}" @legend.append('span').classed('legend-text', true).html "Color: #{@colorMetric.name}" - # Show maxResultsReached message - if @maxResultsReached() - maxResultsReachedLabel = box.append('div').text @options().maxItemsReachedMessage - maxResultsReachedLabel.classed 'max-results-reached-message', true + + renderBreadcrumbs: (box) -> + @breadcrumbsBox = box.append('div').classed 'treemap-breadcrumbs', true + @breadcrumbs = [] + d = name: '', components: @components(), maxResultsReached: @maxResultsReached() + @addToBreadcrumbs d + + + updateBreadcrumbs: -> + breadcrumbs = @breadcrumbsBox.selectAll('.treemap-breadcrumbs-item').data @breadcrumbs + breadcrumbs.exit().remove() + breadcrumbsEnter = breadcrumbs.enter().append('span').classed 'treemap-breadcrumbs-item', true + breadcrumbsEnter.append('i').classed('icon-chevron-right', true).style 'display', (d, i) -> + if i > 0 then 'inline' else 'none' + breadcrumbsEnter.append('i').attr 'class', (d) -> + if d.qualifier? then "icon-qualifier-#{d.qualifier.toLowerCase()}" else '' + breadcrumbsEnterLinks = breadcrumbsEnter.append 'a' + breadcrumbsEnterLinks.classed 'underlined-link', (d, i) -> i > 0 + breadcrumbsEnterLinks.html (d) -> d.name + breadcrumbsEnterLinks.on 'click', (d) => + @updateTreemap d.components, d.maxResultsReached + @cutBreadcrumbs d + @breadcrumbsBox.style 'display', if @breadcrumbs.length < 2 then 'none' else 'block' + + + addToBreadcrumbs: (d) -> + @breadcrumbs.push d + @updateBreadcrumbs() + + + cutBreadcrumbs: (lastElement) -> + index = null + @breadcrumbs.forEach (d, i) -> + index = i if d.key == lastElement.key + if index? + @breadcrumbs = _.initial @breadcrumbs, @breadcrumbs.length - index - 1 + @updateBreadcrumbs() render: (container) -> @@ -90,7 +125,11 @@ class Treemap extends window.SonarWidgets.BaseWidget @treemap = d3.layout.treemap() @treemap.value (d) => @sizeMetric.value d + @maxResultsReachedLabel = box.append('div').text @options().maxItemsReachedMessage + @maxResultsReachedLabel.classed 'max-results-reached-message', true + @renderLegend box + @renderBreadcrumbs box @renderTreemap() super @@ -107,29 +146,34 @@ class Treemap extends window.SonarWidgets.BaseWidget stopDrilldown: -> + formatComponents: (data) -> + components = _.filter data, (component) => + hasSizeMetric = => _.findWhere component.msr, key: @sizeMetric.key + _.isArray(component.msr) && component.msr.length > 0 && hasSizeMetric() + + if _.isArray(components) && components.length > 0 + components.map (component) => + measures = {} + component.msr.forEach (measure) -> + measures[measure.key] = val: measure.val, fval: measure.frmt_val + + key: component.key + name: component.name + longName: component.lname + qualifier: component.qualifier + measures: measures + - requestChildren: (key) -> + requestChildren: (d) -> metrics = @metricsPriority().join ',' RESOURCES_URL = "#{baseUrl}/api/resources/index" - jQuery.get(RESOURCES_URL, resource: key, depth: 1, metrics: metrics).done (r) => - components = _.filter r, (component) => - hasSizeMetric = => _.findWhere component.msr, key: @sizeMetric.key - _.isArray(component.msr) && component.msr.length > 0 && hasSizeMetric() - - if _.isArray(components) && components.length > 0 - components = components.map (component) => - measures = {} - component.msr.forEach (measure) -> - measures[measure.key] = val: measure.val, fval: measure.frmt_val - - key: component.key - name: component.name - longName: component.lname - qualifier: component.qualifier - measures: measures - @components components - @renderTreemap() - @positionCells() + jQuery.get(RESOURCES_URL, resource: d.key, depth: 1, metrics: metrics).done (r) => + components = @formatComponents r + if components? + components = _.sortBy components, (d) => @sizeMetric.value d + components = _.initial components, components.length - @options().maxItems - 1 + @updateTreemap components, components.length > @options().maxItems + @addToBreadcrumbs _.extend d, components: components, maxResultsReached: @maxResultsReached() else @stopDrilldown() diff --git a/sonar-server/src/main/less/icons.less b/sonar-server/src/main/less/icons.less index cb6edff97ab..c7ff41c31c3 100644 --- a/sonar-server/src/main/less/icons.less +++ b/sonar-server/src/main/less/icons.less @@ -473,6 +473,10 @@ a[class^="icon-"], a[class*=" icon-"] { content: "\f069"; font-size: @iconFontSize; } +.icon-home:before { + content: "\f016"; + font-size: @iconFontSize; +} /* diff --git a/sonar-server/src/main/less/style.less b/sonar-server/src/main/less/style.less index 325989f1496..4d625437987 100644 --- a/sonar-server/src/main/less/style.less +++ b/sonar-server/src/main/less/style.less @@ -2859,6 +2859,24 @@ div.rule-title { .treemap-dashboard { display: none; } } +.sonar-d3 .treemap-breadcrumbs { + margin-top: 10px; + padding-top: 7px; + border-top: 1px solid #E6E6E6; +} + +.sonar-d3 .treemap-breadcrumbs-item { + color: @secondFontColor; + + & > [class^="icon-qualifier-"] { margin-right: 4px; } +} + +.sonar-d3 .treemap-breadcrumbs-item + .treemap-breadcrumbs-item { + margin-left: 10px; + + & > .icon-chevron-right { margin-right: 10px; } +} + /* ------------------- Admin pages ------------------- */ -- 2.39.5