aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@gmail.com>2013-06-13 16:19:11 +0200
committerJulien Lancelot <julien.lancelot@gmail.com>2013-06-13 16:19:11 +0200
commita06137eb1111b48e20ccc2f0ac5989e35bd83c55 (patch)
treee676920c3b554508a58ca8558d9941a561cb0515 /sonar-server
parent9678ebc554ee2c2581268c956040e3ebc7adcb12 (diff)
downloadsonarqube-a06137eb1111b48e20ccc2f0ac5989e35bd83c55.tar.gz
sonarqube-a06137eb1111b48e20ccc2f0ac5989e35bd83c55.zip
SONAR-4383 Save issue filter
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java122
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java99
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb114
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb79
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb18
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb10
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb40
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb9
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb12
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java33
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java35
11 files changed, 323 insertions, 248 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
index e944d5a325b..c8c2967d2f5 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
@@ -280,41 +280,14 @@ public class InternalRubyIssueService implements ServerComponent {
String projectParam = parameters.get("project");
Date deadLine = null;
- if (Strings.isNullOrEmpty(name)) {
- result.addError(Result.Message.ofL10n("errors.cant_be_empty", "name"));
- } else {
- if (name.length() > 200) {
- result.addError(Result.Message.ofL10n("errors.is_too_long", "name", 200));
- }
- }
-
- if (!Strings.isNullOrEmpty(description) && description.length() > 1000) {
- result.addError(Result.Message.ofL10n("errors.is_too_long", "description", 1000));
- }
+ checkMandatorySizeParameter(name, "name", 200, result);
+ checkOptionnalSizeParameter(description, "description", 1000, result);
// Can only set project on creation
if (existingActionPlan == null) {
- if (Strings.isNullOrEmpty(projectParam)) {
- result.addError(Result.Message.ofL10n("errors.cant_be_empty", "project"));
- } else {
- ResourceDto project = resourceDao.getResource(ResourceQuery.create().setKey(projectParam));
- if (project == null) {
- result.addError(Result.Message.ofL10n("action_plans.errors.project_does_not_exist", projectParam));
- }
- }
- }
-
- if (!Strings.isNullOrEmpty(deadLineParam)) {
- try {
- deadLine = RubyUtils.toDate(deadLineParam);
- Date today = new Date();
- if (deadLine != null && deadLine.before(today) && !org.apache.commons.lang.time.DateUtils.isSameDay(deadLine, today)) {
- result.addError(Result.Message.ofL10n("action_plans.date_cant_be_in_past"));
- }
- } catch (SonarException e) {
- result.addError(Result.Message.ofL10n("errors.is_not_valid", "date"));
- }
+ checkProject(projectParam, result);
}
+ deadLine = checkAndReturnDeadline(deadLineParam, result);
if (!Strings.isNullOrEmpty(projectParam) && !Strings.isNullOrEmpty(name) && (existingActionPlan == null || !name.equals(existingActionPlan.name()))
&& actionPlanService.isNameAlreadyUsedForProject(name, projectParam)) {
@@ -339,6 +312,33 @@ public class InternalRubyIssueService implements ServerComponent {
return result;
}
+ private void checkProject(String projectParam, Result<ActionPlan> result){
+ if (Strings.isNullOrEmpty(projectParam)) {
+ result.addError(Result.Message.ofL10n("errors.cant_be_empty", "project"));
+ } else {
+ ResourceDto project = resourceDao.getResource(ResourceQuery.create().setKey(projectParam));
+ if (project == null) {
+ result.addError(Result.Message.ofL10n("action_plans.errors.project_does_not_exist", projectParam));
+ }
+ }
+ }
+
+ private Date checkAndReturnDeadline(String deadLineParam, Result<ActionPlan> result){
+ Date deadLine = null;
+ if (!Strings.isNullOrEmpty(deadLineParam)) {
+ try {
+ deadLine = RubyUtils.toDate(deadLineParam);
+ Date today = new Date();
+ if (deadLine != null && deadLine.before(today) && !org.apache.commons.lang.time.DateUtils.isSameDay(deadLine, today)) {
+ result.addError(Result.Message.ofL10n("action_plans.date_cant_be_in_past"));
+ }
+ } catch (SonarException e) {
+ result.addError(Result.Message.ofL10n("errors.is_not_valid", "date"));
+ }
+ }
+ return deadLine;
+ }
+
private Result<ActionPlan> createResultForExistingActionPlan(String actionPlanKey) {
Result<ActionPlan> result = Result.of();
if (findActionPlan(actionPlanKey) == null) {
@@ -369,6 +369,14 @@ public class InternalRubyIssueService implements ServerComponent {
return PublicRubyIssueService.toQuery(props);
}
+ public DefaultIssueFilter findIssueFilter(Long id) {
+ return issueFilterService.findById(id, UserSession.get());
+ }
+
+ public DefaultIssueFilter createFilterFromMap(Map<String, Object> mapData) {
+ return issueFilterService.createEmptyFilter(mapData);
+ }
+
/**
* Execute issue filter
*/
@@ -379,29 +387,69 @@ public class InternalRubyIssueService implements ServerComponent {
/**
* Create issue filter
*/
- public void createIssueFilter(Map<String, String> params) {
+ public Result<DefaultIssueFilter> createIssueFilter(Map<String, String> params) {
Result<DefaultIssueFilter> result = Result.of();
try {
// mandatory parameters
String name = params.get("name");
String description = params.get("description");
String data = params.get("data");
+ Boolean shared = RubyUtils.toBoolean(params.get("shared"));
if (result.ok()) {
- DefaultIssueFilter defaultIssueFilter = new DefaultIssueFilter()
- .setName(name)
+ DefaultIssueFilter defaultIssueFilter = DefaultIssueFilter.create(name)
.setDescription(description)
- .setData(data)
- ;
- defaultIssueFilter = issueFilterService.create(defaultIssueFilter, UserSession.get());
+ .setShared(shared)
+ .setData(data);
+ defaultIssueFilter = issueFilterService.save(defaultIssueFilter, UserSession.get());
result.set(defaultIssueFilter);
}
} catch (Exception e) {
result.addError(e.getMessage());
}
+ return result;
+ }
+ @VisibleForTesting
+ Result<DefaultIssueFilter> createIssueFilterResult(Map<String, String> params) {
+ Result<DefaultIssueFilter> result = Result.of();
+
+ // mandatory parameters
+ String name = params.get("name");
+ String description = params.get("description");
+ String data = params.get("data");
+ Boolean shared = RubyUtils.toBoolean(params.get("shared"));
+
+ checkMandatorySizeParameter(name, "name", 100, result);
+ checkOptionnalSizeParameter(description, "description", 4000, result);
+
+ // TODO check name uniquness
+
+ if (result.ok()) {
+ DefaultIssueFilter defaultIssueFilter = DefaultIssueFilter.create(name)
+ .setDescription(description)
+ .setShared(shared)
+ .setData(data);
+ result.set(defaultIssueFilter);
+ }
+ return result;
}
+ private void checkMandatorySizeParameter(String value, String paramName, Integer size, Result result){
+ if (Strings.isNullOrEmpty(value)) {
+ result.addError(Result.Message.ofL10n("errors.cant_be_empty", paramName));
+ } else {
+ if (value.length() > size) {
+ result.addError(Result.Message.ofL10n("errors.is_too_long", paramName, size));
+ }
+ }
+ }
+
+ private void checkOptionnalSizeParameter(String value, String paramName, Integer size, Result result){
+ if (!Strings.isNullOrEmpty(value) && value.length() > size) {
+ result.addError(Result.Message.ofL10n("errors.is_too_long", paramName, size));
+ }
+ }
} \ No newline at end of file
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java
index d57b32537eb..61dd367abc3 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java
@@ -20,10 +20,6 @@
package org.sonar.server.issue;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
import org.sonar.api.issue.IssueFinder;
import org.sonar.api.issue.IssueQuery;
@@ -33,12 +29,9 @@ import org.sonar.core.issue.db.IssueFilterDao;
import org.sonar.core.issue.db.IssueFilterDto;
import org.sonar.server.user.UserSession;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import javax.annotation.CheckForNull;
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
+import java.util.Map;
public class IssueFilterService implements ServerComponent {
@@ -50,11 +43,32 @@ public class IssueFilterService implements ServerComponent {
this.issueFinder = issueFinder;
}
- public DefaultIssueFilter create(DefaultIssueFilter issueFilter, UserSession userSession) {
+ @CheckForNull
+ public DefaultIssueFilter createEmptyFilter(Map<String, Object> mapData) {
+ return new DefaultIssueFilter(mapData);
+ }
+
+ @CheckForNull
+ public DefaultIssueFilter findById(Long id, UserSession userSession) {
// TODO
// checkAuthorization(userSession, project, UserRole.ADMIN);
- issueFilterDao.insert(IssueFilterDto.toIssueFilter(issueFilter));
- return issueFilter;
+ verifyLoggedIn(userSession);
+// access_denied unless filter.shared || filter.owner?(current_user)
+
+ IssueFilterDto issueFilterDto = issueFilterDao.selectById(id);
+ if (issueFilterDto == null) {
+ return null;
+ }
+ return issueFilterDto.toIssueFilter();
+ }
+
+ public DefaultIssueFilter save(DefaultIssueFilter issueFilter, UserSession userSession) {
+ issueFilter.setUser(userSession.login());
+ // TODO
+// checkAuthorization(userSession, project, UserRole.ADMIN);
+ IssueFilterDto issueFilterDto = IssueFilterDto.toIssueFilter(issueFilter);
+ issueFilterDao.insert(issueFilterDto);
+ return issueFilterDto.toIssueFilter();
}
public DefaultIssueFilter update(DefaultIssueFilter issueFilter, UserSession userSession) {
@@ -89,64 +103,11 @@ public class IssueFilterService implements ServerComponent {
return null;
}
- @VisibleForTesting
- Map<String, Object> dataAsMap(String data) {
- Map<String, Object> map = newHashMap();
-
- Iterable<String> keyValues = Splitter.on(DefaultIssueFilter.SEPARATOR).split(data);
- for (String keyValue : keyValues) {
- String[] keyValueSplit = StringUtils.split(keyValue, DefaultIssueFilter.KEY_VALUE_SEPARATOR);
- if (keyValueSplit.length != 2) {
- throw new IllegalArgumentException("Key value should be separate by a '"+ DefaultIssueFilter.KEY_VALUE_SEPARATOR + "'");
- }
- String key = keyValueSplit[0];
- String value = keyValueSplit[1];
- String[] listValues = StringUtils.split(value, DefaultIssueFilter.LIST_SEPARATOR);
- if (listValues.length > 1) {
- map.put(key, newArrayList(listValues));
- } else {
- map.put(key, value);
- }
+ private void verifyLoggedIn(UserSession userSession) {
+ if (!userSession.isLoggedIn()) {
+ // must be logged
+ throw new IllegalStateException("User is not logged in");
}
- return map;
- }
-
- @VisibleForTesting
- String mapAsdata(Map<String, Object> map) {
- StringBuilder stringBuilder = new StringBuilder();
-
- for (Map.Entry<String, Object> entries : map.entrySet()){
- String key = entries.getKey();
- Object value = entries.getValue();
-
- stringBuilder.append(key);
- stringBuilder.append(DefaultIssueFilter.KEY_VALUE_SEPARATOR);
-
- List valuesList = newArrayList();
- if (value instanceof List) {
- // assume that it contains only strings
- valuesList = (List) value;
- } else if (value instanceof CharSequence) {
- valuesList = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((CharSequence) value));
- } else {
- stringBuilder.append(value);
- }
- for (Iterator<Object> valueListIter = valuesList.iterator(); valueListIter.hasNext();) {
- Object valueList = valueListIter.next();
- stringBuilder.append(valueList);
- if (valueListIter.hasNext()) {
- stringBuilder.append(DefaultIssueFilter.LIST_SEPARATOR);
- }
- }
- stringBuilder.append(DefaultIssueFilter.SEPARATOR);
- }
-
- if (stringBuilder.length() > 0) {
- // Delete useless last separator character
- stringBuilder.deleteCharAt(stringBuilder.length() - 1);
- }
-
- return stringBuilder.toString();
}
}
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
index da523e067fa..cafdd7f75a7 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
@@ -20,36 +20,120 @@
class IssuesController < ApplicationController
- before_filter :init
+ before_filter :init_options
+ # GET /issues/index
def index
redirect_to :action => 'search'
end
+ # GET /issues/search
def search
- init_results
+ if params[:id]
+ @filter = find_filter(params[:id].to_i)
+ else
+ @filter = Internal.issues.createFilterFromMap(criteria_params)
+ end
- @criteria_params = params.merge({:controller => nil, :action => nil, :search => nil, :widget_id => nil, :edit => nil})
- @criteria_params['pageSize'] = 100
- @issue_query = Internal.issues.toQuery(@criteria_params)
+ @issue_query = Internal.issues.toQuery(@filter.dataAsMap)
@issues_result = Internal.issues.execute(@issue_query)
- @paging = @issues_result.paging
- @issues = @issues_result.issues
end
- private
+ # Load existing filter
+ # GET /issues/filter/<filter id>
+ def filter
+ require_parameters :id
+
+ @filter = find_filter(params[:id].to_i)
+ @issue_query = Internal.issues.toQuery(@filter.dataAsMap)
+
+ # criteria can be overridden
+ # TODO ?
+ #@filter.override_criteria(criteria_params)
+
+ @issues_result = Internal.issues.execute(@issue_query)
+ @unchanged = true
+ render :action => 'search'
+ end
- def init_results
- @issues_result = nil
- @paging = nil
- @issues = nil
- #criteria['pageSize'] = 100
- self
+ # GET /issues/save_as_form?[id=<id>][&criteria]
+ def save_as_form
+ if params[:id].present?
+ @filter = find_filter(params[:id])
+ else
+ @filter = Internal.issues.createFilterFromMap(criteria_params)
+ end
+ render :partial => 'issues/save_as_form'
end
- def init
+ # POST /issues/save_as?[id=<id>]&name=<name>[&parameters]
+ def save_as
+ verify_post_request
+ access_denied unless logged_in?
+
+ options = {'name' => params[:name], 'description' => params[:description], 'data' => URI.unescape(params[:data]), 'shared' => params[:shared]=='true' }
+ add_to_favourites=false
+ if params[:id].present?
+ # TODO
+ #@filter = Internal.issues.updateIssueFilter(params[:id], options)
+ else
+ filter_result = Internal.issues.createIssueFilter(options)
+ add_to_favourites=true
+ end
+
+ if filter_result.ok
+ @filter = filter_result.get()
+ puts "#### "+ @filter.id.to_s
+ #current_user.favourited_measure_filters<<@filter if add_to_favourites
+ render :text => @filter.id.to_s, :status => 200
+ else
+ @errors = filter_result.errors
+ render :partial => 'issues/save_as_form', :status => 400
+ end
+ end
+
+ # POST /issues/save?id=<id>&[criteria]
+ # TODO
+ def save
+ verify_post_request
+ require_parameters :id
+ access_denied unless logged_in?
+
+ @filter = find_filter(params[:id])
+
+ #@filter = Internal.issues.updateIssueFilter(params[:id], options)
+
+ #@filter.criteria=criteria_params_without_page_id
+ #@filter.convert_criteria_to_data
+ #unless @filter.save
+ # flash[:error]='Error'
+ #end
+ redirect_to :action => 'filter', :id => @filter.id
+ end
+
+ private
+
+ def init_options
@options_for_statuses = Internal.issues.listStatus().map {|s| [message('issue.status.' + s), s]}
@options_for_resolutions = Internal.issues.listResolutions().map {|s| [message('issue.resolution.' + s), s]}
end
+ # TODO
+ def find_filter(id)
+ filter = Internal.issues.findIssueFilter(id)
+ # TODO
+ #access_denied unless filter.shared || filter.owner?(current_user)
+ filter
+ end
+
+ def criteria_params
+ criteria = params
+ criteria.delete('controller')
+ criteria.delete('action')
+ criteria.delete('search')
+ criteria.delete('edit')
+ criteria.delete('pageSize')
+ criteria
+ end
+
end \ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb
deleted file mode 100644
index 09423ffc863..00000000000
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# Sonar, entreprise quality control tool.
-# Copyright (C) 2008-2013 SonarSource
-# mailto:contact AT sonarsource DOT com
-#
-# SonarQube 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.
-#
-# SonarQube 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 this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-require 'set'
-class IssueFilter
-
- attr_reader :paging, :issues, :issues_result
-
- def criteria(key=nil)
- @criteria ||= HashWithIndifferentAccess.new
- if key
- @criteria[key]
- else
- @criteria
- end
- end
-
- def criteria=(hash)
- @criteria = HashWithIndifferentAccess.new
- hash.each_pair do |k, v|
- set_criteria_value(k, v)
- end
- end
-
- def override_criteria(hash)
- @criteria ||= HashWithIndifferentAccess.new
- hash.each_pair do |k, v|
- set_criteria_value(k, v)
- end
- end
-
- # API used by Displays
- def set_criteria_value(key, value)
- @criteria ||= HashWithIndifferentAccess.new
- if key
- if value!=nil && value!='' && value!=['']
- value = (value.kind_of?(Array) ? value : value.to_s)
- @criteria[key]=value
- else
- @criteria.delete(key)
- end
- end
- end
-
- def execute
- init_results
- @issues_result = Api.issues.find(criteria)
- @paging = @issues_result.paging
- @issues = @issues_result.issues
- self
- end
-
- private
-
- def init_results
- @issues_result = nil
- @paging = nil
- @issues = nil
- criteria['pageSize'] = 100
- self
- end
-
-end \ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb
new file mode 100644
index 00000000000..32cfd27c28b
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb
@@ -0,0 +1,18 @@
+<ul class="operations">
+ <% if logged_in? %>
+ <% if @filter.id %>
+ <!--TODO-->
+ <li class="hidden"><a id="copy" href="<%= url_for :action => 'copy_form', :id => @filter.id -%>" class="link-action open-modal"><%= message('copy') -%></a></li>
+ <% end %>
+ <% if !defined?(@unchanged) && @filter.id && @filter.user == current_user.login %>
+ <li>
+ <%= link_to message('save'), params.merge({:action => 'save', :id => @filter.id}), :class => 'link-action', :id => 'save', :method => :post -%>
+ </li>
+ <% end %>
+ <% unless @filter.id %>
+ <li>
+ <a id="save-as" href="<%= url_for params.merge({:action => 'save_as_form', :id => @filter.id}) -%>" class="link-action open-modal"><%= message('save_as') -%></a>
+ </li>
+ <% end %>
+<% end %>
+</ul> \ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb
index 9b93373ad25..6f1e0ba429e 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb
@@ -18,10 +18,10 @@
<% end %>
<%
- if @issues && !@issues.empty?
+ if @issues_result.issues && !@issues_result.issues.empty?
colspan = 9
%>
- <div>
+ <div id="issues-list">
<table class="data width100">
<thead>
<tr>
@@ -59,7 +59,7 @@
</thead>
<tbody>
<%
- @issues.each do |issue|
+ @issues_result.issues.each do |issue|
%>
<tr class="<%= cycle('even', 'odd') -%>">
<td width="1%" nowrap>
@@ -102,14 +102,14 @@
<%
end
%>
- <% if @issues.empty? %>
+ <% if @issues_result.issues.empty? %>
<tr class="even">
<td colspan="<%= colspan -%>"><%= message 'no_data' -%></td>
</tr>
<% end %>
</tbody>
- <%= paginate_java(@paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id|
+ <%= paginate_java(@issues_result.paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id|
link_to(label, params.merge({:pageIndex => page_id}))
} -%>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb
new file mode 100644
index 00000000000..10dcaf7a402
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb
@@ -0,0 +1,40 @@
+<form id="save-as-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/save_as">
+ <input type="hidden" name="id" value="<%= @filter.id -%>">
+ <input type="hidden" name="data" value="<%= u(@filter.data) -%>">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_filter.save_filter') -%></h2>
+ </div>
+
+ <div class="modal-body">
+ <%
+ if @errors
+ @errors.each do |msg| %>
+ <div class="error"><%= h (msg.text ? msg.text : Api::Utils.message(msg.l10nKey, :params => msg.l10nParams)) -%></div>
+ <% end
+ end
+ %>
+ <div class="modal-field">
+ <label for="name"><%= message('issue_filter.form.name') -%> <em class="mandatory">*</em></label>
+ <input id="name" name="name" type="text" size="50" maxlength="100" value="<%= h @filter.name -%>" autofocus="autofocus"/>
+ </div>
+ <div class="modal-field">
+ <label for="description"><%= message('issue_filter.form.description') -%></label>
+ <input id="description" name="description" type="text" size="50" maxlength="4000" value="<%= h @filter.description -%>"/>
+ </div>
+ <div class="modal-field">
+ <label for="shared"><%= message('issue_filter.form.share') -%></label>
+ <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if @filter.shared -%>/>
+ </div>
+ </div>
+ <div class="modal-foot">
+ <input type="submit" value="<%= h message('save') -%>" id="save-as-submit"/>
+ <a href="#" onclick="return closeModalWindow()" id="save-as-cancel"><%= h message('cancel') -%></a>
+ </div>
+ </fieldset>
+</form>
+<script>
+ $j("#save-as-filter-form").modalForm({success:function (data) {
+ window.location = baseUrl + '/issues/filter/' + data;
+ }});
+</script> \ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb
index dc762c5b1f5..01e6a783115 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb
@@ -1,6 +1,9 @@
<ul class="sidebar gray-sidebar">
<form method="GET" action="<%= ApplicationController.root_context -%>/issues/search" >
+ <% if @filter.id %>
+ <input type="hidden" name="id" value="<%= @filter.id.to_s -%>">
+ <% end %>
<input type="hidden" name="sort" value="<%= @issue_query.sort -%>"/>
<input type="hidden" name="asc" value="<%= @issue_query.asc -%>"/>
@@ -9,7 +12,7 @@
</li>
<li id="criteria-project" class="marginbottom5">
<%= message 'issue_filter.criteria.project' -%>:
- <% selected_componentRoot = Internal.component_api.findByKey(@issue_query.componentRoots.get(0)) if @issue_query.componentRoots and @issue_query.componentRoots.size == 1 %>
+ <% selected_componentRoot = Internal.component_api.findByKey(@issue_query.componentRoots.to_a.first) if @issue_query.componentRoots and @issue_query.componentRoots.size == 1 %>
<%= component_select_tag 'componentRoots', :resource_type_property => 'supportsGlobalDashboards', :width => '100%',
:selected_resource => selected_componentRoot,
:display_key => true,
@@ -38,13 +41,13 @@
</li>
<li id="criteria-assignee" class="marginbottom5">
<%= message 'issue_filter.criteria.assignee' -%>:
- <% selected_assignee = Api.users.findByLogin(@issue_query.assignees.get(0)) if @issue_query.assignees && @issue_query.assignees.size == 1 %>
+ <% selected_assignee = Api.users.findByLogin(@issue_query.assignees.to_a.first) if @issue_query.assignees && @issue_query.assignees.size == 1 %>
<%= user_select_tag('assignees', {:selected_user => selected_assignee, :width => '100%', :placeholder => message('issue_filter.criteria.assignee'),
:html_id => 'select-assignee', :open => false, :allow_clear => true}) -%>
</li>
<li id="criteria-reporter" class="marginbottom5">
<%= message 'issue_filter.criteria.reporter' -%>:
- <% selected_reporter = Api.users.findByLogin(@issue_query.reporters.get(0)) if @issue_query.reporters && @issue_query.reporters.size == 1 %>
+ <% selected_reporter = Api.users.findByLogin(@issue_query.reporters.to_a.first) if @issue_query.reporters && @issue_query.reporters.size == 1 %>
<%= user_select_tag('reporters', {:selected_user => selected_reporter, :width => '100%', :placeholder => message('issue_filter.criteria.reporter'),
:html_id => 'select-reporter', :open => false, :allow_clear => true}) -%>
</li>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb
index 1671e29b5da..7ffbc9df5d3 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb
@@ -5,12 +5,14 @@
<div class="page-split-right">
<div id="content">
- <div class="marginbottom10">
- <% if @issues_result && @issues_result.maxResultsReached() %>
- <p class="notes"><%= message('issue_filter.max_results_reached', :params => @paging.total()) -%></p>
- <% end %>
- <%= render :partial => 'list' -%>
+ <div class="line-block marginbottom10">
+ <%= render :partial => 'action_links' -%>
</div>
+
+ <% if @issues_result && @issues_result.maxResultsReached() %>
+ <p class="notes"><%= message('issue_filter.max_results_reached', :params => @issues_result.paging.total()) -%></p>
+ <% end %>
+ <%= render :partial => 'list' -%>
</div>
</div>
</div> \ No newline at end of file
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
index 915b82d82af..eac0c788819 100644
--- a/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
@@ -293,4 +293,37 @@ public class InternalRubyIssueServiceTest {
assertThat(result).isSameAs(changelog);
}
+
+ @Test
+ public void should_get_error_on_issue_filter_result_when_no_name() {
+ Map<String, String> parameters = newHashMap();
+ parameters.put("name", null);
+ parameters.put("description", "Long term issues");
+
+ Result result = service.createIssueFilterResult(parameters);
+ assertThat(result.ok()).isFalse();
+ assertThat(result.errors()).contains(Result.Message.ofL10n("errors.cant_be_empty", "name"));
+ }
+
+ @Test
+ public void should_get_error_on_issue_filter_result_when_name_is_too_long() {
+ Map<String, String> parameters = newHashMap();
+ parameters.put("name", createLongString(101));
+ parameters.put("description", "Long term issues");
+
+ Result result = service.createIssueFilterResult(parameters);
+ assertThat(result.ok()).isFalse();
+ assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "name", 100));
+ }
+
+ @Test
+ public void should_get_error_on_issue_filter_result_when_description_is_too_long() {
+ Map<String, String> parameters = newHashMap();
+ parameters.put("name", "Long term");
+ parameters.put("description", createLongString(4001));
+
+ Result result = service.createIssueFilterResult(parameters);
+ assertThat(result.ok()).isFalse();
+ assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "description", 4000));
+ }
}
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java
index 8e00284b13f..6a608f25a47 100644
--- a/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java
@@ -21,16 +21,9 @@
package org.sonar.server.issue;
import org.junit.Before;
-import org.junit.Test;
import org.sonar.api.issue.IssueFinder;
import org.sonar.core.issue.db.IssueFilterDao;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newLinkedHashMap;
-import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
public class IssueFilterServiceTest {
@@ -47,32 +40,4 @@ public class IssueFilterServiceTest {
service = new IssueFilterService(issueFilterDao, issueFinder);
}
- @Test
- public void should_convert_data_to_map() {
- String data = "issues=ABCDE1234|severities=MAJOR,MINOR|resolved=true|pageSize=10|pageIndex=50";
-
- Map<String, Object> map = service.dataAsMap(data);
-
- assertThat(map).hasSize(5);
- assertThat(map.get("issues")).isEqualTo("ABCDE1234");
- assertThat(map.get("severities")).isInstanceOf(List.class);
- assertThat((List<String>) map.get("severities")).contains("MAJOR", "MINOR");
- assertThat(map.get("resolved")).isEqualTo("true");
- assertThat(map.get("pageSize")).isEqualTo("10");
- assertThat(map.get("pageIndex")).isEqualTo("50");
- }
-
- @Test
- public void should_convert_map_to_data() {
- Map<String, Object> map = newLinkedHashMap();
- map.put("issues", newArrayList("ABCDE1234"));
- map.put("severities", newArrayList("MAJOR", "MINOR"));
- map.put("resolved", true);
- map.put("pageSize", 10l);
- map.put("pageIndex", 50);
-
- String result = service.mapAsdata(map);
-
- assertThat(result).isEqualTo("issues=ABCDE1234|severities=MAJOR,MINOR|resolved=true|pageSize=10|pageIndex=50");
- }
}