@Override
public String toString() {
- return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
+ return ReflectionToStringBuilder.toString(this);
}
}
public List<MeasureFilterRow> execute2(Map<String, Object> filterMap, @Nullable Long userId) throws ParseException {
Logger logger = FILTER_LOG;
MeasureFilterContext context = new MeasureFilterContext();
- context.setJson(Joiner.on("|").withKeyValueSeparator("=").join(filterMap));
context.setUserId(userId);
try {
long start = System.currentTimeMillis();
MeasureFilter filter = factory.create(filterMap);
+ context.setJson(filter.toString());
List<MeasureFilterRow> rows = executor.execute(filter, context);
log(context, rows, (System.currentTimeMillis() - start), logger);
return rows;
import javax.annotation.Nullable;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public MeasureFilter create(Map<String, Object> properties) {
MeasureFilter filter = new MeasureFilter();
- filter.setBaseResourceKey((String)properties.get("base"));
- filter.setResourceScopes((List<String>)properties.get("scopes"));
- filter.setResourceQualifiers((List<String>)(properties.get("qualifiers")));
- filter.setResourceLanguages((List<String>)(properties.get("languages")));
- if (properties.containsKey("onBaseChildren")) {
- filter.setOnBaseResourceChildren(Boolean.valueOf((String)properties.get("onBaseChildren")));
+ filter.setBaseResourceKey((String) properties.get("base"));
+ filter.setResourceScopes(toList(properties.get("scopes")));
+ filter.setResourceQualifiers(toList(properties.get("qualifiers")));
+ filter.setResourceLanguages(toList(properties.get("languages")));
+ if (properties.containsKey("onBaseComponents")) {
+ filter.setOnBaseResourceChildren(Boolean.valueOf((String) properties.get("onBaseComponents")));
}
- filter.setResourceName((String)properties.get("nameRegexp"));
- filter.setResourceKeyRegexp((String)properties.get("keyRegexp"));
+ filter.setResourceName((String) properties.get("nameRegexp"));
+ filter.setResourceKeyRegexp((String) properties.get("keyRegexp"));
if (properties.containsKey("fromDate")) {
- filter.setFromDate(toDate((String)properties.get("fromDate")));
+ filter.setFromDate(toDate((String) properties.get("fromDate")));
} else if (properties.containsKey("afterDays")) {
- filter.setFromDate(toDays((String)properties.get("afterDays")));
+ filter.setFromDate(toDays((String) properties.get("afterDays")));
}
if (properties.containsKey("toDate")) {
- filter.setToDate(toDate((String)properties.get("toDate")));
+ filter.setToDate(toDate((String) properties.get("toDate")));
} else if (properties.containsKey("beforeDays")) {
- filter.setToDate(toDays((String)properties.get("beforeDays")));
+ filter.setToDate(toDays((String) properties.get("beforeDays")));
}
- if (properties.containsKey("favourites")) {
- filter.setUserFavourites(Boolean.valueOf((String)properties.get("favourites")));
+ if (properties.containsKey("onFavourites")) {
+ filter.setUserFavourites(Boolean.valueOf((String) properties.get("onFavourites")));
}
if (properties.containsKey("asc")) {
- filter.setSortAsc(Boolean.valueOf((String)properties.get("asc")));
+ filter.setSortAsc(Boolean.valueOf((String) properties.get("asc")));
}
- String s = (String)properties.get("sort");
+ String s = (String) properties.get("sort");
if (s != null) {
if (StringUtils.startsWith(s, "metric:")) {
filter.setSortOnMetric(metricFinder.findByKey(StringUtils.substringAfter(s, "metric:")));
return filter;
}
+ private List<String> toList(@Nullable Object obj) {
+ List<String> result = null;
+ if (obj != null) {
+ if (obj instanceof String) {
+ result = Arrays.asList((String)obj);
+ } else {
+ result = (List<String>)obj;
+ }
+ }
+ return result;
+ }
+
private static Date toDate(@Nullable String date) {
if (date != null) {
return DateUtils.parseDate(date);
class MeasureFilterSort {
public static enum Field {
- KEY, NAME, VERSION, LANGUAGE, DATE, METRIC
+ KEY, NAME, VERSION, LANGUAGE, DATE, METRIC, SHORT_NAME, DESCRIPTION
}
private Field field = Field.NAME;
case NAME:
column = "p.long_name";
break;
+ case SHORT_NAME:
+ column = "p.name";
+ break;
+ case DESCRIPTION:
+ column = "p.description";
+ break;
case VERSION:
column = "s.version";
break;
CREATE TABLE "MEASURE_FILTERS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"NAME" VARCHAR(100) NOT NULL,
- "SHARED" BOOLEAN NOT NULL,
+ "SHARED" BOOLEAN NOT NULL DEFAULT FALSE,
"USER_ID" INTEGER,
"DESCRIPTION" VARCHAR(4000),
"DATA" CLOB(2147483647),
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
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]
#
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}"
"<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
# 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)
@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
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?
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
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
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
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
<%
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>
--- /dev/null
+<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
--- /dev/null
+<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
--- /dev/null
+<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>
</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>
<tr>
<td>
Favourites only:<br>
- <%= check_box_tag 'favourites', 'true', params['favourites']=='true' %>
+ <%= check_box_tag 'onFavourites', 'true', params['onFavourites']=='true' %>
</td>
</tr>
<tr>
</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
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
});
$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');
});
});
},
- 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;
});
});