diff options
13 files changed, 123 insertions, 53 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java index e2b9328d31f..bc3125b2d07 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java @@ -38,15 +38,28 @@ public final class DefaultResourceTypes extends ExtensionProvider implements Bat .setProperty("modifiable_history", true) .setProperty("hasRolePolicy", true) .setProperty("updatable_key", true) + .setProperty("supports_measure_filters", true) .build()) .addType(ResourceType.builder(Qualifiers.MODULE) .setProperty("updatable_key", true) + .setProperty("supports_measure_filters", true) .build()) - .addType(ResourceType.builder(Qualifiers.DIRECTORY).build()) - .addType(ResourceType.builder(Qualifiers.PACKAGE).build()) - .addType(ResourceType.builder(Qualifiers.FILE).hasSourceCode().build()) - .addType(ResourceType.builder(Qualifiers.CLASS).hasSourceCode().build()) - .addType(ResourceType.builder(Qualifiers.UNIT_TEST_FILE).hasSourceCode().build()) + .addType(ResourceType.builder(Qualifiers.DIRECTORY) + .setProperty("supports_measure_filters", true) + .build()) + .addType(ResourceType.builder(Qualifiers.PACKAGE) + .build()) + .addType(ResourceType.builder(Qualifiers.FILE) + .hasSourceCode() + .setProperty("supports_measure_filters", true) + .build()) + .addType(ResourceType.builder(Qualifiers.CLASS) + .hasSourceCode() + .build()) + .addType(ResourceType.builder(Qualifiers.UNIT_TEST_FILE) + .hasSourceCode() + .setProperty("supports_measure_filters", true) + .build()) .addRelations(Qualifiers.PROJECT, Qualifiers.MODULE) .addRelations(Qualifiers.MODULE, Qualifiers.DIRECTORY, Qualifiers.PACKAGE) diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index 0a352ace85a..a0a87406463 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -381,6 +381,17 @@ session.flash_notice.logged_out=You have been logged out. # MEASURE FILTERS # #------------------------------------------------------------------------------ +measure_filter.col.date=Date +measure_filter.col.description=Description +measure_filter.col.key=Key +measure_filter.col.language=Language +measure_filter.col.links=Links +measure_filter.col.name=Name +measure_filter.col.short_name=Name +measure_filter.col.version=Version +measure_filter.missing_name=Name is missing +measure_filter.name_too_long=Name is too long + #------------------------------------------------------------------------------ # diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilter.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilter.java index 5c4d247a6d6..41f987dd579 100644 --- a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilter.java +++ b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilter.java @@ -23,8 +23,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.common.collect.Lists; import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; import org.sonar.api.measures.Metric; +import org.sonar.api.resources.Qualifiers; import javax.annotation.Nullable; @@ -76,6 +76,12 @@ public class MeasureFilter { public MeasureFilter setResourceQualifiers(@Nullable List<String> list) { this.resourceQualifiers = sanitize(list); + if (resourceQualifiers.contains(Qualifiers.FILE)) { + resourceQualifiers.add(Qualifiers.CLASS); + } + if (resourceQualifiers.contains(Qualifiers.DIRECTORY)) { + resourceQualifiers.add(Qualifiers.PACKAGE); + } return this; } diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java index 6b1bf54b3b8..0de8fad5f27 100644 --- a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java +++ b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java @@ -19,6 +19,7 @@ */ package org.sonar.core.measure; +import com.google.common.base.Strings; import org.apache.ibatis.session.SqlSession; import org.sonar.api.ServerComponent; import org.sonar.core.persistence.Database; @@ -75,7 +76,8 @@ public class MeasureFilterExecutor implements ServerComponent { } static boolean isValid(MeasureFilter filter, MeasureFilterContext context) { - boolean valid = !(filter.isOnBaseResourceChildren() && context.getBaseSnapshot() == null); + boolean valid = (Strings.isNullOrEmpty(filter.getBaseResourceKey()) || context.getBaseSnapshot()!=null); + valid &= !(filter.isOnBaseResourceChildren() && context.getBaseSnapshot() == null); valid &= !(filter.isOnFavourites() && context.getUserId() == null); valid &= validateMeasureConditions(filter); valid &= validateSort(filter); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java index fc0d8b0041e..bab797e764b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java @@ -40,7 +40,7 @@ import java.util.Map; * </p> * <ul> * <li>"deletable": if set to "true", then this resource can be deleted/purged.</li> - * <li>"availableForFilters": if set to "true", then this resource can be displayed in the filters results</li> + * <li>"supports_measure_filters": if set to "true", then this resource can be displayed in measure filters</li> * <li>"modifiable_history": if set to "true", then the history of this resource may be modified (deletion of snapshots, modification of events, ...)</li> * <li>"updatable_key" (since 3.2): if set to "true", then it is possible to update the key of this resource</li> * <li>"supportsGlobalDashboards" (since 3.2): if true, this resource can be displayed in global dashboards</li> @@ -82,11 +82,11 @@ public final class ResourceType { } /** - * @deprecated since 3.0. Use {@link #setProperty(String, String)} with "availableForFilters" set to "true". + * @deprecated since 3.0. Use {@link #setProperty(String, String)} with "supports_measure_filters" set to "true". */ @Deprecated public Builder availableForFilters() { - setProperty("availableForFilters", "true"); + setProperty("supports_measure_filters", "true"); return this; } @@ -107,6 +107,11 @@ public final class ResourceType { Preconditions.checkNotNull(key); Preconditions.checkNotNull(value); properties.put(key, value); + + // for backward-compatibility since version 3.4 + if (key.equals("availableForFilters")) { + properties.put("supports_measure_filters", value); + } return this; } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java index 4821187385f..f3494e963c2 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java @@ -45,7 +45,7 @@ public final class ResourceTypes implements BatchComponent, ServerComponent { public static final Predicate<ResourceType> AVAILABLE_FOR_FILTERS = new Predicate<ResourceType>() { public boolean apply(@Nullable ResourceType input) { - return input != null && input.getBooleanProperty("availableForFilters"); + return input != null && input.getBooleanProperty("supports_measure_filters"); } }; diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTest.java index 5d3559e9100..98e11c609d3 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTest.java @@ -40,13 +40,13 @@ public class ResourceTypeTest { ResourceType def = ResourceType.builder("qualifier") .setIconPath("/custom-icon.png") .hasSourceCode() - .setProperty("availableForFilters", "true") + .setProperty("supports_measure_filters", "true") .setProperty("anotherProperty", "foo") .build(); assertThat(def.getQualifier()).isEqualTo("qualifier"); assertThat(def.getIconPath()).isEqualTo("/custom-icon.png"); assertThat(def.hasSourceCode()).isTrue(); - assertThat(def.getBooleanProperty("availableForFilters")).isTrue(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue(); assertThat(def.getStringProperty("anotherProperty")).isEqualTo("foo"); } @@ -71,32 +71,32 @@ public class ResourceTypeTest { @Test public void testDeprecatedIsAvailableForFiltesCompatibility() { ResourceType def = ResourceType.builder("qualifier").build(); - assertThat(def.getBooleanProperty("availableForFilters")).isFalse(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse(); def = ResourceType.builder("qualifier").availableForFilters().build(); - assertThat(def.getBooleanProperty("availableForFilters")).isTrue(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue(); } @Test public void getBooleanProperty_is_set() { // set with boolean parameter - ResourceType def = ResourceType.builder("qualifier").setProperty("availableForFilters", true).build(); - assertThat(def.getBooleanProperty("availableForFilters")).isTrue(); + ResourceType def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", true).build(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue(); - def = ResourceType.builder("qualifier").setProperty("availableForFilters", false).build(); - assertThat(def.getBooleanProperty("availableForFilters")).isFalse(); + def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", false).build(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse(); - def = ResourceType.builder("qualifier").setProperty("availableForFilters", "true").build(); - assertThat(def.getBooleanProperty("availableForFilters")).isTrue(); + def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", "true").build(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue(); - def = ResourceType.builder("qualifier").setProperty("availableForFilters", "false").build(); - assertThat(def.getBooleanProperty("availableForFilters")).isFalse(); + def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", "false").build(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse(); } @Test public void getBooleanProperty_is_not_set() { ResourceType def = ResourceType.builder("qualifier").build(); - assertThat(def.getBooleanProperty("availableForFilters")).isFalse(); + assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse(); } @Test diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java index eeb96d7402f..1d73ddcc550 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java @@ -30,14 +30,14 @@ import static org.fest.assertions.Assertions.assertThat; public class ResourceTypesTest { private ResourceTypeTree viewsTree = ResourceTypeTree.builder() - .addType(ResourceType.builder(Qualifiers.VIEW).setProperty("availableForFilters", "true").build()) + .addType(ResourceType.builder(Qualifiers.VIEW).setProperty("supports_measure_filters", "true").build()) .addType(ResourceType.builder(Qualifiers.SUBVIEW).build()) .addRelations(Qualifiers.VIEW, Qualifiers.SUBVIEW) .addRelations(Qualifiers.SUBVIEW, Qualifiers.PROJECT) .build(); private ResourceTypeTree defaultTree = ResourceTypeTree.builder() - .addType(ResourceType.builder(Qualifiers.PROJECT).setProperty("availableForFilters", "true").build()) + .addType(ResourceType.builder(Qualifiers.PROJECT).setProperty("supports_measure_filters", "true").build()) .addType(ResourceType.builder(Qualifiers.DIRECTORY).build()) .addType(ResourceType.builder(Qualifiers.FILE).build()) .addRelations(Qualifiers.PROJECT, Qualifiers.DIRECTORY) @@ -67,14 +67,14 @@ public class ResourceTypesTest { @Test public void getAllWithPropertyKey() { - assertThat(qualifiers(types.getAllWithPropertyKey("availableForFilters"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT); + assertThat(qualifiers(types.getAllWithPropertyKey("supports_measure_filters"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT); } @Test public void getAllWithPropertyValue() { - assertThat(qualifiers(types.getAllWithPropertyValue("availableForFilters", "true"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT); - assertThat(qualifiers(types.getAllWithPropertyValue("availableForFilters", true))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT); - assertThat(qualifiers(types.getAllWithPropertyValue("availableForFilters", false))).containsOnly(Qualifiers.SUBVIEW, Qualifiers.DIRECTORY, Qualifiers.FILE); + assertThat(qualifiers(types.getAllWithPropertyValue("supports_measure_filters", "true"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT); + assertThat(qualifiers(types.getAllWithPropertyValue("supports_measure_filters", true))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT); + assertThat(qualifiers(types.getAllWithPropertyValue("supports_measure_filters", false))).containsOnly(Qualifiers.SUBVIEW, Qualifiers.DIRECTORY, Qualifiers.FILE); } @Test 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 27dfc7c129b..e123375ea17 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 @@ -58,7 +58,7 @@ class MeasureFilter < ActiveRecord::Base if @metric Api::Utils.message("metric.#{@metric.key}.name", :default => @metric.short_name) else - Api::Utils.message("filters.col.#{@key}", :default => @key) + Api::Utils.message("measure_filter.col.#{@key}", :default => @key) end end @@ -96,7 +96,7 @@ class MeasureFilter < ActiveRecord::Base 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('columns', ['metric:alert_status', 'name', 'date', 'metric:ncloc', 'metric:violations', 'links']) filter.set_criteria_default_value('sort', 'name') filter.set_criteria_default_value('asc', 'true') filter.set_criteria_default_value('pageSize', '30') @@ -117,6 +117,7 @@ class MeasureFilter < ActiveRecord::Base def initialize(filter) filter.set_criteria_default_value('columns', ['metric:ncloc', 'metric:violations']) + @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 end @@ -129,11 +130,11 @@ class MeasureFilter < ActiveRecord::Base CRITERIA_SEPARATOR = '|' CRITERIA_KEY_VALUE_SEPARATOR = ',' -# Configuration available after call to execute() + # Configuration available after call to execute() attr_reader :pagination, :security_exclusions, :columns -# Results : sorted array of Result - attr_reader :results + # Results : sorted array of Result + attr_reader :base_result, :results belongs_to :user validates_presence_of :name, :message => Api::Utils.message('measure_filter.missing_name') @@ -223,7 +224,7 @@ class MeasureFilter < ActiveRecord::Base self end -# API used by Displays + # API used by Displays def set_criteria_value(key, value) if value @criteria[key.to_s]=value @@ -232,7 +233,7 @@ class MeasureFilter < ActiveRecord::Base end end -# API used by Displays + # API used by Displays def set_criteria_default_value(key, value) set_criteria_value(key, value) unless criteria.has_key?(key) end @@ -297,6 +298,20 @@ class MeasureFilter < ActiveRecord::Base end end end + if criteria['base'].present? + base_snapshot = Snapshot.find(:first, :include => 'project', :conditions => ['projects.kee=? and islast=?', criteria['base'], true]) + if base_snapshot + @base_result = Result.new(base_snapshot) + if display.metric_ids && !display.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, display.metric_ids] + ) + base_measures.each do |base_measure| + @base_result.add_measure(base_measure) + end + end + end + end end def validate diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb index 4f6cd387760..63c220d9ad5 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb @@ -52,10 +52,6 @@ </li> <% end %> - <li class="<%= 'selected' if controller.controller_path=='reviews' -%>"> - <a href="<%= ApplicationController.root_context -%>/reviews/index"><%= message('reviews.page') -%></a> - </li> - <% controller.java_facade.getPages(Navigation::SECTION_HOME, nil, nil, nil, nil).each do |page| page_url = (page.isController() ? page.getId() : "/plugins/home/#{page.getId()}") selected=request.request_uri.include?("/plugins/home/#{page_url}") diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_tools.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_tools.html.erb index 83fe4265a22..b1bca085e65 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_tools.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_tools.html.erb @@ -4,6 +4,7 @@ <div id="tools-menu" class="dropdown-menu" style="display: none"> <ul> <li><a href="<%= ApplicationController.root_context -%>/dependencies/index"><%= message('dependencies.page') -%></a></li> + <li><a href="<%= ApplicationController.root_context -%>/reviews/index"><%= message('reviews.page') -%></a></li> </ul> </div> </li>
\ No newline at end of file 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 ee642f3c0c9..900431e003b 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 @@ -15,23 +15,39 @@ </tr> </thead> <tbody> + + <% if @filter.base_result %> + <tr class="highlight"> + <% if display_favourites %> + <td class="thin"><%= link_to_favourite(@filter.base_result.snapshot.resource) -%></td> + <% end %> + <% @filter.display.columns.each do |column| %> + <td class="<%= column.align -%>"> + <%= list_cell_html(column, @filter.base_result) -%> + </td> + <% end %> + </tr> + <% end %> + <% @filter.results.each do |result| %> <tr class="<%= cycle 'even', 'odd' -%>"> <% if display_favourites %> <td class="thin"><%= link_to_favourite(result.snapshot.resource) -%></td> <% end %> <% @filter.display.columns.each do |column| %> - <td class="<%= column.align -%>" > + <td class="<%= column.align -%>"> <%= list_cell_html(column, result) -%> </td> <% end %> </tr> <% end %> + <% if @filter.results.empty? %> <tr class="even"> <td colspan="<%= colspan -%>"><%= message 'no_data' -%></td> </tr> <% end %> + </tbody> <%= render :partial => 'utils/tfoot_pagination', :locals => {:pagination => @filter.pagination, :colspan => colspan} %> </table>
\ No newline at end of file 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 4905680ff25..90fc6f7d804 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 @@ -43,53 +43,58 @@ <tr> <td> Qualifiers:<br> - <%= select_tag 'qualifiers[]', options_for_select([['Any', ''], ['Project', 'TRK'], ['Sub-project', 'BRC'], ['Directory/Package', 'PAC'], ['File', 'CLA']], @filter.criteria['qualifiers']||''), :size => 5, :multiple => true -%> + <% + qualifiers = Api::Utils.java_facade.getResourceTypesForFilter().map do |resource_type| + [message("qualifiers.#{resource_type.getQualifier()}"), resource_type.getQualifier()] + end + %> + <%= select_tag 'qualifiers[]', options_for_select([[message('any'), '']].concat(qualifiers), @filter.criteria['qualifiers']||''), :size => 5, :multiple => true -%> </td> </tr> <tr> <td> Language:<br> - <% languages = [['Any', '']].concat(Api::Utils.languages.map { |lang| [lang.name, lang.key] }) %> + <% languages = [[message('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> <td> Name:<br> - <input type="text" name="nameRegexp"></td> + <input type="text" name="nameRegexp" value="<%= h @filter.criteria['nameRegexp'] -%>"></td> </tr> <tr> <td> Key:<br> - <input type="text" name="keyRegexp"></td> + <input type="text" name="keyRegexp" value="<%= h @filter.criteria['keyRegexp'] -%>"></td> </tr> <tr> <td> Favourites only:<br> - <%= check_box_tag 'onFavourites', 'true', params['onFavourites']=='true' %> + <%= check_box_tag 'onFavourites', 'true', @filter.criteria['onFavourites']=='true' %> </td> </tr> <tr> <td> From date:<br> - <input type="text" name="fromDate" value="<%= params['fromDate'] -%>"> + <input type="text" name="fromDate" value="<%= @filter.criteria['fromDate'] -%>"> </td> </tr> <tr> <td> To date:<br> - <input type="text" name="toDate" value="<%= params['toDate'] -%>"> + <input type="text" name="toDate" value="<%= @filter.criteria['toDate'] -%>"> </td> </tr> <tr> <td> - Before:<br> - <input type="text" name="beforeDays" value="<%= params['beforeDays'] -%>" size="4"> days + More than:<br> + <input type="text" name="beforeDays" value="<%= @filter.criteria['beforeDays'] -%>" size="4"> days ago </td> </tr> <tr> - <td>After:<br> - <input type="text" name="afterDays" value="<%= params['afterDays'] -%>" size="4"> days + <td>Within the last:<br> + <input type="text" name="afterDays" value="<%= @filter.criteria['afterDays'] -%>" size="4"> days </td> </tr> <tr> |