@@ -19,13 +19,14 class IssuesController < ApplicationController | |||||
19 | layout 'base' |
|
19 | layout 'base' | |
20 | menu_item :new_issue, :only => :new |
|
20 | menu_item :new_issue, :only => :new | |
21 |
|
21 | |||
22 |
before_filter :find_issue, : |
|
22 | before_filter :find_issue, :only => [:show, :edit, :destroy_attachment] | |
|
23 | before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] | |||
23 | before_filter :find_project, :only => [:new, :update_form] |
|
24 | before_filter :find_project, :only => [:new, :update_form] | |
24 | before_filter :authorize, :except => [:index, :changes, :preview, :update_form] |
|
25 | before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu] | |
25 | before_filter :find_optional_project, :only => [:index, :changes] |
|
26 | before_filter :find_optional_project, :only => [:index, :changes] | |
26 | accept_key_auth :index, :changes |
|
27 | accept_key_auth :index, :changes | |
27 |
|
28 | |||
28 | cache_sweeper :issue_sweeper, :only => [ :new, :edit, :destroy ] |
|
29 | cache_sweeper :issue_sweeper, :only => [ :new, :edit, :bulk_edit, :destroy ] | |
29 |
|
30 | |||
30 | helper :journals |
|
31 | helper :journals | |
31 | helper :projects |
|
32 | helper :projects | |
@@ -152,18 +153,20 class IssuesController < ApplicationController | |||||
152 | @priorities = Enumeration::get_values('IPRI') |
|
153 | @priorities = Enumeration::get_values('IPRI') | |
153 | @custom_values = [] |
|
154 | @custom_values = [] | |
154 | @edit_allowed = User.current.allowed_to?(:edit_issues, @project) |
|
155 | @edit_allowed = User.current.allowed_to?(:edit_issues, @project) | |
|
156 | ||||
|
157 | @notes = params[:notes] | |||
|
158 | journal = @issue.init_journal(User.current, @notes) | |||
|
159 | # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed | |||
|
160 | if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue] | |||
|
161 | attrs = params[:issue].dup | |||
|
162 | attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) } unless @edit_allowed | |||
|
163 | attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s} | |||
|
164 | @issue.attributes = attrs | |||
|
165 | end | |||
|
166 | ||||
155 | if request.get? |
|
167 | if request.get? | |
156 | @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) } |
|
168 | @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) } | |
157 | else |
|
169 | else | |
158 | @notes = params[:notes] |
|
|||
159 | journal = @issue.init_journal(User.current, @notes) |
|
|||
160 | # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed |
|
|||
161 | if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue] |
|
|||
162 | attrs = params[:issue].dup |
|
|||
163 | attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) } unless @edit_allowed |
|
|||
164 | attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s} |
|
|||
165 | @issue.attributes = attrs |
|
|||
166 | end |
|
|||
167 | # Update custom fields if user has :edit permission |
|
170 | # Update custom fields if user has :edit permission | |
168 | if @edit_allowed && params[:custom_fields] |
|
171 | if @edit_allowed && params[:custom_fields] | |
169 | @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } |
|
172 | @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) } | |
@@ -191,8 +194,78 class IssuesController < ApplicationController | |||||
191 | flash.now[:error] = l(:notice_locking_conflict) |
|
194 | flash.now[:error] = l(:notice_locking_conflict) | |
192 | end |
|
195 | end | |
193 |
|
196 | |||
|
197 | # Bulk edit a set of issues | |||
|
198 | def bulk_edit | |||
|
199 | if request.post? | |||
|
200 | status = params[:status_id].blank? ? nil : IssueStatus.find_by_id(params[:status_id]) | |||
|
201 | priority = params[:priority_id].blank? ? nil : Enumeration.find_by_id(params[:priority_id]) | |||
|
202 | assigned_to = params[:assigned_to_id].blank? ? nil : User.find_by_id(params[:assigned_to_id]) | |||
|
203 | category = params[:category_id].blank? ? nil : @project.issue_categories.find_by_id(params[:category_id]) | |||
|
204 | fixed_version = params[:fixed_version_id].blank? ? nil : @project.versions.find_by_id(params[:fixed_version_id]) | |||
|
205 | ||||
|
206 | unsaved_issue_ids = [] | |||
|
207 | @issues.each do |issue| | |||
|
208 | journal = issue.init_journal(User.current, params[:notes]) | |||
|
209 | issue.priority = priority if priority | |||
|
210 | issue.assigned_to = assigned_to if assigned_to || params[:assigned_to_id] == 'none' | |||
|
211 | issue.category = category if category | |||
|
212 | issue.fixed_version = fixed_version if fixed_version | |||
|
213 | issue.start_date = params[:start_date] unless params[:start_date].blank? | |||
|
214 | issue.due_date = params[:due_date] unless params[:due_date].blank? | |||
|
215 | issue.done_ratio = params[:done_ratio] unless params[:done_ratio].blank? | |||
|
216 | # Don't save any change to the issue if the user is not authorized to apply the requested status | |||
|
217 | if (status.nil? || (issue.status.new_status_allowed_to?(status, current_role, issue.tracker) && issue.status = status)) && issue.save | |||
|
218 | # Send notification for each issue (if changed) | |||
|
219 | Mailer.deliver_issue_edit(journal) if journal.details.any? && Setting.notified_events.include?('issue_updated') | |||
|
220 | else | |||
|
221 | # Keep unsaved issue ids to display them in flash error | |||
|
222 | unsaved_issue_ids << issue.id | |||
|
223 | end | |||
|
224 | end | |||
|
225 | if unsaved_issue_ids.empty? | |||
|
226 | flash[:notice] = l(:notice_successful_update) unless @issues.empty? | |||
|
227 | else | |||
|
228 | flash[:error] = l(:notice_failed_to_save_issues, unsaved_issue_ids.size, @issues.size, '#' + unsaved_issue_ids.join(', #')) | |||
|
229 | end | |||
|
230 | redirect_to :controller => 'issues', :action => 'index', :project_id => @project | |||
|
231 | return | |||
|
232 | end | |||
|
233 | # Find potential statuses the user could be allowed to switch issues to | |||
|
234 | @available_statuses = Workflow.find(:all, :include => :new_status, | |||
|
235 | :conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq | |||
|
236 | end | |||
|
237 | ||||
|
238 | def move | |||
|
239 | @allowed_projects = [] | |||
|
240 | # find projects to which the user is allowed to move the issue | |||
|
241 | if User.current.admin? | |||
|
242 | # admin is allowed to move issues to any active (visible) project | |||
|
243 | @allowed_projects = Project.find(:all, :conditions => Project.visible_by(User.current), :order => 'name') | |||
|
244 | else | |||
|
245 | User.current.memberships.each {|m| @allowed_projects << m.project if m.role.allowed_to?(:move_issues)} | |||
|
246 | end | |||
|
247 | @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] | |||
|
248 | @target_project ||= @project | |||
|
249 | @trackers = @target_project.trackers | |||
|
250 | if request.post? | |||
|
251 | new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) | |||
|
252 | unsaved_issue_ids = [] | |||
|
253 | @issues.each do |issue| | |||
|
254 | unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker) | |||
|
255 | end | |||
|
256 | if unsaved_issue_ids.empty? | |||
|
257 | flash[:notice] = l(:notice_successful_update) unless @issues.empty? | |||
|
258 | else | |||
|
259 | flash[:error] = l(:notice_failed_to_save_issues, unsaved_issue_ids.size, @issues.size, '#' + unsaved_issue_ids.join(', #')) | |||
|
260 | end | |||
|
261 | redirect_to :controller => 'issues', :action => 'index', :project_id => @project | |||
|
262 | return | |||
|
263 | end | |||
|
264 | render :layout => false if request.xhr? | |||
|
265 | end | |||
|
266 | ||||
194 | def destroy |
|
267 | def destroy | |
195 | @issue.destroy |
|
268 | @issues.each(&:destroy) | |
196 | redirect_to :action => 'index', :project_id => @project |
|
269 | redirect_to :action => 'index', :project_id => @project | |
197 | end |
|
270 | end | |
198 |
|
271 | |||
@@ -208,17 +281,27 class IssuesController < ApplicationController | |||||
208 | end |
|
281 | end | |
209 |
|
282 | |||
210 | def context_menu |
|
283 | def context_menu | |
|
284 | @issues = Issue.find_all_by_id(params[:ids], :include => :project) | |||
|
285 | if (@issues.size == 1) | |||
|
286 | @issue = @issues.first | |||
|
287 | @allowed_statuses = @issue.new_statuses_allowed_to(User.current) | |||
|
288 | @assignables = @issue.assignable_users | |||
|
289 | @assignables << @issue.assigned_to if @issue.assigned_to && !@assignables.include?(@issue.assigned_to) | |||
|
290 | end | |||
|
291 | projects = @issues.collect(&:project).compact.uniq | |||
|
292 | @project = projects.first if projects.size == 1 | |||
|
293 | ||||
|
294 | @can = {:edit => (@project && User.current.allowed_to?(:edit_issues, @project)), | |||
|
295 | :update => (@issue && (User.current.allowed_to?(:edit_issues, @project) || (User.current.allowed_to?(:change_status, @project) && !@allowed_statuses.empty?))), | |||
|
296 | :move => (@project && User.current.allowed_to?(:move_issues, @project)), | |||
|
297 | :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)), | |||
|
298 | :delete => (@project && User.current.allowed_to?(:delete_issues, @project)) | |||
|
299 | } | |||
|
300 | ||||
211 | @priorities = Enumeration.get_values('IPRI').reverse |
|
301 | @priorities = Enumeration.get_values('IPRI').reverse | |
212 | @statuses = IssueStatus.find(:all, :order => 'position') |
|
302 | @statuses = IssueStatus.find(:all, :order => 'position') | |
213 | @allowed_statuses = @issue.new_statuses_allowed_to(User.current) |
|
303 | @back = request.env['HTTP_REFERER'] | |
214 | @assignables = @issue.assignable_users |
|
304 | ||
215 | @assignables << @issue.assigned_to if @issue.assigned_to && !@assignables.include?(@issue.assigned_to) |
|
|||
216 | @can = {:edit => User.current.allowed_to?(:edit_issues, @project), |
|
|||
217 | :assign => (@allowed_statuses.any? || User.current.allowed_to?(:edit_issues, @project)), |
|
|||
218 | :add => User.current.allowed_to?(:add_issues, @project), |
|
|||
219 | :move => User.current.allowed_to?(:move_issues, @project), |
|
|||
220 | :copy => (@project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)), |
|
|||
221 | :delete => User.current.allowed_to?(:delete_issues, @project)} |
|
|||
222 | render :layout => false |
|
305 | render :layout => false | |
223 | end |
|
306 | end | |
224 |
|
307 | |||
@@ -242,6 +325,21 private | |||||
242 | render_404 |
|
325 | render_404 | |
243 | end |
|
326 | end | |
244 |
|
327 | |||
|
328 | # Filter for bulk operations | |||
|
329 | def find_issues | |||
|
330 | @issues = Issue.find_all_by_id(params[:id] || params[:ids]) | |||
|
331 | raise ActiveRecord::RecordNotFound if @issues.empty? | |||
|
332 | projects = @issues.collect(&:project).compact.uniq | |||
|
333 | if projects.size == 1 | |||
|
334 | @project = projects.first | |||
|
335 | else | |||
|
336 | # TODO: let users bulk edit/move/destroy issues from different projects | |||
|
337 | render_error 'Can not bulk edit/move/destroy issues from different projects' and return false | |||
|
338 | end | |||
|
339 | rescue ActiveRecord::RecordNotFound | |||
|
340 | render_404 | |||
|
341 | end | |||
|
342 | ||||
245 | def find_project |
|
343 | def find_project | |
246 | @project = Project.find(params[:project_id]) |
|
344 | @project = Project.find(params[:project_id]) | |
247 | rescue ActiveRecord::RecordNotFound |
|
345 | rescue ActiveRecord::RecordNotFound |
@@ -22,7 +22,7 class ProjectsController < ApplicationController | |||||
22 | menu_item :roadmap, :only => :roadmap |
|
22 | menu_item :roadmap, :only => :roadmap | |
23 | menu_item :files, :only => [:list_files, :add_file] |
|
23 | menu_item :files, :only => [:list_files, :add_file] | |
24 | menu_item :settings, :only => :settings |
|
24 | menu_item :settings, :only => :settings | |
25 |
menu_item :issues, :only => [ |
|
25 | menu_item :issues, :only => [:changelog] | |
26 |
|
26 | |||
27 | before_filter :find_project, :except => [ :index, :list, :add ] |
|
27 | before_filter :find_project, :except => [ :index, :list, :add ] | |
28 | before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy ] |
|
28 | before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy ] | |
@@ -182,83 +182,6 class ProjectsController < ApplicationController | |||||
182 | end |
|
182 | end | |
183 | end |
|
183 | end | |
184 |
|
184 | |||
185 | # Bulk edit issues |
|
|||
186 | def bulk_edit_issues |
|
|||
187 | if request.post? |
|
|||
188 | status = params[:status_id].blank? ? nil : IssueStatus.find_by_id(params[:status_id]) |
|
|||
189 | priority = params[:priority_id].blank? ? nil : Enumeration.find_by_id(params[:priority_id]) |
|
|||
190 | assigned_to = params[:assigned_to_id].blank? ? nil : User.find_by_id(params[:assigned_to_id]) |
|
|||
191 | category = params[:category_id].blank? ? nil : @project.issue_categories.find_by_id(params[:category_id]) |
|
|||
192 | fixed_version = params[:fixed_version_id].blank? ? nil : @project.versions.find_by_id(params[:fixed_version_id]) |
|
|||
193 | issues = @project.issues.find_all_by_id(params[:issue_ids]) |
|
|||
194 | unsaved_issue_ids = [] |
|
|||
195 | issues.each do |issue| |
|
|||
196 | journal = issue.init_journal(User.current, params[:notes]) |
|
|||
197 | issue.priority = priority if priority |
|
|||
198 | issue.assigned_to = assigned_to if assigned_to || params[:assigned_to_id] == 'none' |
|
|||
199 | issue.category = category if category |
|
|||
200 | issue.fixed_version = fixed_version if fixed_version |
|
|||
201 | issue.start_date = params[:start_date] unless params[:start_date].blank? |
|
|||
202 | issue.due_date = params[:due_date] unless params[:due_date].blank? |
|
|||
203 | issue.done_ratio = params[:done_ratio] unless params[:done_ratio].blank? |
|
|||
204 | # Don't save any change to the issue if the user is not authorized to apply the requested status |
|
|||
205 | if (status.nil? || (issue.status.new_status_allowed_to?(status, current_role, issue.tracker) && issue.status = status)) && issue.save |
|
|||
206 | # Send notification for each issue (if changed) |
|
|||
207 | Mailer.deliver_issue_edit(journal) if journal.details.any? && Setting.notified_events.include?('issue_updated') |
|
|||
208 | else |
|
|||
209 | # Keep unsaved issue ids to display them in flash error |
|
|||
210 | unsaved_issue_ids << issue.id |
|
|||
211 | end |
|
|||
212 | end |
|
|||
213 | if unsaved_issue_ids.empty? |
|
|||
214 | flash[:notice] = l(:notice_successful_update) unless issues.empty? |
|
|||
215 | else |
|
|||
216 | flash[:error] = l(:notice_failed_to_save_issues, unsaved_issue_ids.size, issues.size, '#' + unsaved_issue_ids.join(', #')) |
|
|||
217 | end |
|
|||
218 | redirect_to :controller => 'issues', :action => 'index', :project_id => @project |
|
|||
219 | return |
|
|||
220 | end |
|
|||
221 | # Find potential statuses the user could be allowed to switch issues to |
|
|||
222 | @available_statuses = Workflow.find(:all, :include => :new_status, |
|
|||
223 | :conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq |
|
|||
224 | render :update do |page| |
|
|||
225 | page.hide 'query_form' |
|
|||
226 | page.replace_html 'bulk-edit', :partial => 'issues/bulk_edit_form' |
|
|||
227 | end |
|
|||
228 | end |
|
|||
229 |
|
||||
230 | def move_issues |
|
|||
231 | @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids] |
|
|||
232 | redirect_to :controller => 'issues', :action => 'index', :project_id => @project and return unless @issues |
|
|||
233 |
|
||||
234 | @projects = [] |
|
|||
235 | # find projects to which the user is allowed to move the issue |
|
|||
236 | if User.current.admin? |
|
|||
237 | # admin is allowed to move issues to any active (visible) project |
|
|||
238 | @projects = Project.find(:all, :conditions => Project.visible_by(User.current), :order => 'name') |
|
|||
239 | else |
|
|||
240 | User.current.memberships.each {|m| @projects << m.project if m.role.allowed_to?(:move_issues)} |
|
|||
241 | end |
|
|||
242 | @target_project = @projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] |
|
|||
243 | @target_project ||= @project |
|
|||
244 | @trackers = @target_project.trackers |
|
|||
245 | if request.post? |
|
|||
246 | new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) |
|
|||
247 | unsaved_issue_ids = [] |
|
|||
248 | @issues.each do |issue| |
|
|||
249 | unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker) |
|
|||
250 | end |
|
|||
251 | if unsaved_issue_ids.empty? |
|
|||
252 | flash[:notice] = l(:notice_successful_update) unless @issues.empty? |
|
|||
253 | else |
|
|||
254 | flash[:error] = l(:notice_failed_to_save_issues, unsaved_issue_ids.size, @issues.size, '#' + unsaved_issue_ids.join(', #')) |
|
|||
255 | end |
|
|||
256 | redirect_to :controller => 'issues', :action => 'index', :project_id => @project |
|
|||
257 | return |
|
|||
258 | end |
|
|||
259 | render :layout => false if request.xhr? |
|
|||
260 | end |
|
|||
261 |
|
||||
262 | def add_file |
|
185 | def add_file | |
263 | if request.post? |
|
186 | if request.post? | |
264 | @version = @project.versions.find_by_id(params[:version_id]) |
|
187 | @version = @project.versions.find_by_id(params[:version_id]) |
@@ -1,10 +1,7 | |||||
1 | <div id="bulk-edit"></div> |
|
1 | <% form_tag({}) do -%> | |
2 | <table class="list"> |
|
2 | <table class="list issues"> | |
3 | <thead><tr> |
|
3 | <thead><tr> | |
4 | <th><%= link_to_remote(image_tag('edit.png'), |
|
4 | <th><%= link_to image_tag('edit.png'), {}, :onclick => 'toggleIssuesSelection(this.up("form")); return false;' %> | |
5 | {:url => { :controller => 'projects', :action => 'bulk_edit_issues', :id => @project }, |
|
|||
6 | :method => :get}, |
|
|||
7 | {:title => l(:label_bulk_edit_selected_issues)}) if @project && User.current.allowed_to?(:edit_issues, @project) %> |
|
|||
8 | </th> |
|
5 | </th> | |
9 | <%= sort_header_tag("#{Issue.table_name}.id", :caption => '#', :default_order => 'desc') %> |
|
6 | <%= sort_header_tag("#{Issue.table_name}.id", :caption => '#', :default_order => 'desc') %> | |
10 | <% query.columns.each do |column| %> |
|
7 | <% query.columns.each do |column| %> | |
@@ -12,14 +9,21 | |||||
12 | <% end %> |
|
9 | <% end %> | |
13 | </tr></thead> |
|
10 | </tr></thead> | |
14 | <tbody> |
|
11 | <tbody> | |
15 | <% issues.each do |issue| %> |
|
12 | <% issues.each do |issue| -%> | |
16 | <tr id="issue-<%= issue.id %>" class="issue hascontextmenu <%= cycle('odd', 'even') %> <%= "status-#{issue.status.position} priority-#{issue.priority.position}" %>"> |
|
13 | <tr id="issue-<%= issue.id %>" class="issue hascontextmenu <%= cycle('odd', 'even') %> <%= "status-#{issue.status.position} priority-#{issue.priority.position}" %>"> | |
17 |
<td class="checkbox"><%= check_box_tag(" |
|
14 | <td class="checkbox"><%= check_box_tag("ids[]", issue.id, false) %></td> | |
18 | <td><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td> |
|
15 | <td><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td> | |
19 | <% query.columns.each do |column| %> |
|
16 | <% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.name %><% end %> | |
20 | <%= content_tag 'td', column_content(column, issue), :class => column.name %> |
|
|||
21 | <% end %> |
|
|||
22 | </tr> |
|
17 | </tr> | |
23 | <% end %> |
|
18 | <% end -%> | |
24 | </tbody> |
|
19 | </tbody> | |
25 | </table> |
|
20 | </table> | |
|
21 | <% end -%> | |||
|
22 | ||||
|
23 | <% content_for :header_tags do -%> | |||
|
24 | <%= javascript_include_tag 'context_menu' %> | |||
|
25 | <%= stylesheet_link_tag 'context_menu' %> | |||
|
26 | <% end -%> | |||
|
27 | ||||
|
28 | <div id="context-menu" style="display: none;"></div> | |||
|
29 | <%= javascript_tag "new ContextMenu('#{url_for(:controller => 'issues', :action => 'context_menu')}')" %> |
@@ -1,5 +1,6 | |||||
1 |
<% if issues. |
|
1 | <% if issues && issues.any? %> | |
2 | <table class="list"> |
|
2 | <% form_tag({}) do %> | |
|
3 | <table class="list issues"> | |||
3 | <thead><tr> |
|
4 | <thead><tr> | |
4 | <th>#</th> |
|
5 | <th>#</th> | |
5 | <th><%=l(:field_tracker)%></th> |
|
6 | <th><%=l(:field_tracker)%></th> | |
@@ -9,6 +10,7 | |||||
9 | <% for issue in issues %> |
|
10 | <% for issue in issues %> | |
10 | <tr id="issue-<%= issue.id %>" class="issue hascontextmenu <%= cycle('odd', 'even') %> <%= "status-#{issue.status.position} priority-#{issue.priority.position}" %>"> |
|
11 | <tr id="issue-<%= issue.id %>" class="issue hascontextmenu <%= cycle('odd', 'even') %> <%= "status-#{issue.status.position} priority-#{issue.priority.position}" %>"> | |
11 | <td class="id"> |
|
12 | <td class="id"> | |
|
13 | <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %> | |||
12 | <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %> |
|
14 | <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %> | |
13 | </td> |
|
15 | </td> | |
14 | <td><%=h issue.project.name %> - <%= issue.tracker.name %><br /> |
|
16 | <td><%=h issue.project.name %> - <%= issue.tracker.name %><br /> | |
@@ -20,6 +22,7 | |||||
20 | <% end %> |
|
22 | <% end %> | |
21 | </tbody> |
|
23 | </tbody> | |
22 | </table> |
|
24 | </table> | |
|
25 | <% end %> | |||
23 | <% else %> |
|
26 | <% else %> | |
24 |
< |
|
27 | <p class="nodata"><%= l(:label_no_data) %></p> | |
25 | <% end %> No newline at end of file |
|
28 | <% end %> |
@@ -1,6 +1,12 | |||||
1 | <div id="bulk-edit-fields"> |
|
1 | <h2><%= l(:label_bulk_edit_selected_issues) %></h2> | |
2 | <fieldset class="box"><legend><%= l(:label_bulk_edit_selected_issues) %></legend> |
|
|||
3 |
|
2 | |||
|
3 | <ul><%= @issues.collect {|i| content_tag('li', link_to(h("#{i.tracker} ##{i.id}"), { :action => 'show', :id => i }) + h(": #{i.subject}")) }.join("\n") %></ul> | |||
|
4 | ||||
|
5 | <% form_tag() do %> | |||
|
6 | <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> | |||
|
7 | <div class="box"> | |||
|
8 | <fieldset> | |||
|
9 | <legend><%= l(:label_change_properties) %></legend> | |||
4 | <p> |
|
10 | <p> | |
5 | <% if @available_statuses.any? %> |
|
11 | <% if @available_statuses.any? %> | |
6 | <label><%= l(:field_status) %>: |
|
12 | <label><%= l(:field_status) %>: | |
@@ -28,11 +34,12 | |||||
28 | <label><%= l(:field_done_ratio) %>: |
|
34 | <label><%= l(:field_done_ratio) %>: | |
29 | <%= select_tag 'done_ratio', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></label> |
|
35 | <%= select_tag 'done_ratio', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></label> | |
30 | </p> |
|
36 | </p> | |
31 |
|
||||
32 | <label for="notes"><%= l(:field_notes) %></label><br /> |
|
|||
33 | <%= text_area_tag 'notes', '', :cols => 80, :rows => 5 %> |
|
|||
34 |
|
||||
35 | </fieldset> |
|
37 | </fieldset> | |
36 | <p><%= submit_tag l(:button_apply) %> |
|
38 | ||
37 | <%= link_to l(:button_cancel), {}, :onclick => 'Element.hide("bulk-edit-fields"); if ($("query_form")) {Element.show("query_form")}; return false;' %></p> |
|
39 | <fieldset><legend><%= l(:field_notes) %></legend> | |
|
40 | <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> | |||
|
41 | <%= wikitoolbar_for 'notes' %> | |||
38 | </div> |
|
42 | </div> | |
|
43 | ||||
|
44 | <p><%= submit_tag l(:button_submit) %> | |||
|
45 | <% end %> |
@@ -1,40 +1,45 | |||||
1 | <% back_to = url_for(:controller => 'issues', :action => 'index', :project_id => @project) %> |
|
|||
2 |
|
|
1 | <ul> | |
|
2 | <% if !@issue.nil? -%> | |||
3 | <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, |
|
3 | <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, | |
4 | :class => 'icon-edit', :disabled => !@can[:edit] %></li> |
|
4 | :class => 'icon-edit', :disabled => !@can[:edit] %></li> | |
5 | <li class="folder"> |
|
5 | <li class="folder"> | |
6 | <a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a> |
|
6 | <a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a> | |
7 | <ul> |
|
7 | <ul> | |
8 | <% @statuses.each do |s| %> |
|
8 | <% @statuses.each do |s| -%> | |
9 | <li><%= context_menu_link s.name, {:controller => 'issues', :action => 'edit', :id => @issue, :issue => {:status_id => s}}, |
|
9 | <li><%= context_menu_link s.name, {:controller => 'issues', :action => 'edit', :id => @issue, :issue => {:status_id => s}}, | |
10 | :selected => (s == @issue.status), :disabled => !(@allowed_statuses.include?(s)) %></li> |
|
10 | :selected => (s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %></li> | |
11 | <% end %> |
|
11 | <% end -%> | |
12 | </ul> |
|
12 | </ul> | |
13 | </li> |
|
13 | </li> | |
14 | <li class="folder"> |
|
14 | <li class="folder"> | |
15 | <a href="#" class="submenu"><%= l(:field_priority) %></a> |
|
15 | <a href="#" class="submenu"><%= l(:field_priority) %></a> | |
16 | <ul> |
|
16 | <ul> | |
17 | <% @priorities.each do |p| %> |
|
17 | <% @priorities.each do |p| -%> | |
18 |
<li><%= context_menu_link p.name, {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[priority_id]' => p, :back_to => back |
|
18 | <li><%= context_menu_link p.name, {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[priority_id]' => p, :back_to => @back}, :method => :post, | |
19 | :selected => (p == @issue.priority), :disabled => !@can[:edit] %></li> |
|
19 | :selected => (p == @issue.priority), :disabled => !@can[:edit] %></li> | |
20 | <% end %> |
|
20 | <% end -%> | |
21 | </ul> |
|
21 | </ul> | |
22 | </li> |
|
22 | </li> | |
23 | <li class="folder"> |
|
23 | <li class="folder"> | |
24 | <a href="#" class="submenu"><%= l(:field_assigned_to) %></a> |
|
24 | <a href="#" class="submenu"><%= l(:field_assigned_to) %></a> | |
25 | <ul> |
|
25 | <ul> | |
26 | <% @assignables.each do |u| %> |
|
26 | <% @assignables.each do |u| -%> | |
27 |
<li><%= context_menu_link u.name, {:controller => 'issues', :action => 'edit', :id => @issue, |
|
27 | <li><%= context_menu_link u.name, {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[assigned_to_id]' => u, :back_to => @back}, :method => :post, | |
28 |
:selected => (u == @issue.assigned_to), :disabled => !@can[: |
|
28 | :selected => (u == @issue.assigned_to), :disabled => !@can[:update] %></li> | |
29 | <% end %> |
|
29 | <% end -%> | |
30 |
<li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'edit', :id => @issue, |
|
30 | <li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[assigned_to_id]' => '', :back_to => @back}, :method => :post, | |
31 |
:selected => @issue.assigned_to.nil?, :disabled => !@can[: |
|
31 | :selected => @issue.assigned_to.nil?, :disabled => !@can[:update] %></li> | |
32 | </ul> |
|
32 | </ul> | |
33 | </li> |
|
33 | </li> | |
34 | <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, |
|
34 | <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, | |
35 | :class => 'icon-copy', :disabled => !@can[:copy] %></li> |
|
35 | :class => 'icon-copy', :disabled => !@can[:copy] %></li> | |
36 | <li><%= context_menu_link l(:button_move), {:controller => 'projects', :action => 'move_issues', :id => @project, "issue_ids[]" => @issue.id }, |
|
36 | <% else -%> | |
37 | :class => 'icon-move', :disabled => !@can[:move] %> |
|
37 | <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)}, | |
38 | <li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, |
|
38 | :class => 'icon-edit', :disabled => !@can[:edit] %></li> | |
39 | :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon-del', :disabled => !@can[:delete] %></li> |
|
39 | <% end -%> | |
|
40 | ||||
|
41 | <li><%= context_menu_link l(:button_move), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id)}, | |||
|
42 | :class => 'icon-move', :disabled => !@can[:move] %></li> | |||
|
43 | <li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)}, | |||
|
44 | :method => :post, :confirm => l(:text_issues_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %></li> | |||
40 | </ul> |
|
45 | </ul> |
@@ -31,7 +31,6 | |||||
31 | <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> |
|
31 | <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> | |
32 | <% end %> |
|
32 | <% end %> | |
33 | </div> |
|
33 | </div> | |
34 |
|
||||
35 | <h2><%=h @query.name %></h2> |
|
34 | <h2><%=h @query.name %></h2> | |
36 | <div id="query_form"></div> |
|
35 | <div id="query_form"></div> | |
37 | <% html_title @query.name %> |
|
36 | <% html_title @query.name %> | |
@@ -41,7 +40,6 | |||||
41 | <% if @issues.empty? %> |
|
40 | <% if @issues.empty? %> | |
42 | <p class="nodata"><%= l(:label_no_data) %></p> |
|
41 | <p class="nodata"><%= l(:label_no_data) %></p> | |
43 | <% else %> |
|
42 | <% else %> | |
44 | <% form_tag({:controller => 'projects', :action => 'bulk_edit_issues', :id => @project}, :id => 'issues_form', :onsubmit => "if (!checkBulkEdit(this)) {alert('#{l(:notice_no_issue_selected)}'); return false;}" ) do %> |
|
|||
45 | <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %> |
|
43 | <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %> | |
46 | <div class="contextual"> |
|
44 | <div class="contextual"> | |
47 | <%= l(:label_export_to) %> |
|
45 | <%= l(:label_export_to) %> | |
@@ -51,7 +49,6 | |||||
51 | <p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p> |
|
49 | <p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p> | |
52 | <% end %> |
|
50 | <% end %> | |
53 | <% end %> |
|
51 | <% end %> | |
54 | <% end %> |
|
|||
55 |
|
52 | |||
56 | <% content_for :sidebar do %> |
|
53 | <% content_for :sidebar do %> | |
57 | <%= render :partial => 'issues/sidebar' %> |
|
54 | <%= render :partial => 'issues/sidebar' %> | |
@@ -60,13 +57,4 | |||||
60 | <% content_for :header_tags do %> |
|
57 | <% content_for :header_tags do %> | |
61 | <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %> |
|
58 | <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %> | |
62 | <%= auto_discovery_link_tag(:atom, {:action => 'changes', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %> |
|
59 | <%= auto_discovery_link_tag(:atom, {:action => 'changes', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %> | |
63 | <%= javascript_include_tag 'calendar/calendar' %> |
|
|||
64 | <%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %> |
|
|||
65 | <%= javascript_include_tag 'calendar/calendar-setup' %> |
|
|||
66 | <%= stylesheet_link_tag 'calendar' %> |
|
|||
67 | <%= javascript_include_tag 'context_menu' %> |
|
|||
68 | <%= stylesheet_link_tag 'context_menu' %> |
|
|||
69 | <% end %> |
|
60 | <% end %> | |
70 |
|
||||
71 | <div id="context-menu" style="display: none;"></div> |
|
|||
72 | <%= javascript_tag 'new ContextMenu({})' %> |
|
@@ -1,23 +1,15 | |||||
1 | <h2><%=l(:button_move)%></h2> |
|
1 | <h2><%= l(:button_move) %></h2> | |
2 |
|
2 | |||
|
3 | <ul><%= @issues.collect {|i| content_tag('li', link_to(h("#{i.tracker} ##{i.id}"), { :action => 'show', :id => i }) + h(": #{i.subject}")) }.join("\n") %></ul> | |||
3 |
|
4 | |||
4 | <% form_tag({:action => 'move_issues', :id => @project}, :class => 'tabular', :id => 'move_form') do %> |
|
5 | <% form_tag({}, :id => 'move_form') do %> | |
|
6 | <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> | |||
5 |
|
7 | |||
6 | <div class="box"> |
|
8 | <div class="box tabular"> | |
7 | <p><label><%= l(:label_issue_plural) %> :</label> |
|
|||
8 | <% for issue in @issues %> |
|
|||
9 | <%= link_to_issue issue %>: <%=h issue.subject %> |
|
|||
10 | <%= hidden_field_tag "issue_ids[]", issue.id %><br /> |
|
|||
11 | <% end %> |
|
|||
12 | <i>(<%= @issues.length%> <%= lwr(:label_issue, @issues.length)%>)</i></p> |
|
|||
13 |
|
||||
14 | |
|
|||
15 |
|
||||
16 | <!--[form:issue]--> |
|
|||
17 | <p><label for="new_project_id"><%=l(:field_project)%> :</label> |
|
9 | <p><label for="new_project_id"><%=l(:field_project)%> :</label> | |
18 | <%= select_tag "new_project_id", |
|
10 | <%= select_tag "new_project_id", | |
19 | options_from_collection_for_select(@projects, 'id', 'name', @target_project.id), |
|
11 | options_from_collection_for_select(@allowed_projects, 'id', 'name', @target_project.id), | |
20 |
:onchange => remote_function(:url => {:action => 'move |
|
12 | :onchange => remote_function(:url => {:action => 'move' , :id => @project}, | |
21 | :method => :get, |
|
13 | :method => :get, | |
22 | :update => 'content', |
|
14 | :update => 'content', | |
23 | :with => "Form.serialize('move_form')") %></p> |
|
15 | :with => "Form.serialize('move_form')") %></p> | |
@@ -25,5 +17,6 | |||||
25 | <p><label for="new_tracker_id"><%=l(:field_tracker)%> :</label> |
|
17 | <p><label for="new_tracker_id"><%=l(:field_tracker)%> :</label> | |
26 | <%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p> |
|
18 | <%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p> | |
27 | </div> |
|
19 | </div> | |
|
20 | ||||
28 | <%= submit_tag l(:button_move) %> |
|
21 | <%= submit_tag l(:button_move) %> | |
29 | <% end %> |
|
22 | <% end %> |
@@ -3,7 +3,7 | |||||
3 | <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %> |
|
3 | <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %> | |
4 | <%= watcher_tag(@issue, User.current) %> |
|
4 | <%= watcher_tag(@issue, User.current) %> | |
5 | <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %> |
|
5 | <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %> | |
6 |
<%= link_to_if_authorized l(:button_move), {:controller => ' |
|
6 | <%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %> | |
7 | <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> |
|
7 | <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> | |
8 | </div> |
|
8 | </div> | |
9 |
|
9 |
@@ -37,6 +37,6 | |||||
37 | <% end %> |
|
37 | <% end %> | |
38 |
|
38 | |||
39 | <div id="context-menu" style="display: none;"></div> |
|
39 | <div id="context-menu" style="display: none;"></div> | |
40 | <%= javascript_tag 'new ContextMenu({})' %> |
|
40 | <%= javascript_tag "new ContextMenu('#{url_for(:controller => 'issues', :action => 'context_menu')}')" %> | |
41 |
|
41 | |||
42 | <% html_title(l(:label_my_page)) -%> |
|
42 | <% html_title(l(:label_my_page)) -%> |
@@ -568,3 +568,4 label_associated_revisions: Асоциирани ревизии | |||||
568 | setting_user_format: Потребителски формат |
|
568 | setting_user_format: Потребителски формат | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 enumeration_doc_categories: Dokumentenkategorien | |||||
568 | enumeration_activities: Aktivitäten (Zeiterfassung) |
|
568 | enumeration_activities: Aktivitäten (Zeiterfassung) | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -542,6 +542,7 text_user_mail_option: "For unselected projects, you will only receive notificat | |||||
542 | text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." |
|
542 | text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." | |
543 | text_load_default_configuration: Load the default configuration |
|
543 | text_load_default_configuration: Load the default configuration | |
544 | text_status_changed_by_changeset: Applied in changeset %s. |
|
544 | text_status_changed_by_changeset: Applied in changeset %s. | |
|
545 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' | |||
545 |
|
546 | |||
546 | default_role_manager: Manager |
|
547 | default_role_manager: Manager | |
547 | default_role_developper: Developer |
|
548 | default_role_developper: Developer |
@@ -571,3 +571,4 label_associated_revisions: Associated revisions | |||||
571 | setting_user_format: Users display format |
|
571 | setting_user_format: Users display format | |
572 | text_status_changed_by_changeset: Applied in changeset %s. |
|
572 | text_status_changed_by_changeset: Applied in changeset %s. | |
573 | label_more: More |
|
573 | label_more: More | |
|
574 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -572,3 +572,4 label_associated_revisions: Liittyvät versiot | |||||
572 | setting_user_format: Users display format |
|
572 | setting_user_format: Users display format | |
573 | text_status_changed_by_changeset: Applied in changeset %s. |
|
573 | text_status_changed_by_changeset: Applied in changeset %s. | |
574 | label_more: More |
|
574 | label_more: More | |
|
575 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -543,6 +543,7 text_user_mail_option: "Pour les projets non sélectionnés, vous recevrez seule | |||||
543 | text_no_configuration_data: "Les rôles, trackers, statuts et le workflow ne sont pas encore paramétrés.\nIl est vivement recommandé de charger le paramétrage par defaut. Vous pourrez le modifier une fois chargé." |
|
543 | text_no_configuration_data: "Les rôles, trackers, statuts et le workflow ne sont pas encore paramétrés.\nIl est vivement recommandé de charger le paramétrage par defaut. Vous pourrez le modifier une fois chargé." | |
544 | text_load_default_configuration: Charger le paramétrage par défaut |
|
544 | text_load_default_configuration: Charger le paramétrage par défaut | |
545 | text_status_changed_by_changeset: Appliqué par commit %s. |
|
545 | text_status_changed_by_changeset: Appliqué par commit %s. | |
|
546 | text_issues_destroy_confirmation: 'Etes-vous sûr de vouloir supprimer le(s) demandes(s) selectionnée(s) ?' | |||
546 |
|
547 | |||
547 | default_role_manager: Manager |
|
548 | default_role_manager: Manager | |
548 | default_role_developper: Développeur |
|
549 | default_role_developper: Développeur |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -569,3 +569,4 label_associated_revisions: Associated revisions | |||||
569 | setting_user_format: Users display format |
|
569 | setting_user_format: Users display format | |
570 | text_status_changed_by_changeset: Applied in changeset %s. |
|
570 | text_status_changed_by_changeset: Applied in changeset %s. | |
571 | label_more: More |
|
571 | label_more: More | |
|
572 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -569,3 +569,4 label_associated_revisions: susijusios revizijos | |||||
569 | setting_user_format: Vartotojo atvaizdavimo formatas |
|
569 | setting_user_format: Vartotojo atvaizdavimo formatas | |
570 | text_status_changed_by_changeset: Applied in changeset %s. |
|
570 | text_status_changed_by_changeset: Applied in changeset %s. | |
571 | label_more: More |
|
571 | label_more: More | |
|
572 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -569,3 +569,4 label_associated_revisions: Associated revisions | |||||
569 | setting_user_format: Users display format |
|
569 | setting_user_format: Users display format | |
570 | text_status_changed_by_changeset: Applied in changeset %s. |
|
570 | text_status_changed_by_changeset: Applied in changeset %s. | |
571 | label_more: More |
|
571 | label_more: More | |
|
572 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 label_associated_revisions: Associated revisions | |||||
568 | setting_user_format: Users display format |
|
568 | setting_user_format: Users display format | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -569,3 +569,4 enumeration_doc_categories: Категории документов | |||||
569 | enumeration_activities: Действия (учет времени) |
|
569 | enumeration_activities: Действия (учет времени) | |
570 | text_status_changed_by_changeset: Applied in changeset %s. |
|
570 | text_status_changed_by_changeset: Applied in changeset %s. | |
571 | label_more: More |
|
571 | label_more: More | |
|
572 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -569,3 +569,4 label_associated_revisions: Associated revisions | |||||
569 | setting_user_format: Users display format |
|
569 | setting_user_format: Users display format | |
570 | text_status_changed_by_changeset: Applied in changeset %s. |
|
570 | text_status_changed_by_changeset: Applied in changeset %s. | |
571 | label_more: More |
|
571 | label_more: More | |
|
572 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -569,3 +569,4 label_associated_revisions: Associated revisions | |||||
569 | setting_user_format: Users display format |
|
569 | setting_user_format: Users display format | |
570 | text_status_changed_by_changeset: Applied in changeset %s. |
|
570 | text_status_changed_by_changeset: Applied in changeset %s. | |
571 | label_more: More |
|
571 | label_more: More | |
|
572 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -568,3 +568,4 enumeration_doc_categories: 文件分類 | |||||
568 | enumeration_activities: 活動 (time tracking) |
|
568 | enumeration_activities: 活動 (time tracking) | |
569 | text_status_changed_by_changeset: Applied in changeset %s. |
|
569 | text_status_changed_by_changeset: Applied in changeset %s. | |
570 | label_more: More |
|
570 | label_more: More | |
|
571 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -571,3 +571,4 label_associated_revisions: 相关的版本 | |||||
571 | setting_user_format: 用户显示格式 |
|
571 | setting_user_format: 用户显示格式 | |
572 | text_status_changed_by_changeset: Applied in changeset %s. |
|
572 | text_status_changed_by_changeset: Applied in changeset %s. | |
573 | label_more: More |
|
573 | label_more: More | |
|
574 | text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' |
@@ -31,11 +31,10 Redmine::AccessControl.map do |map| | |||||
31 | :queries => :index, |
|
31 | :queries => :index, | |
32 | :reports => :issue_report}, :public => true |
|
32 | :reports => :issue_report}, :public => true | |
33 | map.permission :add_issues, {:issues => :new} |
|
33 | map.permission :add_issues, {:issues => :new} | |
34 |
map.permission :edit_issues, {: |
|
34 | map.permission :edit_issues, {:issues => [:edit, :bulk_edit, :destroy_attachment]} | |
35 | :issues => [:edit, :destroy_attachment]} |
|
|||
36 | map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]} |
|
35 | map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]} | |
37 | map.permission :add_issue_notes, {:issues => :edit} |
|
36 | map.permission :add_issue_notes, {:issues => :edit} | |
38 |
map.permission :move_issues, {: |
|
37 | map.permission :move_issues, {:issues => :move}, :require => :loggedin | |
39 | map.permission :delete_issues, {:issues => :destroy}, :require => :member |
|
38 | map.permission :delete_issues, {:issues => :destroy}, :require => :member | |
40 | # Queries |
|
39 | # Queries | |
41 | map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member |
|
40 | map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member |
@@ -1,3 +1,6 | |||||
|
1 | /* redMine - project management software | |||
|
2 | Copyright (C) 2006-2008 Jean-Philippe Lang */ | |||
|
3 | ||||
1 | function checkAll (id, checked) { |
|
4 | function checkAll (id, checked) { | |
2 | var el = document.getElementById(id); |
|
5 | var el = document.getElementById(id); | |
3 | for (var i = 0; i < el.elements.length; i++) { |
|
6 | for (var i = 0; i < el.elements.length; i++) { | |
@@ -49,16 +52,6 function promptToRemote(text, param, url) { | |||||
49 | } |
|
52 | } | |
50 | } |
|
53 | } | |
51 |
|
54 | |||
52 | /* checks that at least one checkbox is checked (used when submitting bulk edit form) */ |
|
|||
53 | function checkBulkEdit(form) { |
|
|||
54 | for (var i = 0; i < form.elements.length; i++) { |
|
|||
55 | if (form.elements[i].checked) { |
|
|||
56 | return true; |
|
|||
57 | } |
|
|||
58 | } |
|
|||
59 | return false; |
|
|||
60 | } |
|
|||
61 |
|
||||
62 | function collapseScmEntry(id) { |
|
55 | function collapseScmEntry(id) { | |
63 | var els = document.getElementsByClassName(id, 'browser'); |
|
56 | var els = document.getElementsByClassName(id, 'browser'); | |
64 | for (var i = 0; i < els.length; i++) { |
|
57 | for (var i = 0; i < els.length; i++) { |
@@ -1,47 +1,161 | |||||
|
1 | /* redMine - project management software | |||
|
2 | Copyright (C) 2006-2008 Jean-Philippe Lang */ | |||
|
3 | ||||
|
4 | var observingContextMenuClick; | |||
|
5 | ||||
1 | ContextMenu = Class.create(); |
|
6 | ContextMenu = Class.create(); | |
2 | ContextMenu.prototype = { |
|
7 | ContextMenu.prototype = { | |
3 |
initialize: function ( |
|
8 | initialize: function (url) { | |
4 | this.options = Object.extend({selector: '.hascontextmenu'}, options || { }); |
|
9 | this.url = url; | |
5 |
|
10 | |||
6 | Event.observe(document, 'click', function(e){ |
|
11 | // prevent selection when using Ctrl/Shit key | |
7 | var t = Event.findElement(e, 'a'); |
|
12 | var tables = $$('table.issues'); | |
8 | if ((t != document) && (Element.hasClassName(t, 'disabled') || Element.hasClassName(t, 'submenu'))) { |
|
13 | for (i=0; i<tables.length; i++) { | |
9 | Event.stop(e); |
|
14 | tables[i].onselectstart = function () { return false; } // ie | |
10 | } else { |
|
15 | tables[i].onmousedown = function () { return false; } // mozilla | |
11 | $('context-menu').hide(); |
|
16 | } | |
12 | if (this.selection) { |
|
17 | ||
13 | this.selection.removeClassName('context-menu-selection'); |
|
18 | if (!observingContextMenuClick) { | |
14 | } |
|
19 | Event.observe(document, 'click', this.Click.bindAsEventListener(this)); | |
15 | } |
|
20 | Event.observe(document, (window.opera ? 'click' : 'contextmenu'), this.RightClick.bindAsEventListener(this)); | |
16 |
|
21 | observingContextMenuClick = true; | ||
17 | }.bind(this)); |
|
22 | } | |
18 |
|
|
23 | ||
19 | $$(this.options.selector).invoke('observe', (window.opera ? 'click' : 'contextmenu'), function(e){ |
|
24 | this.unselectAll(); | |
20 | if (window.opera && !e.ctrlKey) { |
|
25 | this.lastSelected = null; | |
21 | return; |
|
|||
22 | } |
|
|||
23 | this.show(e); |
|
|||
24 | }.bind(this)); |
|
|||
25 |
|
||||
26 | }, |
|
26 | }, | |
27 | show: function(e) { |
|
27 | ||
|
28 | RightClick: function(e) { | |||
|
29 | this.hideMenu(); | |||
|
30 | // do not show the context menu on links | |||
|
31 | if (Event.findElement(e, 'a') != document) { return; } | |||
|
32 | // right-click simulated by Alt+Click with Opera | |||
|
33 | if (window.opera && !e.altKey) { return; } | |||
|
34 | var tr = Event.findElement(e, 'tr'); | |||
|
35 | if ((tr == document) || !tr.hasClassName('hascontextmenu')) { return; } | |||
28 | Event.stop(e); |
|
36 | Event.stop(e); | |
29 | Element.hide('context-menu'); |
|
37 | if (!this.isSelected(tr)) { | |
30 |
|
|
38 | this.unselectAll(); | |
31 | this.selection.removeClassName('context-menu-selection'); |
|
39 | this.addSelection(tr); | |
|
40 | this.lastSelected = tr; | |||
32 | } |
|
41 | } | |
|
42 | this.showMenu(e); | |||
|
43 | }, | |||
|
44 | ||||
|
45 | Click: function(e) { | |||
|
46 | this.hideMenu(); | |||
|
47 | if (Event.findElement(e, 'a') != document) { return; } | |||
|
48 | if (window.opera && e.altKey) { return; } | |||
|
49 | if (Event.isLeftClick(e) || (navigator.appVersion.match(/\bMSIE\b/))) { | |||
|
50 | var tr = Event.findElement(e, 'tr'); | |||
|
51 | if (tr!=document && tr.hasClassName('hascontextmenu')) { | |||
|
52 | // a row was clicked, check if the click was on checkbox | |||
|
53 | var box = Event.findElement(e, 'input'); | |||
|
54 | if (box!=document) { | |||
|
55 | // a checkbox may be clicked | |||
|
56 | if (box.checked) { | |||
|
57 | tr.addClassName('context-menu-selection'); | |||
|
58 | } else { | |||
|
59 | tr.removeClassName('context-menu-selection'); | |||
|
60 | } | |||
|
61 | } else { | |||
|
62 | if (e.ctrlKey) { | |||
|
63 | this.toggleSelection(tr); | |||
|
64 | } else if (e.shiftKey) { | |||
|
65 | if (this.lastSelected != null) { | |||
|
66 | var toggling = false; | |||
|
67 | var rows = $$('.hascontextmenu'); | |||
|
68 | for (i=0; i<rows.length; i++) { | |||
|
69 | if (toggling || rows[i]==tr) { | |||
|
70 | this.addSelection(rows[i]); | |||
|
71 | } | |||
|
72 | if (rows[i]==tr || rows[i]==this.lastSelected) { | |||
|
73 | toggling = !toggling; | |||
|
74 | } | |||
|
75 | } | |||
|
76 | } else { | |||
|
77 | this.addSelection(tr); | |||
|
78 | } | |||
|
79 | } else { | |||
|
80 | this.unselectAll(); | |||
|
81 | this.addSelection(tr); | |||
|
82 | } | |||
|
83 | this.lastSelected = tr; | |||
|
84 | } | |||
|
85 | } else { | |||
|
86 | // click is outside the rows | |||
|
87 | var t = Event.findElement(e, 'a'); | |||
|
88 | if ((t != document) && (Element.hasClassName(t, 'disabled') || Element.hasClassName(t, 'submenu'))) { | |||
|
89 | Event.stop(e); | |||
|
90 | } | |||
|
91 | } | |||
|
92 | } | |||
|
93 | }, | |||
|
94 | ||||
|
95 | showMenu: function(e) { | |||
33 | $('context-menu').style['left'] = (Event.pointerX(e) + 'px'); |
|
96 | $('context-menu').style['left'] = (Event.pointerX(e) + 'px'); | |
34 | $('context-menu').style['top'] = (Event.pointerY(e) + 'px'); |
|
97 | $('context-menu').style['top'] = (Event.pointerY(e) + 'px'); | |
35 | Element.update('context-menu', ''); |
|
98 | Element.update('context-menu', ''); | |
|
99 | new Ajax.Updater({success:'context-menu'}, this.url, | |||
|
100 | {asynchronous:true, | |||
|
101 | evalScripts:true, | |||
|
102 | parameters:Form.serialize(Event.findElement(e, 'form')), | |||
|
103 | onComplete:function(request){ | |||
|
104 | Effect.Appear('context-menu', {duration: 0.20}); | |||
|
105 | if (window.parseStylesheets) { window.parseStylesheets(); } // IE | |||
|
106 | }}) | |||
|
107 | }, | |||
|
108 | ||||
|
109 | hideMenu: function() { | |||
|
110 | Element.hide('context-menu'); | |||
|
111 | }, | |||
|
112 | ||||
|
113 | addSelection: function(tr) { | |||
|
114 | tr.addClassName('context-menu-selection'); | |||
|
115 | this.checkSelectionBox(tr, true); | |||
|
116 | }, | |||
|
117 | ||||
|
118 | toggleSelection: function(tr) { | |||
|
119 | if (this.isSelected(tr)) { | |||
|
120 | this.removeSelection(tr); | |||
|
121 | } else { | |||
|
122 | this.addSelection(tr); | |||
|
123 | } | |||
|
124 | }, | |||
|
125 | ||||
|
126 | removeSelection: function(tr) { | |||
|
127 | tr.removeClassName('context-menu-selection'); | |||
|
128 | this.checkSelectionBox(tr, false); | |||
|
129 | }, | |||
|
130 | ||||
|
131 | unselectAll: function() { | |||
|
132 | var rows = $$('.hascontextmenu'); | |||
|
133 | for (i=0; i<rows.length; i++) { | |||
|
134 | this.removeSelection(rows[i]); | |||
|
135 | } | |||
|
136 | }, | |||
|
137 | ||||
|
138 | checkSelectionBox: function(tr, checked) { | |||
|
139 | var inputs = Element.getElementsBySelector(tr, 'input'); | |||
|
140 | if (inputs.length > 0) { inputs[0].checked = checked; } | |||
|
141 | }, | |||
|
142 | ||||
|
143 | isSelected: function(tr) { | |||
|
144 | return Element.hasClassName(tr, 'context-menu-selection'); | |||
|
145 | } | |||
|
146 | } | |||
36 |
|
147 | |||
37 | var tr = Event.findElement(e, 'tr'); |
|
148 | function toggleIssuesSelection(el) { | |
38 | tr.addClassName('context-menu-selection'); |
|
149 | var boxes = el.getElementsBySelector('input[type=checkbox]'); | |
39 | this.selection = tr; |
|
150 | var all_checked = true; | |
40 | var id = tr.id.substring(6, tr.id.length); |
|
151 | for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } } | |
41 | /* TODO: do not hard code path */ |
|
152 | for (i = 0; i < boxes.length; i++) { | |
42 | new Ajax.Updater({success:'context-menu'}, '../../issues/context_menu/' + id, {asynchronous:true, evalScripts:true, onComplete:function(request){ |
|
153 | if (all_checked) { | |
43 | Effect.Appear('context-menu', {duration: 0.20}); |
|
154 | boxes[i].checked = false; | |
44 | if (window.parseStylesheets) { window.parseStylesheets(); } |
|
155 | boxes[i].up('tr').removeClassName('context-menu-selection'); | |
45 | }}) |
|
156 | } else if (boxes[i].checked == false) { | |
|
157 | boxes[i].checked = true; | |||
|
158 | boxes[i].up('tr').addClassName('context-menu-selection'); | |||
|
159 | } | |||
46 | } |
|
160 | } | |
47 | } |
|
161 | } |
@@ -197,6 +197,28 class IssuesControllerTest < Test::Unit::TestCase | |||||
197 | assert_not_nil assigns(:issue) |
|
197 | assert_not_nil assigns(:issue) | |
198 | assert_equal Issue.find(1), assigns(:issue) |
|
198 | assert_equal Issue.find(1), assigns(:issue) | |
199 | end |
|
199 | end | |
|
200 | ||||
|
201 | def test_get_edit_with_params | |||
|
202 | @request.session[:user_id] = 2 | |||
|
203 | get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 } | |||
|
204 | assert_response :success | |||
|
205 | assert_template 'edit' | |||
|
206 | ||||
|
207 | issue = assigns(:issue) | |||
|
208 | assert_not_nil issue | |||
|
209 | ||||
|
210 | assert_equal 5, issue.status_id | |||
|
211 | assert_tag :select, :attributes => { :name => 'issue[status_id]' }, | |||
|
212 | :child => { :tag => 'option', | |||
|
213 | :content => 'Closed', | |||
|
214 | :attributes => { :selected => 'selected' } } | |||
|
215 | ||||
|
216 | assert_equal 7, issue.priority_id | |||
|
217 | assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, | |||
|
218 | :child => { :tag => 'option', | |||
|
219 | :content => 'Urgent', | |||
|
220 | :attributes => { :selected => 'selected' } } | |||
|
221 | end | |||
200 |
|
222 | |||
201 | def test_post_edit |
|
223 | def test_post_edit | |
202 | @request.session[:user_id] = 2 |
|
224 | @request.session[:user_id] = 2 | |
@@ -305,12 +327,105 class IssuesControllerTest < Test::Unit::TestCase | |||||
305 | # No email should be sent |
|
327 | # No email should be sent | |
306 | assert ActionMailer::Base.deliveries.empty? |
|
328 | assert ActionMailer::Base.deliveries.empty? | |
307 | end |
|
329 | end | |
|
330 | ||||
|
331 | def test_bulk_edit | |||
|
332 | @request.session[:user_id] = 2 | |||
|
333 | # update issues priority | |||
|
334 | post :bulk_edit, :ids => [1, 2], :priority_id => 7, :notes => 'Bulk editing', :assigned_to_id => '' | |||
|
335 | assert_response 302 | |||
|
336 | # check that the issues were updated | |||
|
337 | assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} | |||
|
338 | assert_equal 'Bulk editing', Issue.find(1).journals.find(:first, :order => 'created_on DESC').notes | |||
|
339 | end | |||
|
340 | ||||
|
341 | def test_move_one_issue_to_another_project | |||
|
342 | @request.session[:user_id] = 1 | |||
|
343 | post :move, :id => 1, :new_project_id => 2 | |||
|
344 | assert_redirected_to 'projects/ecookbook/issues' | |||
|
345 | assert_equal 2, Issue.find(1).project_id | |||
|
346 | end | |||
|
347 | ||||
|
348 | def test_bulk_move_to_another_project | |||
|
349 | @request.session[:user_id] = 1 | |||
|
350 | post :move, :ids => [1, 2], :new_project_id => 2 | |||
|
351 | assert_redirected_to 'projects/ecookbook/issues' | |||
|
352 | # Issues moved to project 2 | |||
|
353 | assert_equal 2, Issue.find(1).project_id | |||
|
354 | assert_equal 2, Issue.find(2).project_id | |||
|
355 | # No tracker change | |||
|
356 | assert_equal 1, Issue.find(1).tracker_id | |||
|
357 | assert_equal 2, Issue.find(2).tracker_id | |||
|
358 | end | |||
|
359 | ||||
|
360 | def test_bulk_move_to_another_tracker | |||
|
361 | @request.session[:user_id] = 1 | |||
|
362 | post :move, :ids => [1, 2], :new_tracker_id => 2 | |||
|
363 | assert_redirected_to 'projects/ecookbook/issues' | |||
|
364 | assert_equal 2, Issue.find(1).tracker_id | |||
|
365 | assert_equal 2, Issue.find(2).tracker_id | |||
|
366 | end | |||
308 |
|
367 | |||
309 | def test_context_menu |
|
368 | def test_context_menu_one_issue | |
|
369 | @request.session[:user_id] = 2 | |||
|
370 | get :context_menu, :ids => [1] | |||
|
371 | assert_response :success | |||
|
372 | assert_template 'context_menu' | |||
|
373 | assert_tag :tag => 'a', :content => 'Edit', | |||
|
374 | :attributes => { :href => '/issues/edit/1', | |||
|
375 | :class => 'icon-edit' } | |||
|
376 | assert_tag :tag => 'a', :content => 'Closed', | |||
|
377 | :attributes => { :href => '/issues/edit/1?issue%5Bstatus_id%5D=5', | |||
|
378 | :class => '' } | |||
|
379 | assert_tag :tag => 'a', :content => 'Immediate', | |||
|
380 | :attributes => { :href => '/issues/edit/1?issue%5Bpriority_id%5D=8', | |||
|
381 | :class => '' } | |||
|
382 | assert_tag :tag => 'a', :content => 'Dave Lopper', | |||
|
383 | :attributes => { :href => '/issues/edit/1?issue%5Bassigned_to_id%5D=3', | |||
|
384 | :class => '' } | |||
|
385 | assert_tag :tag => 'a', :content => 'Copy', | |||
|
386 | :attributes => { :href => '/projects/ecookbook/issues/new?copy_from=1', | |||
|
387 | :class => 'icon-copy' } | |||
|
388 | assert_tag :tag => 'a', :content => 'Move', | |||
|
389 | :attributes => { :href => '/issues/move?ids%5B%5D=1', | |||
|
390 | :class => 'icon-move' } | |||
|
391 | assert_tag :tag => 'a', :content => 'Delete', | |||
|
392 | :attributes => { :href => '/issues/destroy?ids%5B%5D=1', | |||
|
393 | :class => 'icon-del' } | |||
|
394 | end | |||
|
395 | ||||
|
396 | def test_context_menu_one_issue_by_anonymous | |||
|
397 | get :context_menu, :ids => [1] | |||
|
398 | assert_response :success | |||
|
399 | assert_template 'context_menu' | |||
|
400 | assert_tag :tag => 'a', :content => 'Delete', | |||
|
401 | :attributes => { :href => '#', | |||
|
402 | :class => 'icon-del disabled' } | |||
|
403 | end | |||
|
404 | ||||
|
405 | def test_context_menu_multiple_issues_of_same_project | |||
|
406 | @request.session[:user_id] = 2 | |||
|
407 | get :context_menu, :ids => [1, 2] | |||
|
408 | assert_response :success | |||
|
409 | assert_template 'context_menu' | |||
|
410 | assert_tag :tag => 'a', :content => 'Edit', | |||
|
411 | :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2', | |||
|
412 | :class => 'icon-edit' } | |||
|
413 | assert_tag :tag => 'a', :content => 'Move', | |||
|
414 | :attributes => { :href => '/issues/move?ids%5B%5D=1&ids%5B%5D=2', | |||
|
415 | :class => 'icon-move' } | |||
|
416 | assert_tag :tag => 'a', :content => 'Delete', | |||
|
417 | :attributes => { :href => '/issues/destroy?ids%5B%5D=1&ids%5B%5D=2', | |||
|
418 | :class => 'icon-del' } | |||
|
419 | end | |||
|
420 | ||||
|
421 | def test_context_menu_multiple_issues_of_different_project | |||
310 | @request.session[:user_id] = 2 |
|
422 | @request.session[:user_id] = 2 | |
311 | get :context_menu, :id => 1 |
|
423 | get :context_menu, :ids => [1, 2, 4] | |
312 | assert_response :success |
|
424 | assert_response :success | |
313 | assert_template 'context_menu' |
|
425 | assert_template 'context_menu' | |
|
426 | assert_tag :tag => 'a', :content => 'Delete', | |||
|
427 | :attributes => { :href => '#', | |||
|
428 | :class => 'icon-del disabled' } | |||
314 | end |
|
429 | end | |
315 |
|
430 | |||
316 | def test_destroy |
|
431 | def test_destroy |
@@ -93,32 +93,6 class ProjectsControllerTest < Test::Unit::TestCase | |||||
93 | assert_nil Project.find_by_id(1) |
|
93 | assert_nil Project.find_by_id(1) | |
94 | end |
|
94 | end | |
95 |
|
95 | |||
96 | def test_bulk_edit_issues |
|
|||
97 | @request.session[:user_id] = 2 |
|
|||
98 | # update issues priority |
|
|||
99 | post :bulk_edit_issues, :id => 1, :issue_ids => [1, 2], :priority_id => 7, :notes => 'Bulk editing', :assigned_to_id => '' |
|
|||
100 | assert_response 302 |
|
|||
101 | # check that the issues were updated |
|
|||
102 | assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} |
|
|||
103 | assert_equal 'Bulk editing', Issue.find(1).journals.find(:first, :order => 'created_on DESC').notes |
|
|||
104 | end |
|
|||
105 |
|
||||
106 | def test_move_issues_to_another_project |
|
|||
107 | @request.session[:user_id] = 1 |
|
|||
108 | post :move_issues, :id => 1, :issue_ids => [1, 2], :new_project_id => 2 |
|
|||
109 | assert_redirected_to 'projects/ecookbook/issues' |
|
|||
110 | assert_equal 2, Issue.find(1).project_id |
|
|||
111 | assert_equal 2, Issue.find(2).project_id |
|
|||
112 | end |
|
|||
113 |
|
||||
114 | def test_move_issues_to_another_tracker |
|
|||
115 | @request.session[:user_id] = 1 |
|
|||
116 | post :move_issues, :id => 1, :issue_ids => [1, 2], :new_tracker_id => 2 |
|
|||
117 | assert_redirected_to 'projects/ecookbook/issues' |
|
|||
118 | assert_equal 2, Issue.find(1).tracker_id |
|
|||
119 | assert_equal 2, Issue.find(2).tracker_id |
|
|||
120 | end |
|
|||
121 |
|
||||
122 | def test_list_files |
|
96 | def test_list_files | |
123 | get :list_files, :id => 1 |
|
97 | get :list_files, :id => 1 | |
124 | assert_response :success |
|
98 | assert_response :success |
General Comments 0
You need to be logged in to leave comments.
Login now