diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2012-11-24 17:17:54 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2012-11-26 13:54:16 +0100 |
commit | ea13e4fddb1a70c36d0c6b641825cb8289aba50b (patch) | |
tree | 7b1afc3148c33181d7e92c2cd76414b39e3c1f39 /sonar-server/src/main/webapp | |
parent | 5c920f1d8e47f3c61f951fecf3e1fa6e31a1892a (diff) | |
download | sonarqube-ea13e4fddb1a70c36d0c6b641825cb8289aba50b.tar.gz sonarqube-ea13e4fddb1a70c36d0c6b641825cb8289aba50b.zip |
SONAR-3825 manage my filters
Diffstat (limited to 'sonar-server/src/main/webapp')
13 files changed, 475 insertions, 148 deletions
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb index 25a0248df1c..ab33a006d21 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb @@ -22,16 +22,108 @@ class MeasuresController < ApplicationController SECTION=Navigation::SECTION_HOME def index + @filter = MeasureFilter.new render :action => 'search' end def search - options = { - :user => current_user, - :page => (params[:page] || 1) - } - @filter = MeasureFilter.new(params) - @filter.execute(self, options) + if params[:id] + @filter = MeasureFilter.find(params[:id]) + else + @filter = MeasureFilter.new + end + @filter.set_criteria_from_url_params(params) + @filter.execute(self, :user => current_user) end + # Load existing filter + def filter + require_parameters :id + + @filter = find_filter(params[:id]) + @filter.load_criteria_from_data + @filter.execute(self, :user => current_user) + render :action => 'search' + end + + def save_form + if params[:id].present? + @filter = find_filter(params[:id]) + else + @filter = MeasureFilter.new + end + @filter.set_criteria_from_url_params(params) + @filter.convert_criteria_to_data + render :partial => 'measures/save_form' + end + + def save + verify_post_request + access_denied unless logged_in? + + if params[:id].present? + @filter = find_filter(params[:id]) + else + @filter = MeasureFilter.new + @filter.user_id=current_user.id + end + @filter.name=params[:name] + @filter.description=params[:description] + @filter.shared=(params[:shared]=='true') + @filter.data=URI.unescape(params[:data]) + if @filter.save + render :text => @filter.id.to_s, :status => 200 + else + render :partial => 'measures/save_form', :status => 400 + end + end + + # GET /measures/manage + def manage + access_denied unless logged_in? + end + + def edit_form + require_parameters :id + @filter = find_filter(params[:id]) + render :partial => 'measures/edit_form' + end + + def edit + verify_post_request + access_denied unless logged_in? + require_parameters :id + + @filter = MeasureFilter.find(params[:id]) + access_denied unless owner?(@filter) + @filter.name=params[:name] + @filter.description=params[:description] + @filter.shared=(params[:shared]=='true') + if @filter.save + render :text => @filter.id.to_s, :status => 200 + else + render :partial => 'measures/edit_form', :status => 400 + end + end + + def delete + verify_post_request + access_denied unless logged_in? + require_parameters :id + + @filter = find_filter(params[:id]) + @filter.destroy + redirect_to :action => 'manage' + end + + private + def find_filter(id) + filter = MeasureFilter.find(id) + access_denied unless filter.shared || owner?(filter) + filter + end + + def owner?(filter) + current_user && filter.user_id==current_user.id + end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb index eb887f649f5..a4c30ef5227 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb @@ -285,14 +285,14 @@ module ApplicationHelper period_index=nil if period_index && period_index<=0 if resource.display_dashboard? if options[:dashboard] - link_to(name || resource.name, {:overwrite_params => {:controller => 'dashboard', :action => 'index', :id => resource.id, :period => period_index, - :tab => options[:tab], :rule => options[:rule]}}, :title => options[:title]) + link_to(name || resource.name, params.merge({:controller => 'dashboard', :action => 'index', :id => resource.id, :period => period_index, + :tab => options[:tab], :rule => options[:rule]}), :title => options[:title]) elsif options[:filter] - link_to(name || resource.name, {:overwrite_params => {:controller => 'dashboard', :action => 'index', :did => nil, :id => resource.id, :period => period_index, - :tab => options[:tab], :rule => options[:rule]}}, :title => options[:title]) + link_to(name || resource.name, params.merge({:controller => 'dashboard', :action => 'index', :did => nil, :id => resource.id, :period => period_index, + :tab => options[:tab], :rule => options[:rule]}), :title => options[:title]) else # stay on the same page (for example components) - link_to(name || resource.name, {:overwrite_params => {:id => resource.id, :period => period_index, :tab => options[:tab], :rule => options[:rule]}}, :title => options[:title]) + link_to(name || resource.name, params.merge({:id => resource.id, :period => period_index, :tab => options[:tab], :rule => options[:rule]}), :title => options[:title]) end else if options[:line] diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/measures_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/measures_helper.rb index 6d4beff64a9..77f3593f123 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/measures_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/measures_helper.rb @@ -19,11 +19,12 @@ # module MeasuresHelper - def list_column_title(filter, column, url_params) + def list_column_html(filter, column) + if column.sort? - html = link_to(h(column.display_name), url_params.merge({:controller => 'measures', :action => 'search', :asc => (!filter.sort_asc?).to_s, :sort => column.key})) + html = link_to(h(column.name), filter.url_params.merge({:controller => 'measures', :action => 'search', :asc => (!filter.sort_asc?).to_s, :sort => column.key})) else - html=h(column.display_name) + html=h(column.name) end #if column.variation # html="<img src='#{ApplicationController.root_context}/images/trend-up.png'></img> #{html}" @@ -35,4 +36,29 @@ module MeasuresHelper "<th class='#{column.align}'>#{html}</th>" end + def list_cell_html(column, result) + if column.metric + format_measure(result.measure(column.metric)) + elsif column.key=='name' + "#{qualifier_icon(result.snapshot)} #{link_to(result.snapshot.resource.name(true), {:controller => 'dashboard', :id => result.snapshot.resource_id}, :title => result.snapshot.resource.key)}" + elsif column.key=='short_name' + "#{qualifier_icon(result.snapshot)} #{link_to(result.snapshot.resource.name(false), {:controller => 'dashboard', :id => result.snapshot.resource_id}, :title => result.snapshot.resource.key)}" + elsif column.key=='date' + human_short_date(result.snapshot.created_at) + elsif column.key=='key' + "<span class='small'>#{result.snapshot.resource.kee}</span>" + elsif column.key=='description' + h result.snapshot.resource.description + elsif column.key=='version' + h result.snapshot.version + elsif column.key=='language' + h result.snapshot.resource.language + elsif column.key=='links' && result.links + html = '' + result.links.select { |link| link.href.start_with?('http') }.each do |link| + html += link_to(image_tag(link.icon, :alt => link.name), link.href, :class => 'nolink', :popup => true) unless link.custom? + end + html + end + end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb index fd71d2aa752..3e187330e35 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb @@ -17,9 +17,11 @@ # License along with Sonar; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 # -class MeasureFilter +require 'set' +class MeasureFilter < ActiveRecord::Base + # Row in the table of results - class Data + class Result attr_reader :snapshot, :measures_by_metric, :links def initialize(snapshot) @@ -52,7 +54,7 @@ class MeasureFilter @metric = Metric.by_key(metric_key) if metric_key end - def display_name + def name if @metric Api::Utils.message("metric.#{@metric.key}.name", :default => @metric.short_name) else @@ -61,7 +63,11 @@ class MeasureFilter end def align - (@key=='name') ? 'left' : 'right' + @align ||= + begin + # by default is table cells are left-aligned + (@key=='name' || @key=='short_name' || @key=='description') ? '' : 'right' + end end def sort? @@ -74,108 +80,168 @@ class MeasureFilter end class Display - def prepare_filter(filter, options) + attr_reader :metric_ids + + def initialize(filter) + end + + def load_links? + false end end class ListDisplay < Display - def key - 'list' + attr_reader :columns + + KEY = :list + + def initialize(filter) + filter.set_criteria_default_value('columns', ['name', 'short_name', 'description', 'links', 'date', 'language', 'version', 'alert', 'metric:ncloc', 'metric:violations']) + filter.set_criteria_default_value('sort', 'name') + filter.set_criteria_default_value('asc', 'true') + filter.set_criteria_default_value('pageSize', '30') + filter.pagination.per_page = [filter.criteria['pageSize'].to_i, 200].min + filter.pagination.page = (filter.criteria['page'] || 1).to_i + + @columns = filter.criteria['columns'].map { |column_key| Column.new(column_key) } + @metric_ids = @columns.map { |column| column.metric.id if column.metric }.compact.uniq end - def prepare_filter(filter, options) - filter.set_criteria_default_value(:columns, 'name,date,metric:ncloc,metric:violations') - filter.set_criteria_default_value(:sort, 'name') - filter.set_criteria_default_value(:asc, true) - filter.set_criteria_default_value(:listPageSize, 30) - filter.pagination.per_page = [filter.criteria[:listPageSize].to_i, 200].min - filter.pagination.page = (options[:page] || 1).to_i + def load_links? + @columns.index { |column| column.links? } end end class TreemapDisplay < Display - def key - 'treemap' - end + KEY = :treemap end - DISPLAYS = [ListDisplay.new, TreemapDisplay.new] + DISPLAYS = [ListDisplay, TreemapDisplay] - def self.register_display(display) - DISPLAYS << display - end + SUPPORTED_CRITERIA_KEYS=Set.new([:qualifiers, :scopes, :onFavourites, :base, :onBaseComponents, :languages, :fromDate, :toDate, :beforeDays, :afterDays, + :keyRegexp, :nameRegexp, + :sort, :asc, :columns, :display, :pageSize, :page]) + CRITERIA_SEPARATOR = '|' + CRITERIA_KEY_VALUE_SEPARATOR = ',' - # Simple hash {string key => fixnum or boolean or string} - attr_accessor :criteria +# Configuration available after call to execute() + attr_reader :pagination, :security_exclusions, :columns - # Configuration available after call to execute() - attr_reader :pagination, :security_exclusions, :columns, :display +# Results : sorted array of Result + attr_reader :results - # Results : sorted array of Data - attr_reader :data + belongs_to :user + validates_presence_of :name, :message => Api::Utils.message('measure_filter.missing_name') + validates_length_of :name, :maximum => 100, :message => Api::Utils.message('measure_filter.name_too_long') + validates_length_of :description, :allow_nil => true, :maximum => 4000 - def initialize(criteria={}) - @criteria = criteria - @pagination = Api::Pagination.new + def criteria + @criteria ||= {} end def sort_key - @criteria[:sort] + criteria['sort'] end def sort_asc? - @criteria[:asc]=='true' + criteria['asc']=='true' + end + +# API for plugins + def self.register_display(display_class) + DISPLAYS<<display_class + end + + def self.supported_criteria?(key) + SUPPORTED_CRITERIA_KEYS.include?(key.to_sym) + end + + def set_criteria_from_url_params(params) + @criteria = {} + params.each_pair do |k, v| + if MeasureFilter.supported_criteria?(k) && !v.empty? && v!=[''] + @criteria[k.to_s]=v + end + end + end + + def load_criteria_from_data + if self.data + @criteria = self.data.split(CRITERIA_SEPARATOR).inject({}) do |h, s| + k, v=s.split('=') + if k && v + v=v.split(CRITERIA_KEY_VALUE_SEPARATOR) if v.include?(CRITERIA_KEY_VALUE_SEPARATOR) + h[k]=v + end + h + end + else + @criteria = {} + end end - # ==== Options - # 'page' : page id starting with 1. Used in display 'list'. - # 'user' : the authenticated user - # 'period' : index of the period between 1 and 5 - # + def convert_criteria_to_data + string_data = [] + if @criteria + @criteria.each_pair do |k, v| + string_value = (v.is_a?(String) ? v : v.join(CRITERIA_KEY_VALUE_SEPARATOR)) + string_data << "#{k}=#{string_value}" + end + end + self.data = string_data.join(CRITERIA_SEPARATOR) + end + + def display + @display ||= + begin + display_class = nil + key = criteria['display'] + if key.present? + display_class = DISPLAYS.find { |d| d::KEY==key.to_sym } + end + display_class ||= DISPLAYS.first + display_class.new(self) + end + end + + +# ==== Options +# :user : the authenticated user def execute(controller, options={}) - return reset_results if @criteria.empty? - init_display - init_filter(options) + init_results user = options[:user] - rows=Api::Utils.java_facade.executeMeasureFilter2(@criteria, (user ? user.id : nil)) + rows=Api::Utils.java_facade.executeMeasureFilter2(criteria, (user ? user.id : nil)) snapshot_ids = filter_authorized_snapshot_ids(rows, controller) - init_data(snapshot_ids) + load_results(snapshot_ids) self end +# API used by Displays def set_criteria_value(key, value) if value - @criteria[key.to_sym]=value.to_s + @criteria[key.to_s]=value else - @criteria.delete(key.to_sym) + @criteria.delete(key) end end +# API used by Displays def set_criteria_default_value(key, value) - set_criteria_value(key, value) unless @criteria.has_key?(key.to_sym) + set_criteria_value(key, value) unless criteria.has_key?(key) end - private - - def init_display - key = @criteria[:display] - if key.present? - @display = DISPLAYS.find { |display| display.key==key } - end - @display ||= DISPLAYS.first + def url_params + criteria.merge({'id' => self.id}) end - def init_filter(options) - @display.prepare_filter(self, options) - @columns = @criteria[:columns].split(',').map { |col_key| Column.new(col_key) } - end + private - def reset_results + def init_results @pagination = Api::Pagination.new @security_exclusions = nil - @data = nil + @results = nil self end @@ -185,48 +251,63 @@ class MeasureFilter snapshot_ids = rows.map { |row| row.getSnapshotId() if authorized_project_ids.include?(row.getResourceRootId()) }.compact @security_exclusions = (snapshot_ids.size<rows.size) @pagination.count = snapshot_ids.size - snapshot_ids[@pagination.offset .. (@pagination.offset+@pagination.limit)] + snapshot_ids[@pagination.offset .. (@pagination.offset+@pagination.limit)] end - def init_data(snapshot_ids) - @data = [] + def load_results(snapshot_ids) + @results = [] if !snapshot_ids.empty? - data_by_snapshot_id = {} + results_by_snapshot_id = {} snapshots = Snapshot.find(:all, :include => ['project'], :conditions => ['id in (?)', snapshot_ids]) snapshots.each do |snapshot| - data = Data.new(snapshot) - data_by_snapshot_id[snapshot.id] = data + result = Result.new(snapshot) + results_by_snapshot_id[snapshot.id] = result end - # @data must be in the same order than the snapshot ids + # @results must be in the same order than the snapshot ids snapshot_ids.each do |sid| - @data << data_by_snapshot_id[sid] + @results << results_by_snapshot_id[sid] end - metric_ids = @columns.map { |column| column.metric }.compact.uniq.map { |metric| metric.id } - unless metric_ids.empty? + if display.metric_ids && !display.metric_ids.empty? measures = ProjectMeasure.find(:all, :conditions => - ['rule_priority is null and rule_id is null and characteristic_id is null and person_id is null and snapshot_id in (?) and metric_id in (?)', snapshot_ids, metric_ids] + ['rule_priority is null and rule_id is null and characteristic_id is null and person_id is null and snapshot_id in (?) and metric_id in (?)', snapshot_ids, display.metric_ids] ) measures.each do |measure| - data = data_by_snapshot_id[measure.snapshot_id] - data.add_measure measure + result = results_by_snapshot_id[measure.snapshot_id] + result.add_measure measure end end - if @columns.index { |column| column.links? } + if display.load_links? project_ids = [] - data_by_project_id = {} + results_by_project_id = {} snapshots.each do |snapshot| project_ids << snapshot.project_id - data_by_project_id[snapshot.project_id] = data_by_snapshot_id[snapshot.id] + results_by_project_id[snapshot.project_id] = results_by_snapshot_id[snapshot.id] end links = ProjectLink.find(:all, :conditions => {:project_id => project_ids}, :order => 'link_type') links.each do |link| - data_by_project_id[link.project_id].add_link(link) + results_by_project_id[link.project_id].add_link(link) end end end end + def validate + # validate uniqueness of name + if id + # update existing filter + count = MeasureFilter.count('id', :conditions => ['name=? and user_id=? and id<>?', name, user_id, id]) + else + # new filter + count = MeasureFilter.count('id', :conditions => ['name=? and user_id=?', name, user_id]) + end + errors.add_to_base('Name already exists') if count>0 + + if shared + count = MeasureFilter.count('id', :conditions => ['name=? and shared=? and user_id!=?', name, true, user_id]) + errors.add_to_base('Other users already shared filters with the same name') if count>0 + end + end end
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/user.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/user.rb index 08618b572d3..ea4fdeb8030 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/user.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/user.rb @@ -30,6 +30,7 @@ class User < ActiveRecord::Base has_many :filters, :dependent => :destroy has_many :active_dashboards, :dependent => :destroy, :order => 'order_index' has_many :dashboards, :dependent => :destroy + has_many :measure_filters, :class_name => 'MeasureFilter', :dependent => :destroy include Authentication include Authentication::ByPassword diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/widget_property.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/widget_property.rb index a6b58412fc6..2d734b4b0d7 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/widget_property.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/widget_property.rb @@ -72,7 +72,7 @@ class WidgetProperty < ActiveRecord::Base protected def validate errors.add_to_base("Unknown property: #{key}") unless java_definition - PropertyType::validate(key, type, java_definition.optional(), text_value, errors); + PropertyType::validate(key, type, java_definition.optional(), text_value, errors) end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_list.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_list.html.erb index 15648dbf9e8..ee642f3c0c9 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_list.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_list.html.erb @@ -1,43 +1,33 @@ <% display_favourites = logged_in? - colspan = @filter.columns.size + colspan = @filter.display.columns.size colspan += 1 if display_favourites %> <table class="data"> <thead> <tr> - <% if display_favourites %><th class="thin"></th><% end %> - <% @filter.columns.each do |column| %> - <%= list_column_title(@filter, column, url_params) -%> + <% if display_favourites %> + <th class="thin"></th> + <% end %> + <% @filter.display.columns.each do |column| %> + <%= list_column_html(@filter, column) -%> <% end %> </tr> </thead> <tbody> - <% @filter.data.each do |data| %> + <% @filter.results.each do |result| %> <tr class="<%= cycle 'even', 'odd' -%>"> - <% if display_favourites %><td class="thin"><%= link_to_favourite(data.snapshot.resource) -%></td><% end %> - <% @filter.columns.each do |column| %> - <% if column.metric %> - <td class="right"> - <%= format_measure(data.measure(column.metric)) -%> - </td> - <% elsif column.key=='name' %> - <td class="left"> - <%= qualifier_icon(data.snapshot) %> <%= link_to_resource(data.snapshot.resource, h(data.snapshot.resource.name(true)), {:title => data.snapshot.resource.key}) -%> - </td> - <% elsif column.key=='date' %> - <td class="right"> - <%= human_short_date(data.snapshot.created_at) -%> - </td> - <% elsif column.key=='key' %> - <td class="left"><span class="small"><%= data.snapshot.resource.kee -%></span></td> - <% else %> - <td></td> - <% end %> + <% if display_favourites %> + <td class="thin"><%= link_to_favourite(result.snapshot.resource) -%></td> + <% end %> + <% @filter.display.columns.each do |column| %> + <td class="<%= column.align -%>" > + <%= list_cell_html(column, result) -%> + </td> <% end %> </tr> <% end %> - <% if @filter.data.empty? %> + <% if @filter.results.empty? %> <tr class="even"> <td colspan="<%= colspan -%>"><%= message 'no_data' -%></td> </tr> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb new file mode 100644 index 00000000000..1708e9552c5 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb @@ -0,0 +1,33 @@ +<form id="edit-filter-form" method="post" action="<%= ApplicationController.root_context -%>/measures/edit"> + <input type="hidden" name="id" value="<%= @filter.id -%>"> + <fieldset> + <div class="form-head"> + <h2>Edit Filter</h2> + </div> + <div class="form-body"> + <% @filter.errors.each do |attr, msg| %> + <p class="error"><%= h msg -%></p> + <% end %> + <div class="form-field"> + <label for="name">Name <em class="mandatory">*</em></label> + <input id="name" name="name" type="text" size="50" maxlength="100" value="<%= h @filter.name -%>"/> + </div> + <div class="form-field"> + <label for="description">Description</label> + <input id="description" name="description" type="text" size="50" maxlength="4000" value="<%= h @filter.description -%>"/> + </div> + <div class="form-field"> + <label for="shared">Shared with all users</label> + <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if @filter.shared -%>/> + </div> + </div> + <div class="form-foot"> + <input type="submit" value="<%= h message('save') -%>" id="save-submit"/> + <a href="#" onclick="return closeModalWindow()" id="save-cancel"><%= h message('cancel') -%></a> + </div> + </fieldset> +</form> +<script> + $j("#edit-filter-form").modalForm(); + $j('#name').focus(); +</script>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_save_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_save_form.html.erb new file mode 100644 index 00000000000..0390f579c0d --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_save_form.html.erb @@ -0,0 +1,37 @@ +<form id="save-filter-form" method="post" action="<%= ApplicationController.root_context -%>/measures/save"> + <input type="hidden" name="id" value="<%= @filter.id -%>"> + <input type="hidden" name="data" value="<%= u(@filter.data) -%>"> + <fieldset> + <div class="form-head"> + <h2>Save Filter</h2> + </div> + + <div class="form-body"> + <% @filter.errors.each do |attr, msg| %> + <p class="error"><%= h msg -%></p> + <% end %> + <div class="form-field"> + <label for="name">Name <em class="mandatory">*</em></label> + <input id="name" name="name" type="text" size="50" maxlength="100" value="<%= h @filter.name -%>"/> + </div> + <div class="form-field"> + <label for="description">Description</label> + <input id="description" name="description" type="text" size="50" maxlength="4000" value="<%= h @filter.description -%>"/> + </div> + <div class="form-field"> + <label for="shared">Shared with all users</label> + <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if @filter.shared -%>/> + </div> + </div> + <div class="form-foot"> + <input type="submit" value="<%= h message('save') -%>" id="save-submit"/> + <a href="#" onclick="return closeModalWindow()" id="save-cancel"><%= h message('cancel') -%></a> + </div> + </fieldset> +</form> +<script> + $j("#save-filter-form").modalForm({success:function (data) { + window.location = baseUrl + '/measures/filter/' + data; + }}); + $j('#name').focus(); +</script>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/manage.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/manage.html.erb new file mode 100644 index 00000000000..33f46b05630 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/manage.html.erb @@ -0,0 +1,47 @@ +<div class="admin_page"> + <table class="data" id="actives"> + <thead> + <tr> + <th><%= message('name') -%></th> + <th><%= message('sharing') -%></th> + <th class="right"><%= message('operations') -%></th> + </tr> + </thead> + <tbody> + <% if current_user.measure_filters.empty? %> + <tr class="even"> + <td colspan="3"><%= message('filters.no_filters') -%></td> + </tr> + <% else %> + <% current_user.measure_filters.each do |filter| %> + <tr id="active-<%= u filter.name -%>" class="<%= cycle('even', 'odd', :name => 'actives') -%>"> + <td> + <%= link_to h(filter.name), :action => 'filter', :id => filter.id -%> + <% if filter.description %> + <div><%= h filter.description -%></div> + <% end %> + </td> + <td> + <% if filter.shared %> + Shared with all users + <% else %> + Private + <% end %> + </td> + <td class="thin nowrap right"> + <a id="edit_<%= filter.name.parameterize -%>" href="<%= ApplicationController.root_context -%>/measures/edit_form/<%= filter.id -%>" class="link-action open-modal"><%= message('edit') -%></a> + + <%= link_to_action message('delete'), "#{ApplicationController.root_context}/measures/delete/#{filter.id}", + :class => 'link-action link-red', + :id => "delete_#{filter.name.parameterize}", + :confirm_button => message('delete'), + :confirm_title => 'measure_filters.delete_confirm_title', + :confirm_msg => 'measure_filters.are_you_sure_want_delete_filter_x', + :confirm_msg_params => [filter.name] -%> + </td> + </tr> + <% end %> + <% end %> + </tbody> + </table> +</div> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/search.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/search.html.erb index 09750fc6be3..4905680ff25 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/search.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/search.html.erb @@ -20,40 +20,37 @@ </style> <% end %> -<% url_params = params.reject { |k, v| v.nil? || v=='' || k.starts_with?('_') }.merge({:controller => 'measures', :action => 'search'}) %> - <div id="measure-filter"> <div id="filter-form"> - <form method="POST" action="<%= ApplicationController.root_context -%>/measures/search"> + <form method="GET" action="<%= ApplicationController.root_context -%>/measures/search"> + <% if @filter.id %> + <input type="hidden" name="id" value="<%= @filter.id -%>"> + <% end %> <table> <tbody> <tr> <td> Base:<br> - <input type="text" name="base"> + <input type="text" name="base" value="<%= @filter.criteria['base'] -%>"> </td> </tr> <tr> <td> - Direct children:<br> - <%= check_box_tag 'onBaseChildren', 'true', params['onBaseChildren']=='true' -%> + On components:<br> + <%= check_box_tag 'onBaseComponents', 'true', @filter.criteria['onBaseComponents'] -%> </td> </tr> <tr> <td> Qualifiers:<br> - <%= select_tag 'qualifiers[]', options_for_select([['Any', ''], ['Project', 'TRK'], ['Sub-project', 'BRC'], ['Directory/Package', 'DIR']], params['qualifiers']||''), :size => 5, :multiple => true -%> + <%= select_tag 'qualifiers[]', options_for_select([['Any', ''], ['Project', 'TRK'], ['Sub-project', 'BRC'], ['Directory/Package', 'PAC'], ['File', 'CLA']], @filter.criteria['qualifiers']||''), :size => 5, :multiple => true -%> </td> </tr> <tr> <td> Language:<br> - <select name="languages[]" multiple size="5"> - <option value="" <%= 'selected' if params['languages[]'].blank? -%>>Any</option> - <% Api::Utils.languages.each do |language| %> - <option value="<%= language.key.parameterize -%>"><%= h language.name -%></option> - <% end %> - </select> + <% languages = [['Any', '']].concat(Api::Utils.languages.map { |lang| [lang.name, lang.key] }) %> + <%= select_tag 'languages[]', options_for_select(languages, @filter.criteria['languages']||''), :size => 5, :multiple => true -%> </td> </tr> <tr> @@ -69,7 +66,7 @@ <tr> <td> Favourites only:<br> - <%= check_box_tag 'favourites', 'true', params['favourites']=='true' %> + <%= check_box_tag 'onFavourites', 'true', params['onFavourites']=='true' %> </td> </tr> <tr> @@ -97,31 +94,54 @@ </tr> <tr> <td> - <input type="submit" name="_search" value="Search"> + <input type="submit" name="search" value="Search"> <a href="<%= ApplicationController.root_context -%>/measures">Reset</a> </td> </tr> </tbody> </table> </form> + + <br/> + + <% if logged_in? %> + <ul id="my-filters"> + <% current_user.measure_filters.each do |my_filter| %> + <li> + <a href="<%= ApplicationController.root_context -%>/measures/filter/<%= my_filter.id -%>"><%= h my_filter.name -%></a> + </li> + <% end %> + </ul> + <% end %> </div> - <% if @filter %> + + <% if @filter.results %> <div id="filter-result"> + <% if @filter.name %> + <h2><%= h @filter.name -%></h2> + <% if @filter.description %> + <p><%= h @filter.description -%></p> + <% end %> + <% end %> + Display as: - <% MeasureFilter::DISPLAYS.each do |display| %> - <%= link_to_if display.key!=@filter.display.key, display.key, url_params.merge(:display => display.key) -%> + <% MeasureFilter::DISPLAYS.each do |display_class| %> + <%= link_to_if display_class::KEY!=@filter.display.class::KEY, display_class::KEY, params.merge(:action => 'search', :display => display_class::KEY, :id => nil) -%> <% end %> - <%= render :partial => "measures/display_#{@filter.display.key}", :locals => {:url_params => url_params} -%> - <p> - <% permalink = url_for(url_params) %> - <a href="<%= permalink -%>">Permalink</a>: <input type="text" value="<%= permalink -%>" size="100"> - </p> + <% if logged_in? && (@filter.user_id==nil || @filter.user_id==current_user.id) %> + <a id="save_as" href="<%= url_for params.merge({:action => 'save_form', :id => @filter.id}) -%>" class="link-action open-modal"><%= message('save') -%></a> + <% end %> + + <%= render :partial => "measures/display_#{@filter.display.class::KEY}" -%> + <br> + <% if @filter.security_exclusions %> <p class="notes"><%= message('results_not_display_due_to_security') -%></p> <% end %> </div> <% end %> + </p> </div>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/356_create_measure_filters.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/356_create_measure_filters.rb index 4a50f1103aa..30f5210435a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/db/migrate/356_create_measure_filters.rb +++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/356_create_measure_filters.rb @@ -26,7 +26,7 @@ class CreateMeasureFilters < ActiveRecord::Migration create_table 'measure_filters' do |t| t.column 'name', :string, :null => false, :limit => 100 t.column 'user_id', :integer, :null => true - t.column 'shared', :boolean, :null => true + t.column 'shared', :boolean, :default => false, :null => false t.column 'description', :string, :null => true, :limit => 4000 t.column 'data', :text, :null => true t.timestamps diff --git a/sonar-server/src/main/webapp/javascripts/application.js b/sonar-server/src/main/webapp/javascripts/application.js index adb76a2821a..579609ebdcd 100644 --- a/sonar-server/src/main/webapp/javascripts/application.js +++ b/sonar-server/src/main/webapp/javascripts/application.js @@ -287,10 +287,10 @@ Treemap.prototype.onLoaded = function (componentsSize) { }); $dialog.dialog("open"); }).error(function () { - alert("Server error. Please contact your administrator."); - }).complete(function() { - $dialog.removeClass('ui-widget-overlay'); - }); + alert("Server error. Please contact your administrator."); + }).complete(function () { + $dialog.removeClass('ui-widget-overlay'); + }); $link.click(function () { $dialog.dialog('open'); @@ -301,22 +301,22 @@ Treemap.prototype.onLoaded = function (componentsSize) { }); }); }, - modalForm:function () { + modalForm:function (ajax_options) { return this.each(function () { var obj = $j(this); obj.submit(function (event) { $j('input[type=submit]', this).attr('disabled', 'disabled'); - $j.ajax({ + $j.ajax($j.extend({ type:'POST', url:obj.attr('action'), data:obj.serialize(), success:function (data) { - location.reload(); + window.location.reload(); }, error:function (xhr, textStatus, errorThrown) { $j("#modal").html(xhr.responseText); } - }); + }, ajax_options)); return false; }); }); |