measure_filter.display.treemap=Treemap
measure_filter.list.change=Change Columns
measure_filter.treemap.change=Change Treemap
-measure_filter.too_many_results=Too many results. Please refine your search.
measure_filter.add_column_button=Add Column
measure_filter.widget.unknown_filter_warning=This widget is configured to display a measure filter that doesn't exist anymore.
-
+measure_filter.error.UNKNOWN=Unexpected error. Please contact the administrator.
+measure_filter.error.TOO_MANY_RESULTS=Too many results. Please refine your search.
#------------------------------------------------------------------------------
#
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import org.apache.commons.lang.SystemUtils;
-import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerComponent;
private final MeasureFilterFactory factory;
private final MeasureFilterExecutor executor;
+ private static final int MAX_ROWS = 5000;
+
public MeasureFilterEngine(MeasureFilterFactory factory, MeasureFilterExecutor executor) {
this.executor = executor;
this.factory = factory;
}
- public List<MeasureFilterRow> execute(Map<String, Object> filterMap, @Nullable Long userId) throws ParseException {
+ public MeasureFilterResult execute(Map<String, Object> filterMap, @Nullable Long userId) {
return execute(filterMap, userId, LoggerFactory.getLogger("org.sonar.MEASURE_FILTER"));
}
@VisibleForTesting
- List<MeasureFilterRow> execute(Map<String, Object> filterMap, @Nullable Long userId, Logger logger) throws ParseException {
+ MeasureFilterResult execute(Map<String, Object> filterMap, @Nullable Long userId, Logger logger) {
+ long start = System.currentTimeMillis();
+ MeasureFilterResult result = new MeasureFilterResult();
MeasureFilterContext context = new MeasureFilterContext();
context.setUserId(userId);
context.setData(String.format("{%s}", Joiner.on('|').withKeyValueSeparator("=").join(filterMap)));
try {
- long start = System.currentTimeMillis();
MeasureFilter filter = factory.create(filterMap);
List<MeasureFilterRow> rows = executor.execute(filter, context);
- log(context, rows, (System.currentTimeMillis() - start), logger);
- return rows;
+ if (rows.size() <= MAX_ROWS) {
+ result.setRows(rows);
+ } else {
+ result.setError(MeasureFilterResult.Error.TOO_MANY_RESULTS);
+ }
+ result.setDurationInMs(System.currentTimeMillis() - start);
+ log(context, result, logger);
+
} catch (Exception e) {
- throw new IllegalStateException("Fail to execute filter: " + context, e);
+ result.setError(MeasureFilterResult.Error.UNKNOWN);
+ logger.error("Fail to execute measure filter: " + context, e);
}
+ return result;
}
- private void log(MeasureFilterContext context, List<MeasureFilterRow> rows, long durationMs, Logger logger) {
+ private void log(MeasureFilterContext context, MeasureFilterResult result, Logger logger) {
if (logger.isDebugEnabled()) {
StringBuilder log = new StringBuilder();
log.append(SystemUtils.LINE_SEPARATOR);
- log.append(" filter: ").append(context.getData()).append(SystemUtils.LINE_SEPARATOR);
+ log.append("request: ").append(context.getData()).append(SystemUtils.LINE_SEPARATOR);
+ log.append(" result: ").append(result.toString()).append(SystemUtils.LINE_SEPARATOR);
log.append(" sql: ").append(context.getSql()).append(SystemUtils.LINE_SEPARATOR);
- log.append("results: ").append(rows.size()).append(" rows in ").append(durationMs).append("ms").append(SystemUtils.LINE_SEPARATOR);
logger.debug(log.toString());
}
}
--- /dev/null
+/*
+ * Sonar, open source software quality management 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
+ */
+package org.sonar.core.measure;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+
+public class MeasureFilterResult {
+
+ public static enum Error {
+ TOO_MANY_RESULTS, UNKNOWN
+ }
+
+ private List<MeasureFilterRow> rows = null;
+ private Error error = null;
+ private long durationInMs;
+
+ MeasureFilterResult() {
+ }
+
+ public List<MeasureFilterRow> getRows() {
+ return rows;
+ }
+
+ public Error getError() {
+ return error;
+ }
+
+ public long getDurationInMs() {
+ return durationInMs;
+ }
+
+ MeasureFilterResult setDurationInMs(long l) {
+ this.durationInMs = l;
+ return this;
+ }
+
+ MeasureFilterResult setRows(@Nullable List<MeasureFilterRow> rows) {
+ this.rows = rows;
+ return this;
+ }
+
+ MeasureFilterResult setError(@Nullable Error err) {
+ this.error = err;
+ return this;
+ }
+
+ public boolean isSuccess() {
+ return error == null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (rows != null) {
+ sb.append(rows.size()).append(" rows, ");
+ }
+ if (error != null) {
+ sb.append("error=").append(error).append(", ");
+ }
+ sb.append(durationInMs).append("ms");
+ return sb.toString();
+ }
+}
}
private void init() {
- sql.append("SELECT block.id, max(block.rid) as rid, max(block.rootid) as rootid, max(sortval) as sortval");
+ sql.append("SELECT block.id, max(block.rid) AS rid, max(block.rootid) AS rootid, max(sortval) AS sortval1, CASE WHEN sortval IS NULL THEN 1 ELSE 0 END AS sortval2 ");
for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
sql.append(", max(crit_").append(index).append(")");
}
appendConditionBlock(index, condition);
}
- sql.append(") block GROUP BY block.id");
+ sql.append(") block GROUP BY block.id, sortval2");
if (!filter.getMeasureConditions().isEmpty()) {
sql.append(" HAVING ");
for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
}
}
if (filter.sort().isSortedByDatabase()) {
- sql.append(" ORDER BY sortval ");
- sql.append(filter.sort().isAsc() ? "ASC" : "DESC");
- sql.append(" NULLS LAST");
+ sql.append(" ORDER BY sortval2 ASC, sortval1 ");
+ sql.append(filter.sort().isAsc() ? "ASC " : "DESC ");
}
}
private void appendSortBlock() {
- sql.append(" SELECT s.id, s.project_id AS rid, s.root_project_id AS rootid, ").append(filter.sort().column()).append(" AS sortval");
+ sql.append(" SELECT s.id, s.project_id AS rid, s.root_project_id AS rootid, ").append(filter.sort().column()).append(" AS sortval ");
for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
sql.append(", ").append(nullSelect(condition.metric())).append(" AS crit_").append(index);
}
private void appendConditionBlock(int conditionIndex, MeasureFilterCondition condition) {
- sql.append(" SELECT s.id, s.project_id AS rid, s.root_project_id AS rootid, null AS sortval");
+ sql.append(" SELECT s.id, s.project_id AS rid, s.root_project_id AS rootid, null AS sortval ");
for (int j = 0; j < filter.getMeasureConditions().size(); j++) {
sql.append(", ");
if (j == conditionIndex) {
--- /dev/null
+/*
+ * Sonar, open source software quality management 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
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.measure;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
package org.sonar.core.measure;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
-import org.json.simple.parser.ParseException;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
-import java.util.HashMap;
import java.util.Map;
+import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class MeasureFilterEngineTest {
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
@Test
public void should_create_and_execute_filter() throws Exception {
- Map<String,Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
+ Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
MeasureFilter filter = new MeasureFilter();
when(factory.create(filterMap)).thenReturn(filter);
}
@Test
- public void throw_definition_of_filter_on_error() throws Exception {
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("filter={qualifiers=TRK}");
-
- Map<String,Object> filterMap = ImmutableMap.of("qualifiers", (Object)"TRK");
+ public void keep_error_but_do_not_fail() throws Exception {
+ Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
when(factory.create(filterMap)).thenThrow(new IllegalArgumentException());
MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor);
- engine.execute(filterMap, 50L);
+ MeasureFilterResult result = engine.execute(filterMap, 50L);
+
+ assertThat(result.isSuccess()).isFalse();
+ assertThat(result.getError()).isEqualTo(MeasureFilterResult.Error.UNKNOWN);
}
}
private static final Metric METRIC_LINES = new Metric.Builder("lines", "Lines", Metric.ValueType.INT).create().setId(1);
private static final Metric METRIC_PROFILE = new Metric.Builder("profile", "Profile", Metric.ValueType.STRING).create().setId(2);
private static final Metric METRIC_COVERAGE = new Metric.Builder("coverage", "Coverage", Metric.ValueType.FLOAT).create().setId(3);
+ private static final Metric METRIC_UNKNOWN = new Metric.Builder("unknown", "Unknown", Metric.ValueType.FLOAT).create().setId(4);
private MeasureFilterExecutor executor;
.setSortOnMetric(METRIC_COVERAGE).setSortAsc(false);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
- // Java has coverage but not PHP
+ // Java project has coverage but not PHP
assertThat(rows).hasSize(2);
verifyJavaProject(rows.get(0));
verifyPhpProject(rows.get(1));
.setSortOnMetric(METRIC_COVERAGE).setSortAsc(true);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
- // Java has coverage but not PHP
+ // Java project has coverage but not PHP
assertThat(rows).hasSize(2);
verifyJavaProject(rows.get(0));
verifyPhpProject(rows.get(1));
@Test
public void sort_by_missing_numeric_measure() throws SQLException {
// coverage measures are not computed
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_COVERAGE);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_UNKNOWN);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
// 2 files, random order
optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
delete_historical_data="[null]"/>
+ <metrics id="4" name="unknown" val_type="FLOAT" description="Coverage" domain="Test"
+ short_name="Unknown" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
+ worst_value="[null]"
+ optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
+ delete_historical_data="[null]"/>
+
<!-- java project -->
<projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
id="1" root_id="[null]"
RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+ <!-- coverage of java project -->
+ <project_measures id="1006" metric_id="3" value="12.3" snapshot_id="101"
+ url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+ variation_value_4="[null]" variation_value_5="[null]"
+ rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+ RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
+ alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
<!-- php project -->
<projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
id="10" root_id="[null]"
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
-import org.json.simple.parser.ParseException;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.License;
import org.sonar.api.workflow.screen.Screen;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.measure.MeasureFilterEngine;
-import org.sonar.core.measure.MeasureFilterRow;
+import org.sonar.core.measure.MeasureFilterResult;
import org.sonar.core.persistence.Database;
import org.sonar.core.persistence.DatabaseMigrator;
import org.sonar.core.persistence.DryRunDatabaseFactory;
return getContainer().getComponentByType(componentType);
}
- public List<MeasureFilterRow> executeMeasureFilter(Map<String, Object> map, @Nullable Long userId) throws ParseException {
+ public MeasureFilterResult executeMeasureFilter(Map<String, Object> map, @Nullable Long userId) {
return get(MeasureFilterEngine.class).execute(map, userId);
}
SECTION=Navigation::SECTION_HOME
def index
- require_parameters :qualifier
- @qualifier = params[:qualifier]
+ @qualifier = params[:qualifier]||'TRK'
bad_request("The 'qualifier' parameter is not valid. It must reference a root type.") unless Project.root_qualifiers.include?(@qualifier)
-
-
+
@filter = MeasureFilter.new
- @filter.criteria = params.merge({'qualifiers' => [@qualifier], :cols => ['name', 'description', 'links'], :sort => 'name'})
- @filter.enable_default_display
+ @filter.criteria={:qualifiers => @qualifier, :sort => 'name', :asc => (params[:asc]!='false')}
@filter.execute(self, :user => current_user)
end
"<th class='#{column.align} #{column.title_css}'>#{html}</th>"
end
- def list_cell_html(column, result)
+ def list_cell_html(column, row)
if column.metric
- measure = result.measure(column.metric)
+ measure = row.measure(column.metric)
if column.period
format_variation(measure, :index => column.period, :style => 'light')
elsif column.metric.numeric?
end
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)}"
+ "#{qualifier_icon(row.snapshot)} #{link_to(row.snapshot.resource.name(true), {:controller => 'dashboard', :id => row.snapshot.resource_id}, :title => row.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)}"
+ "#{qualifier_icon(row.snapshot)} #{link_to(row.snapshot.resource.name(false), {:controller => 'dashboard', :id => row.snapshot.resource_id}, :title => row.snapshot.resource.key)}"
elsif column.key=='date'
- human_short_date(result.snapshot.created_at)
+ human_short_date(row.snapshot.created_at)
elsif column.key=='key'
- "<span class='small'>#{result.snapshot.resource.kee}</span>"
+ "<span class='small'>#{row.snapshot.resource.kee}</span>"
elsif column.key=='description'
- h result.snapshot.resource.description
+ h row.snapshot.resource.description
elsif column.key=='version'
- h result.snapshot.version
+ h row.snapshot.version
elsif column.key=='language'
- Api::Utils.language_name(result.snapshot.resource.language)
- elsif column.key=='links' && result.links
+ Api::Utils.language_name(row.snapshot.resource.language)
+ elsif column.key=='links' && row.links
html = ''
- result.links.select { |link| link.href.start_with?('http') }.each do |link|
+ row.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
class MeasureFilter < ActiveRecord::Base
# Row in the table of results
- class Result
+ class Row
attr_reader :snapshot, :measures_by_metric, :links
def initialize(snapshot)
validates_length_of :name, :maximum => 100, :message => Api::Utils.message('measure_filter.name_too_long')
validates_length_of :description, :allow_nil => true, :maximum => 4000
- attr_reader :pagination, :security_exclusions, :base_result, :results, :display
+ attr_reader :pagination, :security_exclusions, :base_row, :rows, :display
def sort_key
end
def sort_asc?
- criteria['asc']=='true'
+ criteria['asc']!='false'
end
# array of the metrics to use when loading measures
def set_criteria_value(key, value)
@criteria ||= HashWithIndifferentAccess.new
if key
- if value && value!='' && value!=['']
- value = value.to_s if value.is_a?(Fixnum)
- @criteria[key]=value
+ if value!=nil && value!='' && value!=['']
+ @criteria[key]=(value.kind_of?(Array) ? value : value.to_s)
else
@criteria.delete(key)
end
init_results
init_display(options)
user = options[:user]
- rows=Api::Utils.java_facade.executeMeasureFilter(criteria, (user ? user.id : nil))
- snapshot_ids = filter_authorized_snapshot_ids(rows, controller)
- load_results(snapshot_ids)
+ result = Api::Utils.java_facade.executeMeasureFilter(criteria, (user ? user.id : nil))
+ if result.error
+ errors.add_to_base(Api::Utils.message("measure_filter.error.#{result.error}"))
+ else
+ rows = result.getRows()
+ snapshot_ids = filter_authorized_snapshot_ids(rows, controller)
+ load_results(snapshot_ids)
+ end
self
end
def init_results
@pagination = Api::Pagination.new
@security_exclusions = nil
- @results = nil
- @base_result = nil
+ @rows = nil
+ @base_row = nil
self
end
end
def load_results(snapshot_ids)
- @results = []
+ @rows = []
metric_ids = metrics.map(&:id)
if !snapshot_ids.empty?
- results_by_snapshot_id = {}
+ rows_by_snapshot_id = {}
snapshots = Snapshot.find(:all, :include => ['project'], :conditions => ['id in (?)', snapshot_ids])
snapshots.each do |snapshot|
- result = Result.new(snapshot)
- results_by_snapshot_id[snapshot.id] = result
+ row = Row.new(snapshot)
+ rows_by_snapshot_id[snapshot.id] = row
end
- # @results must be in the same order than the snapshot ids
+ # @rows must be in the same order than the snapshot ids
snapshot_ids.each do |sid|
- @results << results_by_snapshot_id[sid]
+ @rows << rows_by_snapshot_id[sid]
end
unless metric_ids.empty?
['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]
)
measures.each do |measure|
- result = results_by_snapshot_id[measure.snapshot_id]
- result.add_measure(measure)
+ row = rows_by_snapshot_id[measure.snapshot_id]
+ row.add_measure(measure)
end
end
if require_links?
project_ids = []
- results_by_project_id = {}
+ rows_by_project_id = {}
snapshots.each do |snapshot|
project_ids << snapshot.project_id
- results_by_project_id[snapshot.project_id] = results_by_snapshot_id[snapshot.id]
+ rows_by_project_id[snapshot.project_id] = rows_by_snapshot_id[snapshot.id]
end
links = ProjectLink.find(:all, :conditions => {:project_id => project_ids}, :order => 'link_type')
links.each do |link|
- results_by_project_id[link.project_id].add_link(link)
+ rows_by_project_id[link.project_id].add_link(link)
end
end
end
if base_resource
base_snapshot = base_resource.last_snapshot
if base_snapshot
- @base_result = Result.new(base_snapshot)
+ @base_row = Row.new(base_snapshot)
unless metric_ids.empty?
base_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=? and metric_id in (?)', base_snapshot.id, metric_ids]
)
base_measures.each do |base_measure|
- @base_result.add_measure(base_measure)
+ @base_row.add_measure(base_measure)
end
end
end
end
def html
- if filter.results
+ if filter.rows
root = Treemap::Node.new(:id => -1, :label => '')
build_tree(root)
end
def empty?
- @filter.results.nil? || @filter.results.empty?
+ @filter.rows.nil? || @filter.rows.empty?
end
def url_params
private
def build_tree(node)
- if @filter.results && @size_metric
- @filter.results.each do |result|
- size_measure=result.measure(@size_metric)
+ if @filter.rows && @size_metric
+ @filter.rows.each do |row|
+ size_measure=row.measure(@size_metric)
if size_measure
- color_measure=(@color_metric ? result.measure(@color_metric) : nil)
- resource = result.snapshot.resource
+ color_measure=(@color_metric ? row.measure(@color_metric) : nil)
+ resource = row.snapshot.resource
child = Treemap::Node.new(:size => size_value(size_measure),
:label => resource.name(false),
:title => escape_javascript(resource.name(true)),
-<% content_for :script do %>
- <script>
- function removeUrlAttr(url, attribute_key) {
- var regexp = new RegExp("&?" + attribute_key + "=([^&]$|[^&]*)", "g");
- return url.replace(regexp, '');
- }
- function reloadParameters(params) {
- var url = decodeURI(window.location.href);
- $j.each(params, function (key, value) {
- url = removeUrlAttr(url, key);
- url += '&' + key + '=' + value;
- });
- window.location = url;
- }
- </script>
-<% end %>
+<% if @filter.rows %>
-<% if @filter.results %>
-
- <h1><%= message('qualifiers.all.' + @qualifier) -%></h1>
- <br/>
+ <h1 class="marginbottom10"><%= message('qualifiers.all.' + @qualifier) -%></h1>
<div id="all-projects">
<% if @filter.security_exclusions %>
- <p class="notes"><%= message('results_not_display_due_to_security') -%></p>
+ <p class="notes"><%= message('rows_not_display_due_to_security') -%></p>
<% end %>
<%
<th class="thin" style></th>
<% end %>
<th class="thin nowrap">
- <%= link_to_function( message('all-projects.cols.name'), "reloadParameters({asc:'#{(!@filter.sort_asc?).to_s}', sort:'name'})") -%>
- <% if @filter.sort_key=='name' %>
- <%= @filter.sort_asc? ? image_tag("asc12.png") : image_tag("desc12.png") -%>
- <% end %>
+ <%= link_to message('all-projects.cols.name'), {:action => 'index', :qualifier => params[:qualifier], :asc => (!@filter.sort_asc?).to_s} -%>
+ <%= @filter.sort_asc? ? image_tag("asc12.png") : image_tag("desc12.png") -%>
</th>
<th></th>
<th></th>
</thead>
<tbody>
- <% @filter.results.each do |result| %>
+ <% @filter.rows.each do |row| %>
<tr class="<%= cycle 'even', 'odd' -%>">
<% if display_favourites %>
- <td class="thin"><%= link_to_favourite(result.snapshot.resource) -%></td>
+ <td class="thin"><%= link_to_favourite(row.snapshot.resource) -%></td>
<% end %>
<td class="nowrap">
- <%= qualifier_icon(result.snapshot)-%> <%= link_to(result.snapshot.resource.name(true), {:controller => 'dashboard', :id => result.snapshot.resource_id}, :title => result.snapshot.resource.key) -%>
+ <%= qualifier_icon(row.snapshot)-%> <%= link_to(row.snapshot.resource.name(true), {:controller => 'dashboard', :id => row.snapshot.resource_id}, :title => row.snapshot.resource.key) -%>
</td>
<td class="sep"></td>
<td>
- <%= h result.snapshot.resource.description -%>
+ <%= h row.snapshot.resource.description -%>
</td>
<td class="sep"></td>
<td class="nowrap right">
<%
- if result.links
- result.links.select { |link| link.href.start_with?('http') }.each do |link|
+ if row.links
+ row.links.select { |link| link.href.start_with?('http') }.each do |link|
%>
<%= link_to(image_tag(link.icon, :alt => link.name), link.href, :class => 'nolink', :popup => true) unless link.custom? -%>
<%
</tr>
<% end %>
- <% if @filter.results.empty? %>
+ <% if @filter.rows.empty? %>
<tr class="even">
<td colspan="<%= colspan -%>"><%= message 'no_data' -%></td>
</tr>
<%= render :partial => 'utils/tfoot_pagination', :locals => {:pagination => @filter.pagination, :colspan => colspan} %>
</table>
-
</div>
<% end %>
\ No newline at end of file
:mean_color => Color::RGB.from_html("4D05B1"), # purple
:max_color => Color::RGB.from_html("2360BF") # blue
}
- size_measure_values = filter.results.map do |result|
- size_measure = result.measure(filter.display.size_metric)
+ size_measure_values = filter.rows.map do |row|
+ size_measure = row.measure(filter.display.size_metric)
size_measure.value if size_measure
end.compact
min_size_value=(size_measure_values.empty? ? 0.0 : size_measure_values.min)
max_size_value=(size_measure_values.empty? ? 0.0 : size_measure_values.max)
- filter.results.each do |result|
- size_measure=result.measure(filter.display.size_metric)
+ filter.rows.each do |row|
+ size_measure=row.measure(filter.display.size_metric)
if size_measure && size_measure.value
- color_measure=result.measure(filter.display.color_metric)
+ color_measure=row.measure(filter.display.color_metric)
- title="#{result.snapshot.resource.long_name} | #{filter.display.size_metric.short_name}: #{size_measure.formatted_value}"
+ title="#{row.snapshot.resource.long_name} | #{filter.display.size_metric.short_name}: #{size_measure.formatted_value}"
if color_measure && color_measure.value
title += " | #{filter.display.color_metric.short_name}: #{color_measure.formatted_value}"
end
%>
- <a href="<%= ApplicationController.root_context -%>/dashboard/index/<%= result.snapshot.resource_id -%>" title="<%= title -%>"><span style="font-size: <%= cloud_font_size(size_measure.value, min_size_value, max_size_value) -%>%;color: <%= MeasureColor.color(color_measure, color_options).html -%>"><%= result.snapshot.resource.name %></span></a>
+ <a href="<%= ApplicationController.root_context -%>/dashboard/index/<%= row.snapshot.resource_id -%>" title="<%= title -%>"><span style="font-size: <%= cloud_font_size(size_measure.value, min_size_value, max_size_value) -%>%;color: <%= MeasureColor.color(color_measure, color_options).html -%>"><%= row.snapshot.resource.name %></span></a>
<% end
end %>
</div>
\ No newline at end of file
<% end %>
<% end %>
- <% if filter.base_result %>
+ <% if filter.base_row %>
<tr class="highlight">
<% if display_favourites %>
- <td class="thin"><%= link_to_favourite(filter.base_result.snapshot.resource) -%></td>
+ <td class="thin"><%= link_to_favourite(filter.base_row.snapshot.resource) -%></td>
<% end %>
<% filter.display.columns.each do |column| %>
<td class="<%= column.align -%> <%= column.row_css -%>">
- <%= list_cell_html(column, filter.base_result) -%>
+ <%= list_cell_html(column, filter.base_row) -%>
</td>
<% end %>
</tr>
<% end %>
- <% filter.results.each do |result| %>
+ <% filter.rows.each do |row| %>
<tr class="<%= cycle 'even', 'odd' -%>">
<% if display_favourites %>
- <td class="thin"><%= link_to_favourite(result.snapshot.resource) -%></td>
+ <td class="thin"><%= link_to_favourite(row.snapshot.resource) -%></td>
<% end %>
<% filter.display.columns.each do |column| %>
<td class="<%= column.align -%> <%= column.row_css -%>">
- <%= list_cell_html(column, result) -%>
+ <%= list_cell_html(column, row) -%>
</td>
<% end %>
</tr>
<% end %>
- <% if filter.results.empty? %>
+ <% if filter.rows.empty? %>
<tr class="even">
<td colspan="<%= colspan -%>"><%= message 'no_data' -%></td>
</tr>
<% end
end %>
-<% if filter.results.empty? %>
+<% if filter.rows.empty? %>
<p><%= message('no_data') -%></p>
<% elsif filter.pagination.pages>1 %>
- <p><%= message('measure_filter.too_many_results') -%></p>
+ <p><%= message('measure_filter.errors.TOO_MANY_RESULTS') -%></p>
<% else %>
<div id="tm-<%= treemap_id -%>" class="treemap width100">
<%= filter.display.html -%>
</li>
<li>
<input type="submit" name="search" value="<%= message('search_verb') -%>" id="search-button">
- <% if @filter.results %>
+ <% if @filter.rows %>
<a href="<%= ApplicationController.root_context -%>/measures" class="link-action"><%= message 'measure_filter.new_search' -%></a>
<% end %>
</li>
<%= render :partial => 'measures/sidebar' -%>
</div>
- <% if @filter.results && @filter.display %>
+ <% if @filter %>
<div class="page-split-right">
<div id="content">
<div class="line-block marginbottom10">
<ul class="operations">
+
<%
- edit_mode = (params[:edit]=='true')
- unless edit_mode
+ if @filter.display
+ edit_mode = (params[:edit]=='true')
+ unless edit_mode
%>
<li>
<a id="change-display" href="<%= url_for params.merge({:edit => true, :id => @filter.id}) -%>"><%= message("measure_filter.#{@filter.display.key}.change") -%></a>
<%= link_to_if display_key!=@filter.display.key, message("measure_filter.display.#{display_key}"), params.merge(:action => 'search', :display => display_key, :id => @filter.id), :id => "display_as_#{display_key}" -%>
<% end %>
</li>
+ <% end %>
+
<% if logged_in? %>
<% if @filter.id %>
<li><a id="copy" href="<%= url_for params.merge({:action => 'copy_form', :id => @filter.id}) -%>" class="link-action open-modal"><%= message('copy') -%></a></li>
<p class="notes"><%= message('results_not_display_due_to_security') -%></p>
<% end %>
- <%= render :partial => "measures/display_#{@filter.display.class::KEY}", :locals => {:filter => @filter, :edit_mode => edit_mode} -%>
+ <% if !@filter.errors.empty? %>
+ <% @filter.errors.full_messages.each do |message| %>
+ <div class="warning"><%= h message %></div>
+ <% end %>
+ <% elsif @filter.rows && @filter.display %>
+ <%= render :partial => "measures/display_#{@filter.display.class::KEY}", :locals => {:filter => @filter, :edit_mode => edit_mode} -%>
+ <% end %>
</div>
</div>
<% end %>