issue_filter.shared_with_all_users=Shared with all users
issue_filter.sharing=Sharing
issue_filter.manage.shared_filters=Shared Filters
-issue_filter.bulk_change=Bulk change
+issue_filter.bulk_change.form.title=Change {0} issues
#------------------------------------------------------------------------------
#
public class CommentAction extends Action implements ServerComponent {
public static final String COMMENT_ACTION_KEY = "comment";
+ public static final String COMMENT_PROPERTY = "comment";
public CommentAction() {
super(COMMENT_ACTION_KEY);
}
private String comment(Map<String, Object> properties) {
- return (String) properties.get("comment");
+ return (String) properties.get(COMMENT_PROPERTY);
}
}
\ No newline at end of file
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.sonar.server.util.RubyUtils;
import java.util.HashMap;
private List<String> issues;
private List<String> actions;
- private String comment;
Map<String, Map<String, Object>> propertiesByActions = new HashMap<String, Map<String, Object>>();
}
private void parse(Map<String, Object> props, String comment) {
- this.comment = comment;
this.issues = RubyUtils.toStrings(props.get("issues"));
if (issues == null || issues.isEmpty()) {
throw new IllegalArgumentException("Issues must not be empty");
}
for (String action : actions) {
Map<String, Object> actionProperties = getActionProps(action, props);
- if (actionProperties.isEmpty()) {
- throw new IllegalArgumentException("Missing properties for action: "+ action);
- }
propertiesByActions.put(action, actionProperties);
}
if (!Strings.isNullOrEmpty(comment)) {
actions.add(CommentAction.COMMENT_ACTION_KEY);
Map<String, Object> commentMap = newHashMap();
- commentMap.put(CommentAction.COMMENT_ACTION_KEY, comment);
+ commentMap.put(CommentAction.COMMENT_PROPERTY, comment);
propertiesByActions.put(CommentAction.COMMENT_ACTION_KEY, commentMap);
}
}
return actionProps;
}
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this);
+ }
+
}
}
public IssueBulkChangeResult execute(IssueBulkChangeQuery issueBulkChangeQuery, UserSession userSession) {
+ LOG.debug("BulkChangeQuery : {}", issueBulkChangeQuery);
verifyLoggedIn(userSession);
IssueBulkChangeResult result = new IssueBulkChangeResult();
# GET /issues/save_as_form?[&criteria]
def save_as_form
@filter_query_serialized = Internal.issues.serializeFilterQuery(criteria_params_to_save)
- render :partial => 'issues/save_as_form'
+ render :partial => 'issues/filter_save_as_form'
end
# POST /issues/save_as?name=<name>[¶meters]
render :text => @filter.id.to_s, :status => 200
else
@errors = filter_result.errors
- render :partial => 'issues/save_as_form', :status => 400
+ render :partial => 'issues/filter_save_as_form', :status => 400
end
end
def edit_form
require_parameters :id
@filter = find_filter(params[:id].to_i)
- render :partial => 'issues/edit_form'
+ render :partial => 'issues/filter_edit_form'
end
# POST /issues/edit/<filter id>?name=<name>&description=<description>&shared=<true|false>
render :text => @filter.id.to_s, :status => 200
else
@errors = filter_result.errors
- render :partial => 'issues/edit_form', :status => 400
+ render :partial => 'issues/filter_edit_form', :status => 400
end
end
def copy_form
require_parameters :id
@filter = find_filter(params[:id].to_i)
- render :partial => 'issues/copy_form'
+ render :partial => 'issues/filter_copy_form'
end
# POST /issues/copy/<filter id>?name=<copy name>&description=<copy description>
render :text => @filter.id.to_s, :status => 200
else
@errors = filter_result.errors
- render :partial => 'issues/copy_form', :status => 400
+ render :partial => 'issues/filter_copy_form', :status => 400
end
end
# GET /issues/bulk_change_form?[&criteria]
def bulk_change_form
+ # Load maximum number of issues
+ @criteria_params = criteria_params
+ @criteria_params['pageSize'] = -1
+ issue_filter_result = Internal.issues.execute(@criteria_params)
+ @issue_query = issue_filter_result.query
+ @issues_result = issue_filter_result.result
+
+ @issue_keys = @issues_result.issues.map {|issue| issue.key()}.join(',') if !@issues_result.issues.empty?
+
render :partial => 'issues/bulk_change_form'
end
+ # POST /issues/bulk_change
+ def bulk_change
+ verify_post_request
+
+ render :text => '', :status => 200
+ end
+
private
<%
plans_select_box_id = "plans-#{params[:issue]}"
plans = Internal.issues.findOpenActionPlans(@issue_result.project(@issue).key())
-
-
if plans.empty?
%>
<% if is_admin? %>
<form id="bulk-change-form" method="post" action="<%= ApplicationController.root_context -%>/issues/bulk_change">
- <input type="hidden" name="data" value="<%= params[:data] || u(@filter_query_serialized) -%>">
+ <input type="hidden" name="issues" value="<%= @issue_keys -%>">
<fieldset>
<div class="modal-head">
- <h2><%= message('issue_filter.bulk_change') -%></h2>
+ <h2><%= message('issue_filter.bulk_change.form.title', {:params => @issues_result.issues.size.to_s}) -%></h2>
+ </div>
+ <div class="modal-body">
+ <%= render :partial => 'display_errors' %>
+ <div class="modal-field">
+ <label for="assignee">
+ <input id="assign-action" name="actions[]" type="checkbox" value="assign"/>
+ <%= message('issue.assign.formlink') -%>
+ </label>
+ <%= user_select_tag('assign.assignee', :html_id => 'assignee', :open => false) -%>
+ </div>
+ <% if @issue_query.componentRoots and @issue_query.componentRoots.size == 1 %>
+ <%
+ componentRoot = @issue_query.componentRoots.to_a.first
+ plans = Internal.issues.findOpenActionPlans(componentRoot)
+ first_plan = plans[0]
+ plan_options = ""
+ unless plans.empty?
+ plan_options = options_for_select(plans.map { |plan|
+ if plan.deadLine
+ label = "#{h plan.name} (#{format_date(plan.deadLine)})"
+ else
+ label = h plan.name
+ end
+ [label, plan.key]
+ }, first_plan.key)
+ end
+ %>
+ <div class="modal-field">
+ <label for="plan">
+ <input id="plan-action" name="actions[]" type="checkbox" value="plan"/>
+ <%= message('issue.do_plan') -%>
+ </label>
+ <%= dropdown_tag('plan.plan', plan_options, {:show_search_box => false}, {:id => 'plan'}) -%>
+ </div>
+ <% end %>
+ <div class="modal-field">
+ <label for="severity">
+ <input id="set-severity-action" name="actions[]" type="checkbox" value="set_severity"/>
+ <%= message('issue.set_severity') -%>
+ </label>
+ <select name="set_severity.severity" class="withIcons" id="severity">
+ <% Severity::KEYS.each do |severity| %>
+ <option class="sev_<%= severity -%>" value="<%= severity -%>" <%= 'selected' if severity==Severity::MAJOR -%>><%= message("severity.#{severity}") -%></option>
+ <% end %>
+ </select>
+ </div>
</div>
<div class="modal-foot">
<input type="submit" value="<%= message('submit') -%>" id="bulk-change-submit"/>
</form>
<script>
$j("#bulk-change-form").modalForm({success:function (data) {
- window.location = baseUrl + '/issues/filter/' + data;
+ window.location = baseUrl + '/issues/search/' + data;
}});
</script>
\ No newline at end of file
+++ /dev/null
-<form id="copy-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/copy">
- <input type="hidden" name="id" value="<%= params[:id] || @filter.id -%>">
- <fieldset>
- <div class="modal-head">
- <h2><%= message('issue_filter.copy_filter') -%></h2>
- </div>
- <%= render :partial => 'shared_form' %>
- <div class="modal-foot">
- <input type="submit" value="<%= message('copy') -%>" id="copy-submit"/>
- <a href="#" onclick="return closeModalWindow()" id="copy-cancel"><%= h message('cancel') -%></a>
- </div>
- </fieldset>
-</form>
-<script>
- $j("#copy-filter-form").modalForm({success: function (data) {
- window.location = baseUrl + '/issues/filter/' + data;
- }});
-</script>
\ No newline at end of file
+++ /dev/null
-<form id="edit-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/edit">
- <input type="hidden" name="id" value="<%= params[:id] || @filter.id -%>">
- <fieldset>
- <div class="modal-head">
- <h2><%= message('issue_filter.edit_filter') -%></h2>
- </div>
-
- <%= render :partial => 'shared_form', :locals => {:display_owner => true} %>
-
- <div class="modal-foot">
- <input type="submit" value="<%= message('save') -%>" id="save-submit"/>
- <a href="#" onclick="return closeModalWindow()" id="save-cancel"><%= message('cancel') -%></a>
- </div>
- </fieldset>
-</form>
-<script>
- $j("#edit-filter-form").modalForm({success: function (data) {
- window.location = baseUrl + '/issues/filter/' + data;
- }});
-</script>
\ No newline at end of file
+++ /dev/null
-<div id="sidebar-favourites">
-<% if logged_in? %>
- <li class="sidebar-title"><%= message('issue_filter.favourite_filters') -%></li>
- <% @favourite_filters.each do |filter| %>
- <li <%= "class='active'" if @filter && filter.id==@filter.id -%>>
- <a href="<%= ApplicationController.root_context -%>/issues/filter/<%= filter.id -%>"><%= h filter.name -%></a>
- </li>
- <% end %>
-
- <li><a href="<%= ApplicationController.root_context -%>/issues/manage" class="link-action"><%= message('manage') %></a></li>
- <li class="spacer"></li>
-<% end %>
-</div>
\ No newline at end of file
--- /dev/null
+<form id="copy-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/copy">
+ <input type="hidden" name="id" value="<%= params[:id] || @filter.id -%>">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_filter.copy_filter') -%></h2>
+ </div>
+ <%= render :partial => 'filter_shared_form' %>
+ <div class="modal-foot">
+ <input type="submit" value="<%= message('copy') -%>" id="copy-submit"/>
+ <a href="#" onclick="return closeModalWindow()" id="copy-cancel"><%= h message('cancel') -%></a>
+ </div>
+ </fieldset>
+</form>
+<script>
+ $j("#copy-filter-form").modalForm({success: function (data) {
+ window.location = baseUrl + '/issues/filter/' + data;
+ }});
+</script>
\ No newline at end of file
--- /dev/null
+<form id="edit-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/edit">
+ <input type="hidden" name="id" value="<%= params[:id] || @filter.id -%>">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_filter.edit_filter') -%></h2>
+ </div>
+ <%= render :partial => 'filter_shared_form', :locals => {:display_owner => true} %>
+ <div class="modal-foot">
+ <input type="submit" value="<%= message('save') -%>" id="save-submit"/>
+ <a href="#" onclick="return closeModalWindow()" id="save-cancel"><%= message('cancel') -%></a>
+ </div>
+ </fieldset>
+</form>
+<script>
+ $j("#edit-filter-form").modalForm({success: function (data) {
+ window.location = baseUrl + '/issues/filter/' + data;
+ }});
+</script>
\ No newline at end of file
--- /dev/null
+<div id="sidebar-favourites">
+<% if logged_in? %>
+ <li class="sidebar-title"><%= message('issue_filter.favourite_filters') -%></li>
+ <% @favourite_filters.each do |filter| %>
+ <li <%= "class='active'" if @filter && filter.id==@filter.id -%>>
+ <a href="<%= ApplicationController.root_context -%>/issues/filter/<%= filter.id -%>"><%= h filter.name -%></a>
+ </li>
+ <% end %>
+
+ <li><a href="<%= ApplicationController.root_context -%>/issues/manage" class="link-action"><%= message('manage') %></a></li>
+ <li class="spacer"></li>
+<% end %>
+</div>
\ No newline at end of file
--- /dev/null
+<form id="save-as-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/save_as">
+ <input type="hidden" name="data" value="<%= params[:data] || u(@filter_query_serialized) -%>">
+ <fieldset>
+ <div class="modal-head">
+ <h2><%= message('issue_filter.save_filter') -%></h2>
+ </div>
+ <%= render :partial => 'filter_shared_form' %>
+ <div class="modal-foot">
+ <input type="submit" value="<%= message('save') -%>" id="save-as-submit"/>
+ <a href="#" onclick="return closeModalWindow()" id="save-as-cancel"><%= 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
--- /dev/null
+<% if !local_assigns.has_key? :display_owner
+ display_owner = false
+ end %>
+<div class="modal-body">
+ <%= render :partial => 'display_errors' %>
+ <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="<%= params[:name] || (h(@filter.name) if @filter) -%>" 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="<%= params[:description] || (h(@filter.description) if @filter) -%>"/>
+ </div>
+ <% if display_owner && can_be_reassigned_by(current_user, @filter) %>
+ <% filter_owner = Api.users.findByLogin(@filter.user) %>
+ <div class="modal-field">
+ <label for="user"><%= h message('issue_filter.form.owner') -%></label>
+ <%= user_select_tag('user', :html_id => 'select-filter-owner', :selected_user => filter_owner) -%>
+ </div>
+ <% end %>
+ <div class="modal-field">
+ <label for="shared"><%= message('issue_filter.form.share') -%></label>
+ <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if (params[:shared] || (@filter && @filter.shared)) -%>/>
+ </div>
+</div>
\ No newline at end of file
+++ /dev/null
-<form id="save-as-filter-form" method="post" action="<%= ApplicationController.root_context -%>/issues/save_as">
- <input type="hidden" name="data" value="<%= params[:data] || u(@filter_query_serialized) -%>">
- <fieldset>
- <div class="modal-head">
- <h2><%= message('issue_filter.save_filter') -%></h2>
- </div>
- <%= render :partial => 'shared_form' %>
- <div class="modal-foot">
- <input type="submit" value="<%= message('save') -%>" id="save-as-submit"/>
- <a href="#" onclick="return closeModalWindow()" id="save-as-cancel"><%= 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
+++ /dev/null
-<% if !local_assigns.has_key? :display_owner
- display_owner = false
- end %>
-<div class="modal-body">
- <%= render :partial => 'display_errors' %>
- <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="<%= params[:name] || (h(@filter.name) if @filter) -%>" 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="<%= params[:description] || (h(@filter.description) if @filter) -%>"/>
- </div>
- <% if display_owner && can_be_reassigned_by(current_user, @filter) %>
- <% filter_owner = Api.users.findByLogin(@filter.user) %>
- <div class="modal-field">
- <label for="user"><%= h message('issue_filter.form.owner') -%></label>
- <%= user_select_tag('user', :html_id => 'select-filter-owner', :selected_user => filter_owner) -%>
- </div>
- <% end %>
- <div class="modal-field">
- <label for="shared"><%= message('issue_filter.form.share') -%></label>
- <input id="shared" name="shared" type="checkbox" value="true" <%= 'checked' if (params[:shared] || (@filter && @filter.shared)) -%>/>
- </div>
-</div>
\ No newline at end of file
<ul class="sidebar gray-sidebar">
- <%= render :partial => 'issues/favourites' -%>
+ <%= render :partial => 'issues/filter_favourites' -%>
<form method="GET" action="<%= ApplicationController.root_context -%>/issues/search" >
<a id="save-as" href="<%= url_for params.merge({:action => 'save_as_form'}) -%>" class="link-action open-modal"><%= message('save_as') -%></a>
</li>
<% end %>
- <!--<li>-->
- <!--<a id="bulk-change" href="<%= url_for params.merge({:action => 'bulk_change_form'}) -%>" class="link-action open-modal"><%= message('bulk_change') -%></a>-->
- <!--</li>-->
+ <li>
+ <a id="bulk-change" href="<%= url_for params.merge({:action => 'bulk_change_form'}) -%>" class="link-action open-modal"><%= message('bulk_change') -%></a>
+ </li>
</ul>
<div class="page_title" id="filter-title">
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
public class IssueBulkChangeQueryTest {
@Test
- public void should_create_query(){
+ public void should_create_query() {
Map<String, Object> params = newHashMap();
params.put("issues", newArrayList("ABCD", "EFGH"));
params.put("actions", newArrayList("do_transition", "assign", "set_severity", "plan"));
}
@Test
- public void should_create_query_with_comment(){
+ public void should_create_query_with_comment() {
Map<String, Object> params = newHashMap();
params.put("issues", newArrayList("ABCD", "EFGH"));
params.put("actions", newArrayList("assign"));
}
@Test
- public void should_get_properties_action(){
+ public void should_get_properties_action() {
Map<String, Object> params = newHashMap();
params.put("issues", newArrayList("ABCD", "EFGH"));
params.put("actions", newArrayList("assign"));
assertThat(issueBulkChangeQuery.properties("assign").get("assignee")).isEqualTo("arthur");
}
- @Test(expected = IllegalArgumentException.class)
- public void fail_to_build_if_no_issue(){
+ @Test
+ public void fail_to_build_if_no_issue() {
Map<String, Object> params = newHashMap();
params.put("actions", newArrayList("assign"));
params.put("assign.assignee", "arthur");
- new IssueBulkChangeQuery(params);
+ try {
+ new IssueBulkChangeQuery(params);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issues must not be empty");
+ }
}
- @Test(expected = IllegalArgumentException.class)
- public void fail_to_build_if_issues_are_empty(){
+ @Test
+ public void fail_to_build_if_issues_are_empty() {
Map<String, Object> params = newHashMap();
params.put("issues", Collections.emptyList());
params.put("actions", newArrayList("assign"));
params.put("assign.assignee", "arthur");
- new IssueBulkChangeQuery(params);
+ try {
+ new IssueBulkChangeQuery(params);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issues must not be empty");
+ }
}
- @Test(expected = IllegalArgumentException.class)
- public void fail_to_build_if_no_action(){
+ @Test
+ public void fail_to_build_if_no_action() {
Map<String, Object> params = newHashMap();
- params.put("issues", Collections.emptyList());
- new IssueBulkChangeQuery(params);
+ params.put("issues", newArrayList("ABCD", "EFGH"));
+ try {
+ new IssueBulkChangeQuery(params);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("At least one action must be provided");
+ }
}
- @Test(expected = IllegalArgumentException.class)
- public void fail_to_build_if_actions_are_empty(){
+ @Test
+ public void fail_to_build_if_actions_are_empty() {
Map<String, Object> params = newHashMap();
params.put("issues", newArrayList("ABCD", "EFGH"));
params.put("actions", Collections.emptyList());
- new IssueBulkChangeQuery(params);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void fail_to_build_if_action_properties_are_empty(){
- Map<String, Object> params = newHashMap();
- params.put("issues", Collections.emptyList());
- params.put("actions", newArrayList("assign"));
- new IssueBulkChangeQuery(params);
+ try {
+ new IssueBulkChangeQuery(params);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("At least one action must be provided");
+ }
}
}