* Major refactoring of javascript code for treemap navigation.
* Extract the execution of filters in a dedicated Ruby component : Filters.execute(filter)
:treemap_id => widget.id,
:size_metric => widget_properties['sizeMetric'],
:color_metric => widget_properties['colorMetric'],
- :heightInPercents => widget_properties['heightInPercents'],
- :resource_id => @resource.id
+ :height_in_percents => widget_properties['heightInPercents'],
+ :context_type => 'resource',
+ :context_id => @resource.id
} -%>
\ No newline at end of file
if @components_configuration.treemap_enabled? && @snapshots.size>1
@treemap = Sonar::Treemap.new(1, default_treemap_size_metric, TREEMAP_SIZE, TREEMAP_SIZE, {
:color_metric => default_treemap_color_metric,
- :root_snapshot => @snapshot,
- :browsable => false
+ :root_snapshot => @snapshot
})
end
end
- def treemap
- snapshot=Snapshot.find(params[:sid])
- not_found("Snapshot not found") unless snapshot
- access_denied unless has_role?(:user, snapshot)
-
- size_metric = (params[:size_metric] ? Metric.by_key(params[:size_metric]) : default_treemap_size_metric)
- color_metric = (params[:color_metric] ? Metric.by_key(params[:color_metric]) : default_treemap_color_metric)
-
- @treemap = Sonar::Treemap.new(1, size_metric, TREEMAP_SIZE, TREEMAP_SIZE, {
- :color_metric => color_metric,
- :root_snapshot => snapshot,
- :browsable => false
- })
-
- render(:update) do |page|
- page.replace_html 'treemap', @treemap.generate_html
- page.replace_html 'treemap_gradient', :partial => 'treemap/gradient', :locals => {:metric => @treemap.color_metric}
- page.replace_html 'treemap_set_default', :partial => 'components/treemap_set_default',
- :locals => {:controller => 'components', :size_metric => params[:size_metric], :color_metric => params[:color_metric], :rid => snapshot.project_id}
- end
- end
-
def update_default_treemap_metrics
Property.set(TREEMAP_SIZE_METRIC_PROPERTY, params[:size_metric])
Property.set(TREEMAP_COLOR_METRIC_PROPERTY, params[:color_metric])
def edit
@filter=::Filter.find(params[:id])
- access_denied unless editable_filter?(@filter)
+ access_denied unless @filter.authorized_to_edit?(self)
- options=params
- options[:user]=current_user
- @filter_context=execute_filter(FilterContext.new(@filter, options))
+ @filter_context=Filters.execute(@filter, self, params)
render :action => 'new'
end
def update
@filter=::Filter.find(params[:id])
- access_denied unless editable_filter?(@filter)
+ access_denied unless @filter.authorized_to_edit?(self)
load_filter_from_params(@filter, params)
column=FilterColumn.find(params[:id])
filter=column.filter
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
if column.deletable?
column.destroy
redirect_to :action => 'edit', :id => filter.id
+ redirect_to :action => 'edit', :id => filter.id
else
flash[:error]='Unknown column'
redirect_to :action => 'manage'
def add_column
filter=::Filter.find(params[:id])
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
filter.clean_columns_order() # clean the columns which are badly ordered (see SONAR-1902)
fields=params[:column].split(',')
column=FilterColumn.find(params[:id])
filter=column.filter
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
filter.clean_columns_order() # clean the columns which are badly ordered (see SONAR-1902)
target_column=filter.column_by_id(params[:id].to_i)
column=FilterColumn.find(params[:id])
filter=column.filter
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
filter.clean_columns_order() # clean the columns which are badly ordered (see SONAR-1902)
target_column=filter.column_by_id(params[:id].to_i)
column=FilterColumn.find(params[:id])
filter=column.filter
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
filter.columns.each do |col|
if col==column
#---------------------------------------------------------------------
def set_view
filter=::Filter.find(params[:id])
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
filter.default_view=params[:view]
filter.save
def set_columns
filter=::Filter.find(params[:id])
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
filter.columns.clear
params[:columns].each do |colstring|
def set_page_size
filter=::Filter.find(params[:id])
- access_denied unless editable_filter?(filter)
+ access_denied unless filter.authorized_to_edit?(self)
size=[::Filter::MAX_PAGE_SIZE, params[:size].to_i].min
size=[::Filter::MIN_PAGE_SIZE, size].max
#---------------------------------------------------------------------
def treemap
@filter=::Filter.find(params[:id])
- access_denied unless viewable_filter?(@filter)
+ access_denied unless @filter.authorized_to_execute?(self)
@size_metric=Metric.by_key(params[:size_metric])
@color_metric=Metric.by_key(params[:color_metric])
@filter.sorted_column=FilterColumn.new('family' => 'metric', :kee => @size_metric.key, :sort_direction => (@size_metric.direction>=0 ? 'ASC' : 'DESC'))
- options=params
- options[:user]=current_user
- @filter_context=execute_filter(FilterContext.new(@filter, options))
+ @filter_context=Filters.execute(@filter, self, params)
@width=(params[:width]||'800').to_i
@height=(params[:height]||'500').to_i
@treemap = Sonar::Treemap.new(@filter.id, @size_metric, @width, @height, {
:color_metric => @color_metric,
:period_index => @filter_context.period_index,
- :measures_by_snapshot => @filter_context.measures_by_snapshot,
- :browsable => false
+ :measures_by_snapshot => @filter_context.measures_by_snapshot
})
if @active
@filter=@active.filter
unless @filter.ajax_loading?
- options=params
- options[:user]=current_user
- @filter_context=execute_filter(FilterContext.new(@filter, options))
+ @filter_context=Filters.execute(@filter, self, params)
load_masterproject() if @filter.projects_homepage?
end
end
color_metric=(params[:color_metric].present? ? Metric.by_key(params[:color_metric]) : nil)
- resource = Project.by_key(params[:resource])
- bad_request('Unknown resource: ' + params[:resource]) unless resource
- bad_request('Data not available') unless resource.last_snapshot
- access_denied unless has_role?(:user, resource)
+ if params[:resource]
+ resource = Project.by_key(params[:resource])
+ bad_request('Unknown resource: ' + params[:resource]) unless resource
+ bad_request('Data not available') unless resource.last_snapshot
+ access_denied unless has_role?(:user, resource)
+ elsif params[:filter]
+ filter=::Filter.find(params[:filter])
+ bad_request('Unknown filter: ' + params[:filter]) unless filter
+ access_denied unless filter.authorized_to_execute?(self)
+ filter.sorted_column=FilterColumn.new('family' => 'metric', :kee => size_metric.key, :sort_direction => (size_metric.direction>=0 ? 'ASC' : 'DESC'))
+ filter_context=Filters.execute(filter, self, params)
+ else
+ bad_request('Missing parameter: resource or filter')
+ end
treemap = Sonar::Treemap.new(html_id, size_metric, width.to_i, height.to_i, {
:color_metric => color_metric,
- :root_snapshot => resource.last_snapshot,
- :period_index => params[:period_index].to_i,
- :browsable => true
+ :root_snapshot => (resource ? resource.last_snapshot : nil),
+ :measures_by_snapshot => (filter_context ? filter_context.measures_by_snapshot : nil),
+ :period_index => params[:period_index].to_i
})
render :update do |page|
- page.replace_html "tm-#{html_id}", :partial => 'treemap', :object => treemap
- page.replace_html "tm-gradient-#{html_id}", :partial => 'gradient', :locals => {:metric => color_metric}
+ page.replace_html "tm-#{html_id}", :partial => 'treemap', :object => treemap
+ page.replace_html "tm-gradient-#{html_id}", :partial => 'gradient', :locals => {:metric => color_metric}
page.hide "tm-loading-#{html_id}"
end
end
#
module FiltersHelper
- def execute_filter(filter_context)
- filter=filter_context.filter
- java_filter=Java::OrgSonarServerFilters::Filter.new
-
- #----- FILTER ON RESOURCES
- if filter.resource_id
- snapshot=Snapshot.find(:first, :conditions => {:project_id => filter.resource_id, :islast => true})
- if snapshot
- java_filter.setPath(snapshot.root_snapshot_id, snapshot.id, snapshot.path, (snapshot.view? || snapshot.subview?))
- else
- java_filter.setPath(-1, -1, '', false)
- end
- end
-
- if filter.favourites
- java_filter.setFavouriteIds((filter_context.user ? filter_context.user.favourite_ids : []).to_java(:Integer))
- end
-
- date_criterion=filter.criterion('date')
- if date_criterion
- java_filter.setDateCriterion(date_criterion.operator, date_criterion.value.to_i)
- end
-
- key_criterion=filter.criterion('key')
- if key_criterion
- java_filter.setKeyRegexp(key_criterion.text_value)
- end
-
- name_criterion=filter.criterion('name')
- if name_criterion
- java_filter.setNameRegexp(name_criterion.text_value)
- end
-
- qualifier_criterion=filter.criterion('qualifier')
- if qualifier_criterion
- java_filter.setQualifiers(qualifier_criterion.text_values.to_java(:String))
- else
- java_filter.setQualifiers([].to_java(:String))
- end
-
- language_criterion=filter.criterion('language')
- if language_criterion
- java_filter.setLanguages(language_criterion.text_values.to_java :String)
- end
-
-
- #----- FILTER ON MEASURES
- filter.measure_criteria.each do |c|
- java_filter.createMeasureCriterionOnValue(c.metric.id, c.operator, c.value, c.variation)
- end
-
-
- #----- SORTED COLUMN
- if filter_context.sorted_column_id
- filter.sorted_column=filter_context.sorted_column_id
- end
- if filter.sorted_column.on_name?
- java_filter.setSortedByName()
-
- elsif filter.sorted_column.on_date?
- java_filter.setSortedByDate()
-
- elsif filter.sorted_column.on_version?
- java_filter.setSortedByVersion()
-
- elsif filter.sorted_column.on_language?
- java_filter.setSortedByLanguage()
-
- elsif filter.sorted_column.on_metric? && filter.sorted_column.metric
- metric=filter.sorted_column.metric
- java_filter.setSortedMetricId(metric.id, metric.numeric?, filter.sorted_column.variation)
-
- end
-
-
- #----- SORTING DIRECTION
- if filter_context.ascending_sort.nil?
- java_filter.setAscendingSort(filter.sorted_column.ascending?)
- else
- filter.sorted_column.ascending=filter_context.ascending_sort
- java_filter.setAscendingSort(filter.sorted_column.ascending?)
- end
-
-
- if filter_context.ascending_sort
- filter.sorted_column.ascending=filter_context.ascending_sort
- end
- java_filter.setAscendingSort(filter.sorted_column.ascending?)
-
-
- #----- VARIATION
- java_filter.setPeriodIndex(filter_context.period_index)
-
- #----- EXECUTION
- java_result=java_facade.execute_filter(java_filter)
- snapshot_ids=extract_snapshot_ids(java_result.getRows())
-
- has_security_exclusions=(snapshot_ids.size < java_result.size())
- filter_context.process_results(snapshot_ids, has_security_exclusions)
- end
-
def column_title(column, filter)
if column.sortable?
html=link_to h(column.display_name), url_for(:overwrite_params => {:asc => (!(column.ascending?)).to_s, :sort => column.id})
[size_metric, color_metric]
end
- def viewable_filter?(filter)
- if logged_in?
- filter.shared || (filter.user==current_user)
- else
- filter.shared
- end
- end
-
- def editable_filter?(filter)
- if logged_in?
- (filter.user && filter.user==current_user) || (!filter.user && is_admin?)
- else
- false
- end
- end
-
def period_names
p1=Property.value('sonar.timemachine.period1', nil, 'previous_analysis')
p2=Property.value('sonar.timemachine.period2', nil, '5')
nil
end
end
-
- def extract_snapshot_ids(sql_rows)
- sids=[]
- project_ids=sql_rows.map{|r| r[2] ? to_integer(r[2]) : to_integer(r[1])}.compact.uniq
- authorized_pids=select_authorized(:user, project_ids)
- sql_rows.each do |row|
- pid=(row[2] ? to_integer(row[2]) : to_integer(row[1]))
- if authorized_pids.include?(pid)
- sids<<to_integer(row[0])
- end
- end
- sids
- end
-
- def to_integer(obj)
- if obj.is_a?(Fixnum)
- obj
- else
- # java.math.BigDecimal
- obj.intValue()
- end
- end
end
\ No newline at end of file
validates_length_of :name, :within => 1..100
validates_uniqueness_of :name, :scope => :user_id, :if => Proc.new { |filter| filter.user_id }
- validates_inclusion_of :default_view, :in => ['list','treemap'], :allow_nil => true
+ validates_inclusion_of :default_view, :in => ['list', 'treemap'], :allow_nil => true
def criterion(family, key=nil)
criteria.each do |criterion|
def measure_criteria
@measure_criteria ||=
begin
- criteria.select{|c| c.on_metric? && c.metric}
+ criteria.select { |c| c.on_metric? && c.metric }
end
end
end
def measure_columns
- columns.select{|col| col.metric}
+ columns.select { |col| col.metric }
end
def sorted_column
@sorted_column ||=
begin
- columns.to_a.find{|c| c.sort_direction} || column('name')
+ columns.to_a.find { |c| c.sort_direction } || column('name')
end
end
def sorted_column=(col_or_id)
if col_or_id.is_a?(Fixnum)
- @sorted_column=columns.to_a.find{|c| c.id==col_or_id}
+ @sorted_column=columns.to_a.find { |c| c.id==col_or_id }
else
@sorted_column=col_or_id
end
TREEMAP_PAGE_SIZE
else
read_attribute(:page_size) || DEFAULT_PAGE_SIZE
- end
+ end
end
def ajax_loading?
def period?
period_index && period_index>0
end
-
+
def column_by_id(col_id)
columns.each do |col|
return col if col.id==col_id
end
nil
end
-
+
def clean_columns_order
columns.each_with_index do |col, index|
col.order_index=index+1
reload
end
+ def authorized_to_execute?(authenticated_system)
+ shared || (user==authenticated_system.current_user)
+ end
+
+ def authorized_to_edit?(authenticated_system)
+ if authenticated_system.logged_in?
+ (user && user==authenticated_system.current_user) || (!user && authenticated_system.is_admin?)
+ else
+ false
+ end
+ end
+
protected
def before_validation
end
# one column must be sorted
- sorted_col=self.columns.to_a.find{|c| c.sort_direction}
+ sorted_col=self.columns.to_a.find { |c| c.sort_direction }
unless sorted_col
column('name').sort_direction='ASC'
end
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
#
class FilterContext
- attr_accessor :filter, :page_size, :page_id, :security_exclusions, :period_index, :user, :sorted_column_id, :ascending_sort
+ attr_accessor :filter, :page_size, :page_id, :security_exclusions, :period_index, :sorted_column_id, :ascending_sort
def initialize(filter, options={})
@filter = filter
@page_id=(options[:page_id] ? options[:page_id].to_i : 1)
@sorted_column_id=(options[:sort].blank? ? nil : options[:sort].to_i)
@ascending_sort=(options[:asc].blank? ? nil : options[:asc]=='true')
- @user=options[:user]
@period_index = (options[:period] ? options[:period].to_i : @filter.period_index )
@metric_ids=(options[:metric_ids] || @filter.columns.map{|col| col.metric ? col.metric.id : nil}.compact.uniq)
end
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2012 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar 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.
+#
+# Sonar 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 Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+class Filters
+
+ def self.execute(filter, authenticated_system, options={})
+ filter_context = FilterContext.new(filter, options)
+ java_filter=Java::OrgSonarServerFilters::Filter.new
+
+ #----- FILTER ON RESOURCES
+ if filter.resource_id
+ snapshot=Snapshot.find(:first, :conditions => {:project_id => filter.resource_id, :islast => true})
+ if snapshot
+ java_filter.setPath(snapshot.root_snapshot_id, snapshot.id, snapshot.path, (snapshot.view? || snapshot.subview?))
+ else
+ java_filter.setPath(-1, -1, '', false)
+ end
+ end
+
+ if filter.favourites
+ java_filter.setFavouriteIds((authenticated_system.current_user.favourite_ids||[]).to_java(:Integer))
+ end
+
+ date_criterion=filter.criterion('date')
+ if date_criterion
+ java_filter.setDateCriterion(date_criterion.operator, date_criterion.value.to_i)
+ end
+
+ key_criterion=filter.criterion('key')
+ if key_criterion
+ java_filter.setKeyRegexp(key_criterion.text_value)
+ end
+
+ name_criterion=filter.criterion('name')
+ if name_criterion
+ java_filter.setNameRegexp(name_criterion.text_value)
+ end
+
+ qualifier_criterion=filter.criterion('qualifier')
+ if qualifier_criterion
+ java_filter.setQualifiers(qualifier_criterion.text_values.to_java(:String))
+ else
+ java_filter.setQualifiers([].to_java(:String))
+ end
+
+ language_criterion=filter.criterion('language')
+ if language_criterion
+ java_filter.setLanguages(language_criterion.text_values.to_java :String)
+ end
+
+
+ #----- FILTER ON MEASURES
+ filter.measure_criteria.each do |c|
+ java_filter.createMeasureCriterionOnValue(c.metric.id, c.operator, c.value, c.variation)
+ end
+
+
+ #----- SORTED COLUMN
+ if filter_context.sorted_column_id
+ filter.sorted_column=filter_context.sorted_column_id
+ end
+ if filter.sorted_column.on_name?
+ java_filter.setSortedByName()
+
+ elsif filter.sorted_column.on_date?
+ java_filter.setSortedByDate()
+
+ elsif filter.sorted_column.on_version?
+ java_filter.setSortedByVersion()
+
+ elsif filter.sorted_column.on_language?
+ java_filter.setSortedByLanguage()
+
+ elsif filter.sorted_column.on_metric? && filter.sorted_column.metric
+ metric=filter.sorted_column.metric
+ java_filter.setSortedMetricId(metric.id, metric.numeric?, filter.sorted_column.variation)
+
+ end
+
+
+ #----- SORTING DIRECTION
+ if filter_context.ascending_sort.nil?
+ java_filter.setAscendingSort(filter.sorted_column.ascending?)
+ else
+ filter.sorted_column.ascending=filter_context.ascending_sort
+ java_filter.setAscendingSort(filter.sorted_column.ascending?)
+ end
+
+
+ if filter_context.ascending_sort
+ filter.sorted_column.ascending=filter_context.ascending_sort
+ end
+ java_filter.setAscendingSort(filter.sorted_column.ascending?)
+
+
+ #----- VARIATION
+ java_filter.setPeriodIndex(filter_context.period_index)
+
+ #----- EXECUTION
+ java_result=Java::OrgSonarServerUi::JRubyFacade.getInstance().execute_filter(java_filter)
+ snapshot_ids=extract_snapshot_ids(java_result.getRows(), authenticated_system)
+
+ has_security_exclusions=(snapshot_ids.size < java_result.size())
+ filter_context.process_results(snapshot_ids, has_security_exclusions)
+ filter_context
+ end
+
+ private
+
+ def self.extract_snapshot_ids(sql_rows, authenticated_system)
+ sids=[]
+ project_ids=sql_rows.map { |r| r[2] ? to_integer(r[2]) : to_integer(r[1]) }.compact.uniq
+ authorized_pids=authenticated_system.select_authorized(:user, project_ids)
+ sql_rows.each do |row|
+ pid=(row[2] ? to_integer(row[2]) : to_integer(row[1]))
+ if authorized_pids.include?(pid)
+ sids<<to_integer(row[0])
+ end
+ end
+ sids
+ end
+
+ def self.to_integer(obj)
+ if obj.is_a?(Fixnum)
+ obj
+ else
+ # java.math.BigDecimal
+ obj.intValue()
+ end
+ end
+end
\ No newline at end of file
include ActionView::Helpers::UrlHelper
attr_accessor :size_metric, :color_metric, :width, :height, :root_snapshot, :period_index,
- :id, :components_size, :measures, :browsable
+ :id, :components_size, :measures
def initialize(id, size_metric, width, height, options={})
@components_size = 0
@color_metric = options[:color_metric]
@root_snapshot = options[:root_snapshot]
@measures_by_snapshot = options[:measures_by_snapshot] # pre-computed measures, for example by filters
- @browsable = options[:browsable]
if options[:period_index] && options[:period_index]>0
@period_index = options[:period_index]
end
o.details_at_depth = 1
end
html = output.to_html(root)
- html += "<script>enableTreemap(#{@id},#{@components_size})</script>"
- html
+ html + "<script>treemapById(#{@id}).onLoaded(#{@components_size});</script>"
end
def empty?
:tooltip => tooltip(resource, size_measure, color_measure),
:color => html_color(color_measure),
:rid => resource.copy_resource_id || resource.id,
- :browsable => @browsable && resource.display_dashboard?)
+ :browsable => resource.display_dashboard?)
node.add_child(child)
end
end
end
def draw_label(node)
- label= "<a href='#' onclick='return openResource(#{node.rid})'>"
- label += node_label(node)
- label += "</a>"
- label
+ if node.browsable
+ "<a href='#{ApplicationController.root_context}/dashboard/index/#{node.rid}'>#{node_label(node)}</a>"
+ else
+ "<a onclick=\"window.open(this.href,'resource','height=800,width=900,scrollbars=1,resizable=1');return false;\" " +
+ "href=\"#{ApplicationController.root_context}/resource/index/#{node.rid}\">#{node_label(node)}</a>"
+ end
end
end
\ No newline at end of file
+++ /dev/null
-<%
-if color_metric && color_metric.worst_value && color_metric.best_value
- min=0
- max=0
- if color_metric.worst_value<color_metric.best_value
- min=color_metric.worst_value
- max=color_metric.best_value
- image = 'treemap_gradient.png'
- id = 'treemap_gradient_direction_positive'
- else
- min=color_metric.best_value
- max=color_metric.worst_value
- image = 'treemap_gradient_inverted.png'
- id = 'treemap_gradient_direction_negative'
- end
-%>
- <span class="note"><%= min -%><%= color_metric.suffix -%> <img id="<%= id -%>" src="<%= image_path image -%>" style="border: 1px solid #000; vertical-align:middle"> <%= max
- -%><%= color_metric.suffix -%></span>
-<%
-end
-%>
\ No newline at end of file
-<% form_tag(
- {:controller => controller, :action => "update_default_treemap_metrics", :size_metric => @treemap.size_metric.key, :color_metric => @treemap.color_metric.key, :rid => rid},
- :id => 'form_set_default') do %>
-<% end %>
+<form method="post" id="form_set_default" name="setDefaultForm" action="<%= ApplicationController.root_context -%>/components/update_default_treemap_metrics"
+ onsubmit="">
+ <input type="hidden" name="rid" value="<%= rid -%>"/>
+ <input type="hidden" name="size_metric" />
+ <input type="hidden" name="color_metric" />
+</form>
+<script>
+ function submitDefaultForm() {
+ document.setDefaultForm.size_metric.value=$F('select_size_metric');
+ document.setDefaultForm.color_metric.value=$F('select_color_metric');
+ document.setDefaultForm.submit();
+ }
+</script>
\ No newline at end of file
<%= render :partial => 'components/treemap_set_default',
:locals => {:controller => 'components', :size_metric => @treemap.size_metric.key, :color_metric => @treemap.color_metric.key, :rid => @project.id } %>
</div>
-<%
-url_params = {:action => action}
-if defined?(@snapshot) && @snapshot
- url_params[:sid]= @snapshot.id
-end
-remote_form_for :treemap, :url => url_params, :html => { :id => 'tm_form', :method => 'get' },
- :loading => "$('tm_form').disable();$('tm_loading').show();",
- :complete => "$('tm_form').enable();$('tm_loading').hide();" do |form | %>
-<%= submit_tag(value = message('update_verb'), :id => 'submit_treemap', :style => 'display:none;') %>
<table class="spaced">
<tr>
<td valign="bottom">
<span class="comments"><%= message('size') -%></span>
<br/>
<%= select_tag 'size_metric', options_grouped_by_domain(Sonar::Treemap.size_metrics, @treemap.size_metric.key),
- :id => 'select_size_metric', :class => 'small',:onchange => "$('submit_treemap').click();" %>
+ :id => 'select_size_metric', :class => 'small',:onchange => "return treemapById(1).changeSizeMetric(this.value);" %>
</td>
</tr>
<tr>
<td>
<span class="comments"><%= message('color') -%></span>
- <span id="treemap_gradient" class="comments little">
- <%= render :partial => 'components/treemap_gradient', :locals => {:color_metric => @treemap.color_metric} %>
+ <span id="tm-gradient-1" class="comments little">
+ <%= render :partial => 'treemap/gradient', :locals => {:metric => @treemap.color_metric} %>
</span>
- <%= image_tag('loading.gif', {:id => "tm_loading", :style => 'display: none;'}) %>
+ <%= image_tag('loading.gif', {:id => "tm-loading-1", :style => 'display: none;'}) %>
<br/>
<%= select_tag 'color_metric', options_grouped_by_domain(Sonar::Treemap.color_metrics, @treemap.color_metric.key),
- :id => 'select_color_metric', :class => 'small', :onchange => "$('submit_treemap').click();" %>
+ :id => 'select_color_metric', :class => 'small', :onchange => "return treemapById(1).changeColorMetric(this.value);" %>
</td>
</tr>
<% if configuring? && has_role?(:admin) %>
<tr >
- <td class="admin"><%= button_to message('set_as_default'), "#", :id => 'set_default_treemap', :onclick => "$('form_set_default').submit()" %></td>
+ <td class="admin"><%= button_to message('set_as_default'), "#", :id => 'set_default_treemap', :onclick => "submitDefaultForm();return false;" %></td>
</tr>
<% end %>
</table>
-<% end %>
-
-
-
<% if is_admin? %>
-<div id="page-operations">
- <ul class="operations">
+ <div id="page-operations">
+ <ul class="operations">
<li><%= message('customize') -%>
- <% if configuring? %>
- <span class="green"><b><%= message('on').upcase -%></b></span> |
- <a class="action" href="<%= url_for :overwrite_params => {:configuring => nil} -%>" id="configure-off"><%= message('off').upcase -%></a>
- <% else %>
- <a class="action" href="<%= url_for :overwrite_params => {:configuring => 'true'} -%>" id="configure-on"><%= message('on').upcase -%></a>
- | <span class="red"><b><%= message('off').upcase -%></b></span>
- <% end %>
+ <% if configuring? %>
+ <span class="green"><b><%= message('on').upcase -%></b></span> |
+ <a class="action" href="<%= url_for :overwrite_params => {:configuring => nil} -%>" id="configure-off"><%= message('off').upcase -%></a>
+ <% else %>
+ <a class="action" href="<%= url_for :overwrite_params => {:configuring => 'true'} -%>" id="configure-on"><%= message('on').upcase -%></a>
+ | <span class="red"><b><%= message('off').upcase -%></b></span>
+ <% end %>
</li>
- </ul>
-</div>
+ </ul>
+ </div>
<% end %>
<% if has_role?(:admin) && configuring? %>
- <%= render :partial => 'list_edit_mode_controls', :locals => {:configured_columns => @columns, :components_configuration => @components_configuration}%>
+ <%= render :partial => 'list_edit_mode_controls', :locals => {:configured_columns => @columns, :components_configuration => @components_configuration} %>
<% end %>
<% if @snapshots.empty? && @project.nil? %>
-<h3><%= message('components.no_projects_have_been_analysed') -%>No projects have been analysed.</h3>
-<p><%= message('components.explanation_launch_sonar_to_have_results') -%></p>
+ <h3><%= message('components.no_projects_have_been_analysed') -%>No projects have been analysed.</h3>
+ <p><%= message('components.explanation_launch_sonar_to_have_results') -%></p>
<% else %>
-<table width="100%">
- <tr>
- <td align="left" valign="top">
- <table id="components" class="data sortable">
- <%= render :partial => 'list_table_header', :locals => {:configured_columns => @columns} if !configuring? || ( !is_admin? && configuring? ) %>
- <%= render :partial => 'list_table_header_edit_mode', :locals => {:configured_columns => @columns} if configuring? && is_admin? %>
- <tbody>
- <% if @snapshots.empty? %>
- <tr><td colspan="<%= @columns.size + 2 -%>">No components</td></tr>
- <% else
- @snapshots.each do |snapshot| %>
- <% project = snapshot.project %>
- <tr id="project_<%= project.id -%>">
- <% alert_status_measure=search_measure(@measures_by_snapshot[snapshot], Metric::ALERT_STATUS)
- alert_status_x=(alert_status_measure ? alert_status_measure.data : '')
- %>
- <td x="<%= alert_status_x -%>" width="1%" nowrap><%= html_measure(alert_status_measure, nil, true, nil, nil, nil) %></td>
- <td width="1%" nowrap>
- <% if logged_in? %><%= link_to_favourite(project) -%><% end %>
- <%= link_to_resource(project, image_tag('zoom.png')) %>
- </td>
- <td class="left" x="<%= u(snapshot.project.name) -%>">
- <%= qualifier_icon(snapshot) %>
- <% if snapshot.project.display_dashboard? %>
- <a href="<%= ApplicationController.root_context + "/dashboard/index/#{snapshot.project.copy_resource_id || snapshot.project.id}" -%>"><%= snapshot.project.name -%></a>
- <% else %>
- <%= snapshot.project.name %>
+ <table width="100%">
+ <tr>
+ <td align="left" valign="top">
+ <table id="components" class="data sortable">
+ <%= render :partial => 'list_table_header', :locals => {:configured_columns => @columns} if !configuring? || (!is_admin? && configuring?) %>
+ <%= render :partial => 'list_table_header_edit_mode', :locals => {:configured_columns => @columns} if configuring? && is_admin? %>
+ <tbody>
+ <% if @snapshots.empty? %>
+ <tr>
+ <td colspan="<%= @columns.size + 2 -%>">No components</td>
+ </tr>
+ <% else
+ @snapshots.each do |snapshot| %>
+ <% project = snapshot.project %>
+ <tr id="project_<%= project.id -%>">
+ <% alert_status_measure=search_measure(@measures_by_snapshot[snapshot], Metric::ALERT_STATUS)
+ alert_status_x=(alert_status_measure ? alert_status_measure.data : '')
+ %>
+ <td x="<%= alert_status_x -%>" width="1%" nowrap><%= html_measure(alert_status_measure, nil, true, nil, nil, nil) %></td>
+ <td width="1%" nowrap>
+ <% if logged_in? %><%= link_to_favourite(project) -%>
+ <% end %>
+ <%= link_to_resource(project, image_tag('zoom.png')) %>
+ </td>
+ <td class="left" x="<%= u(snapshot.project.name) -%>">
+ <%= qualifier_icon(snapshot) %>
+ <% if snapshot.project.display_dashboard? %>
+ <a href="<%= ApplicationController.root_context + "/dashboard/index/#{snapshot.project.copy_resource_id || snapshot.project.id}" -%>"><%= snapshot.project.name -%></a>
+ <% else %>
+ <%= snapshot.project.name %>
+ <% end %>
+ </td>
+ <% @columns.each do |column| %>
+ <%= get_column_content(column, snapshot, @measures_by_snapshot) -%>
<% end %>
- </td>
- <% @columns.each do |column| %>
- <%= get_column_content(column, snapshot, @measures_by_snapshot) -%>
- <% end %>
- </tr>
- <% end %>
- <% end %>
- </tbody>
- </table>
- <script>TableKit.Sortable.init('components');</script>
- <p> </p>
- </td>
- <% if @treemap %>
- <td width="10px"> </td>
- <td width="<%= @treemap.width -%>" valign="top">
- <div id="treemap" class="treemap" style="height:<%= @treemap.height %>px">
- <%= @treemap.generate_html() %>
- </div>
- <%= render :partial => 'components/treemap_settings', :locals => {:action => 'treemap'} %>
+ </tr>
+ <% end %>
+ <% end %>
+ </tbody>
+ </table>
+ <script>TableKit.Sortable.init('components');</script>
+ <p> </p>
</td>
- <% end %>
- </tr>
-</table>
+ <% if @treemap %>
+ <td width="10px"> </td>
+ <td width="<%= @treemap.width -%>" valign="top">
+ <script>
+ new Treemap(1, '<%= @treemap.size_metric ? @treemap.size_metric.key : '' -%>', '<%= @treemap.color_metric ? @treemap.color_metric.key : '' -%>', 100.0).init('resource',
+ <%= @project.id -%>);
+ </script>
+
+ <div id="tm-1" class="treemap" style="height:<%= @treemap.height %>px">
+ <%= @treemap.generate_html() %>
+ </div>
+ <%= render :partial => 'components/treemap_settings', :locals => {:action => 'treemap'} %>
+ </td>
+ <% end %>
+ </tr>
+ </table>
<% end %>
-<div class="<%= widget.key %>" style="height:100%;">
+<div style="height:100%;">
<% if widget.configured %>
<%
begin
<td>
<%= select_tag 'columns[]', options_grouped_by_domain(Sonar::Treemap.color_metrics, color_metric.key),
:id => 'color_metric' %>
- <span class="comments"><%= render :partial => 'components/treemap_gradient', :locals => {:color_metric => color_metric} %></span>
</td>
</tr>
<tr>
<div id="page-operations">
<ul class="operations">
<li><a href="<%= url_for :action => 'new' -%>" ><%= message('filters.add_filter') -%></a></li>
- <% if @filter && @filter.id && editable_filter?(@filter) %>
+ <% if @filter && @filter.id && @filter.authorized_to_edit?(self) %>
<li><a href="<%= url_for :action => 'edit', :id => @filter.id -%>"><%= message('filters.edit_filter') -%></a></li>
<% end %>
<li class="last"><%= link_to message('filters.manage_filters'), {:action => 'manage'} -%></li>
<% if @filter.period? %>
-<%= message('filters.treemap_not_supported_for_period_selection') -%>
+ <%= message('filters.treemap_not_supported_for_period_selection') -%>
<% else %>
<%
- metrics=treemap_metrics(@filter)
- size_metric=metrics[0]
- color_metric=metrics[1]
+ metrics=treemap_metrics(@filter)
%>
- <div id="treemap_loading">
- <%= image_tag 'loading.gif' %>
- </div>
- <div id="treemap"> </div>
- <script>
- var treemap_width = $('treemap').getDimensions().width - 15;
- var treemap_height = document.viewport.getDimensions().height - 220;
- function load_treemap(size_metric, color_metric, hide_form) {
- $('treemap_loading').show();
- $('treemap').hide();
- <%= remote_function :update => 'treemap', :url => {:action => 'treemap', :id => @filter.id},
- :complete => "$('treemap_loading').hide();$('treemap').show();",
- :with => "'width=' + treemap_width + '&height=' + treemap_height + '&size_metric=' + size_metric + '&color_metric=' + color_metric + '&hide_form=' + hide_form" %>
- }
- load_treemap('<%= size_metric.key -%>', '<%= color_metric.key -%>', <%= edit_mode -%>);
- </script>
+ <%= render :partial => 'treemap/treemap_container', :locals => {
+ :treemap_id => @filter.id,
+ :size_metric => metrics[0],
+ :color_metric => metrics[1],
+ :height_in_percents => 50.0,
+ :context_type => 'filter',
+ :context_id => @filter.id
+ } -%>
<% end %>
\ No newline at end of file
<% end %>
</td>
<td>
- <% if editable_filter?(active.filter) %>
+ <% if active.filter.authorized_to_edit?(self) %>
<%= link_to message('edit'), {:action => 'edit', :id => active.filter_id}, :id => "edit-#{u active.name}" %> |
<%= link_to message('delete'), {:action => 'deactivate', :id => active.filter_id}, :method => :post, :confirm => message('filters.do_you_want_to_delete'), :id => "delete-#{u active.name}" %>
<% else %>
<br/>
<% end %>
-<div class="treemap">
- <%= render :partial => 'treemap/treemap' -%>
-</div>
\ No newline at end of file
+<div>
+ <%= render :partial => 'treemap/treemap', :locals => {:treemap => @treemap} -%>
+</div>
+<div style="margin: 5px 0 0 0" class="notes">
+ <div style="float: right"><span><%= message('treemap.click_help') -%></span></div>
+ <div id="tm-bc-<%= @filter.id -%>">/</div>
+</div>
<span class="comments"><%= message('size') -%></span>
<br/>
<%= select_tag "size", options_grouped_by_domain(Sonar::Treemap.size_metrics, (size_metric ? size_metric.key : nil), :include_empty => true),
- :id => "tm-size-#{treemap_id}", :class => 'small spacer-right', :onchange => "refreshTm(#{treemap_id}, null)" %>
+ :id => "tm-size-#{treemap_id}", :class => 'small spacer-right', :onchange => "return treemapById(#{treemap_id}).changeSizeMetric(this.value)" %>
</td>
<td valign="top" class="thin nowrap">
<span class="comments"><%= message('color') -%></span>
<span id="tm-gradient-<%= treemap_id -%>" class="note"></span>
<br/>
<%= select_tag 'color', options_grouped_by_domain(Sonar::Treemap.color_metrics, (color_metric ? color_metric.key : nil), :include_empty => true),
- :id => "tm-color-#{treemap_id}", :class => 'small', :onchange => "refreshTm(#{treemap_id}, null)" %>
+ :id => "tm-color-#{treemap_id}", :class => 'small', :onchange => "return treemapById(#{treemap_id}).changeColorMetric(this.value)" %>
<%= image_tag 'loading.gif', :id => "tm-loading-#{treemap_id}", :style => 'vertical-align: top;display: none' -%>
</td>
<td></td>
</tr>
</table>
- <input type="hidden" id="tm-h-<%= treemap_id -%>" value="<%= heightInPercents -%>"/>
+ <input type="hidden" id="tm-h-<%= treemap_id -%>" value="<%= height_in_percents -%>"/>
</div>
<div id="tm-<%= treemap_id -%>" class="spacer-bottom"></div>
</div>
<script>
- treemapContexts[<%= treemap_id -%>] = [
- [<%= resource_id -%>, '']
- ];
-
- refreshTm(<%= treemap_id -%>, <%= resource_id -%>);
+ new Treemap(<%= treemap_id -%>, '<%= size_metric ? size_metric.key : '' -%>', '<%= color_metric ? color_metric.key : '' -%>',
+ <%= height_in_percents -%>).init('<%= context_type -%>', <%= context_id -%>).load();
</script>
module AuthenticatedSystem
- protected
# Returns true or false if the user is logged in.
# Preloads @current_user with the user model if they're logged in.
def logged_in?
# These methods depend on the restful_authentication plugin.
#
module Helper
- protected
def has_role?(role, objects=nil)
(current_user || Anonymous.user).has_role?(role, objects)
@children = []
@rid = opts[:rid]
@browsable = opts[:browsable]
-
if(@id.nil?)
make_id
end
}
};
-var treemapContexts = {};
-function enableTreemap(treemap_id, components_size) {
- for (var i = 1; i <= components_size; i++) {
- var elt = $('tm-node-' + treemap_id + '-' + i);
- elt.oncontextmenu = function () {
- return false
- };
- elt.observe('mouseup', function (event) {
- context = treemapContexts[treemap_id];
- onTmClick(treemap_id, event, context);
- });
- }
+var treemaps = {};
+
+function treemapById(id) {
+ return treemaps[id];
}
+var TreemapContext = function (type, id, label) {
+ this.type = type;
+ this.id = id;
+ this.label = label;
+};
+
+/**
+ * HTML elements :
+ * tm-#{id} : required treemap container
+ * tm-bc-#{id} : required breadcrumb
+ * tm-loading-#{id} : optional loading icon
+ */
+var Treemap = function (id, sizeMetric, colorMetric, heightInPercents) {
+ this.id = id;
+ this.sizeMetric = sizeMetric;
+ this.colorMetric = colorMetric;
+ this.heightInPercents = heightInPercents;
+ this.breadcrumb = [];
+ treemaps[id] = this;
+};
+Treemap.prototype.initResource = function (resourceId) {
+ this.breadcrumb.push(new TreemapContext('resource', resourceId, ''));
+ return this;
+};
+Treemap.prototype.initFilter = function (filterId) {
+ this.breadcrumb.push(new TreemapContext('filter', filterId, ''));
+ return this;
+};
+Treemap.prototype.init = function (type, id) {
+ this.breadcrumb.push(new TreemapContext(type, id, ''));
+ return this;
+};
+Treemap.prototype.changeSizeMetric = function (metric) {
+ this.sizeMetric = metric;
+ this.load();
+ return false;
+};
+Treemap.prototype.changeColorMetric = function (metric) {
+ this.colorMetric = metric;
+ this.load();
+ return false;
+};
+Treemap.prototype.currentContext = function () {
+ if (this.breadcrumb.length > 0) {
+ return this.breadcrumb[this.breadcrumb.length - 1];
+ }
+ return null;
+};
+Treemap.prototype.width = function () {
+ return $('tm-' + this.id).getWidth() - 10;
+};
+Treemap.prototype.load = function () {
+ var context = this.currentContext();
+ var width = this.width();
+ var height = Math.round(width * Math.abs(this.heightInPercents / 100.0));
+ var output = '';
+ this.breadcrumb.each(function (ctx) {
+ output += ctx.label + ' / ';
+ });
+ if ($('tm-bc-' + this.id)!=null) {
+ $('tm-bc-' + this.id).innerHTML = output;}
+ var loadingIcon = $('tm-loading-' + this.id);
+ if (loadingIcon != null) {
+ loadingIcon.show();
+ }
-function onTmClick(treemap_id, event, context) {
+ new Ajax.Request(
+ baseUrl + '/treemap/index?id=' + this.id + '&width=' + width + '&height=' + height + '&size_metric=' + this.sizeMetric + '&color_metric=' + this.colorMetric + '&' + context.type + '=' + context.id,
+ {
+ asynchronous:true,
+ evalScripts:true
+ });
+};
+Treemap.prototype.htmlNode = function (nodeId) {
+ return $('tm-node-' + this.id + '-' + nodeId);
+};
+Treemap.prototype.handleClick = function (event) {
if (Event.isLeftClick(event)) {
var link = event.findElement('a');
if (link != null) {
var browsable = elt.hasAttribute('b');
if (browsable) {
var label = elt.innerText || elt.textContent;
- context.push([rid, label]);
- refreshTm(treemap_id, rid);
- } else {
- openResource(rid);
+ var context = new TreemapContext('resource', rid, label);
+ this.breadcrumb.push(context);
+ this.load();
}
} else if (Event.isRightClick(event)) {
- if (context.length > 1) {
- context.pop();
- var rid = context[context.length - 1][0];
- refreshTm(treemap_id, rid);
+ if (this.breadcrumb.length > 1) {
+ this.breadcrumb.pop();
+ this.load();
}
}
-}
-
-function refreshTm(treemap_id, resource_id) {
- var size = $F('tm-size-' + treemap_id);
- var color = $F('tm-color-' + treemap_id);
- var width = $('tm-' + treemap_id).getWidth() - 10;
- var height = Math.round(width * Math.abs(parseFloat($F('tm-h-' + treemap_id)) / 100.0));
- var rid = (resource_id != null ? resource_id : context[context.length - 1][0]);
-
- context = treemapContexts[treemap_id];
- var output = '';
- context.each(function (elt) {
- output += elt[1] + ' / ';
- });
- $('tm-bc-' + treemap_id).innerHTML = output;
- $('tm-loading-' + treemap_id).show();
-
- new Ajax.Request(
- baseUrl + '/treemap/index?id=' + treemap_id + '&width=' + width + '&height=' + height + '&size_metric=' + size + '&color_metric=' + color + '&resource=' + rid,
- {asynchronous:true, evalScripts:true});
-
- return false;
-}
+};
+Treemap.prototype.onLoaded = function (componentsSize) {
+ for (var i = 1; i <= componentsSize; i++) {
+ var elt = this.htmlNode(i);
+ elt.oncontextmenu = function () {
+ return false
+ };
+ elt.observe('mouseup', this.handleClick.bind(this));
+ }
+};
-function openResource(key) {
- document.location = baseUrl + '/dashboard/index/' + key;
+function openResource(key, options) {
+ if (typeof popup == "undefined") {
+ popup = false;
+ }
+ if (popup) {
+ window.open(this.href, 'resource', 'height=800,width=900,scrollbars=1,resizable=1');
+ } else {
+ document.location = baseUrl + '/dashboard/index/' + key;
+ }
return false;
}
\ No newline at end of file