@@ -1,140 +1,140 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2014 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | class WorkflowsController < ApplicationController |
|
19 | 19 | layout 'admin' |
|
20 | 20 | |
|
21 | 21 | before_filter :require_admin |
|
22 | 22 | |
|
23 | 23 | def index |
|
24 | 24 | @workflow_counts = WorkflowTransition.count_by_tracker_and_role |
|
25 | 25 | end |
|
26 | 26 | |
|
27 | 27 | def edit |
|
28 | 28 | find_trackers_roles_and_statuses_for_edit |
|
29 | 29 | |
|
30 | 30 | if request.post? && @roles && @trackers && params[:transitions] |
|
31 | 31 | transitions = params[:transitions].deep_dup |
|
32 | 32 | transitions.each do |old_status_id, transitions_by_new_status| |
|
33 | 33 | transitions_by_new_status.each do |new_status_id, transition_by_rule| |
|
34 | 34 | transition_by_rule.reject! {|rule, transition| transition == 'no_change'} |
|
35 | 35 | end |
|
36 | 36 | end |
|
37 | 37 | WorkflowTransition.replace_transitions(@trackers, @roles, transitions) |
|
38 | 38 | flash[:notice] = l(:notice_successful_update) |
|
39 | 39 | redirect_to_referer_or workflows_edit_path |
|
40 | 40 | return |
|
41 | 41 | end |
|
42 | 42 | |
|
43 | 43 | if @trackers && @roles && @statuses.any? |
|
44 | 44 | workflows = WorkflowTransition.where(:role_id => @roles.map(&:id), :tracker_id => @trackers.map(&:id)) |
|
45 | 45 | @workflows = {} |
|
46 | 46 | @workflows['always'] = workflows.select {|w| !w.author && !w.assignee} |
|
47 | 47 | @workflows['author'] = workflows.select {|w| w.author} |
|
48 | 48 | @workflows['assignee'] = workflows.select {|w| w.assignee} |
|
49 | 49 | end |
|
50 | 50 | end |
|
51 | 51 | |
|
52 | 52 | def permissions |
|
53 | 53 | find_trackers_roles_and_statuses_for_edit |
|
54 | 54 | |
|
55 | 55 | if request.post? && @roles && @trackers && params[:permissions] |
|
56 | 56 | permissions = params[:permissions].deep_dup |
|
57 | 57 | permissions.each { |field, rule_by_status_id| |
|
58 | 58 | rule_by_status_id.reject! {|status_id, rule| rule == 'no_change'} |
|
59 | 59 | } |
|
60 | 60 | WorkflowPermission.replace_permissions(@trackers, @roles, permissions) |
|
61 | 61 | flash[:notice] = l(:notice_successful_update) |
|
62 | 62 | redirect_to_referer_or workflows_permissions_path |
|
63 | 63 | return |
|
64 | 64 | end |
|
65 | 65 | |
|
66 | 66 | if @roles && @trackers |
|
67 | 67 | @fields = (Tracker::CORE_FIELDS_ALL - @trackers.map(&:disabled_core_fields).reduce(:&)).map {|field| [field, l("field_"+field.sub(/_id$/, ''))]} |
|
68 | 68 | @custom_fields = @trackers.map(&:custom_fields).flatten.uniq.sort |
|
69 | 69 | @permissions = WorkflowPermission.rules_by_status_id(@trackers, @roles) |
|
70 | 70 | @statuses.each {|status| @permissions[status.id] ||= {}} |
|
71 | 71 | end |
|
72 | 72 | end |
|
73 | 73 | |
|
74 | 74 | def copy |
|
75 | @roles = Role.sorted | |
|
75 | @roles = Role.sorted.select(&:consider_workflow?) | |
|
76 | 76 | @trackers = Tracker.sorted |
|
77 | 77 | |
|
78 | 78 | if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' |
|
79 | 79 | @source_tracker = nil |
|
80 | 80 | else |
|
81 | 81 | @source_tracker = Tracker.find_by_id(params[:source_tracker_id].to_i) |
|
82 | 82 | end |
|
83 | 83 | if params[:source_role_id].blank? || params[:source_role_id] == 'any' |
|
84 | 84 | @source_role = nil |
|
85 | 85 | else |
|
86 | 86 | @source_role = Role.find_by_id(params[:source_role_id].to_i) |
|
87 | 87 | end |
|
88 | 88 | @target_trackers = params[:target_tracker_ids].blank? ? |
|
89 | 89 | nil : Tracker.where(:id => params[:target_tracker_ids]).to_a |
|
90 | 90 | @target_roles = params[:target_role_ids].blank? ? |
|
91 | 91 | nil : Role.where(:id => params[:target_role_ids]).to_a |
|
92 | 92 | if request.post? |
|
93 | 93 | if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) |
|
94 | 94 | flash.now[:error] = l(:error_workflow_copy_source) |
|
95 | 95 | elsif @target_trackers.blank? || @target_roles.blank? |
|
96 | 96 | flash.now[:error] = l(:error_workflow_copy_target) |
|
97 | 97 | else |
|
98 | 98 | WorkflowRule.copy(@source_tracker, @source_role, @target_trackers, @target_roles) |
|
99 | 99 | flash[:notice] = l(:notice_successful_update) |
|
100 | 100 | redirect_to workflows_copy_path(:source_tracker_id => @source_tracker, :source_role_id => @source_role) |
|
101 | 101 | end |
|
102 | 102 | end |
|
103 | 103 | end |
|
104 | 104 | |
|
105 | 105 | private |
|
106 | 106 | |
|
107 | 107 | def find_trackers_roles_and_statuses_for_edit |
|
108 | 108 | find_roles |
|
109 | 109 | find_trackers |
|
110 | 110 | find_statuses |
|
111 | 111 | end |
|
112 | 112 | |
|
113 | 113 | def find_roles |
|
114 | 114 | ids = Array.wrap(params[:role_id]) |
|
115 | 115 | if ids == ['all'] |
|
116 | 116 | @roles = Role.sorted.to_a |
|
117 | 117 | elsif ids.present? |
|
118 | 118 | @roles = Role.where(:id => ids).to_a |
|
119 | 119 | end |
|
120 | 120 | @roles = nil if @roles.blank? |
|
121 | 121 | end |
|
122 | 122 | |
|
123 | 123 | def find_trackers |
|
124 | 124 | ids = Array.wrap(params[:tracker_id]) |
|
125 | 125 | if ids == ['all'] |
|
126 | 126 | @trackers = Tracker.sorted.to_a |
|
127 | 127 | elsif ids.present? |
|
128 | 128 | @trackers = Tracker.where(:id => ids).to_a |
|
129 | 129 | end |
|
130 | 130 | @trackers = nil if @trackers.blank? |
|
131 | 131 | end |
|
132 | 132 | |
|
133 | 133 | def find_statuses |
|
134 | 134 | @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) |
|
135 | 135 | if @trackers && @used_statuses_only |
|
136 | 136 | @statuses = @trackers.map(&:issue_statuses).flatten.uniq.sort.presence |
|
137 | 137 | end |
|
138 | 138 | @statuses ||= IssueStatus.sorted.to_a |
|
139 | 139 | end |
|
140 | 140 | end |
@@ -1,74 +1,74 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2014 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | class WorkflowRule < ActiveRecord::Base |
|
19 | 19 | self.table_name = "#{table_name_prefix}workflows#{table_name_suffix}" |
|
20 | 20 | |
|
21 | 21 | belongs_to :role |
|
22 | 22 | belongs_to :tracker |
|
23 | 23 | belongs_to :old_status, :class_name => 'IssueStatus' |
|
24 | 24 | belongs_to :new_status, :class_name => 'IssueStatus' |
|
25 | 25 | |
|
26 | 26 | validates_presence_of :role, :tracker, :old_status |
|
27 | 27 | attr_protected :id |
|
28 | 28 | |
|
29 | 29 | # Copies workflows from source to targets |
|
30 | 30 | def self.copy(source_tracker, source_role, target_trackers, target_roles) |
|
31 | 31 | unless source_tracker.is_a?(Tracker) || source_role.is_a?(Role) |
|
32 | 32 | raise ArgumentError.new("source_tracker or source_role must be specified") |
|
33 | 33 | end |
|
34 | 34 | |
|
35 | 35 | target_trackers = [target_trackers].flatten.compact |
|
36 | 36 | target_roles = [target_roles].flatten.compact |
|
37 | 37 | |
|
38 | 38 | target_trackers = Tracker.sorted.to_a if target_trackers.empty? |
|
39 | target_roles = Role.all if target_roles.empty? | |
|
39 | target_roles = Role.all.select(&:consider_workflow?) if target_roles.empty? | |
|
40 | 40 | |
|
41 | 41 | target_trackers.each do |target_tracker| |
|
42 | 42 | target_roles.each do |target_role| |
|
43 | 43 | copy_one(source_tracker || target_tracker, |
|
44 | 44 | source_role || target_role, |
|
45 | 45 | target_tracker, |
|
46 | 46 | target_role) |
|
47 | 47 | end |
|
48 | 48 | end |
|
49 | 49 | end |
|
50 | 50 | |
|
51 | 51 | # Copies a single set of workflows from source to target |
|
52 | 52 | def self.copy_one(source_tracker, source_role, target_tracker, target_role) |
|
53 | 53 | unless source_tracker.is_a?(Tracker) && !source_tracker.new_record? && |
|
54 | 54 | source_role.is_a?(Role) && !source_role.new_record? && |
|
55 | 55 | target_tracker.is_a?(Tracker) && !target_tracker.new_record? && |
|
56 | 56 | target_role.is_a?(Role) && !target_role.new_record? |
|
57 | 57 | |
|
58 | 58 | raise ArgumentError.new("arguments can not be nil or unsaved objects") |
|
59 | 59 | end |
|
60 | 60 | |
|
61 | 61 | if source_tracker == target_tracker && source_role == target_role |
|
62 | 62 | false |
|
63 | 63 | else |
|
64 | 64 | transaction do |
|
65 | 65 | delete_all :tracker_id => target_tracker.id, :role_id => target_role.id |
|
66 | 66 | connection.insert "INSERT INTO #{WorkflowRule.table_name} (tracker_id, role_id, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type)" + |
|
67 | 67 | " SELECT #{target_tracker.id}, #{target_role.id}, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type" + |
|
68 | 68 | " FROM #{WorkflowRule.table_name}" + |
|
69 | 69 | " WHERE tracker_id = #{source_tracker.id} AND role_id = #{source_role.id}" |
|
70 | 70 | end |
|
71 | 71 | true |
|
72 | 72 | end |
|
73 | 73 | end |
|
74 | 74 | end |
@@ -1,102 +1,102 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2014 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | class WorkflowTransition < WorkflowRule |
|
19 | 19 | validates_presence_of :new_status |
|
20 | 20 | |
|
21 | 21 | # Returns workflow transitions count by tracker and role |
|
22 | 22 | def self.count_by_tracker_and_role |
|
23 | 23 | counts = connection.select_all("SELECT role_id, tracker_id, count(id) AS c FROM #{table_name} WHERE type = 'WorkflowTransition' GROUP BY role_id, tracker_id") |
|
24 | roles = Role.sorted | |
|
24 | roles = Role.sorted.to_a.select(&:consider_workflow?) | |
|
25 | 25 | trackers = Tracker.sorted |
|
26 | 26 | result = [] |
|
27 | 27 | trackers.each do |tracker| |
|
28 | 28 | t = [] |
|
29 | 29 | roles.each do |role| |
|
30 | 30 | row = counts.detect {|c| c['role_id'].to_s == role.id.to_s && c['tracker_id'].to_s == tracker.id.to_s} |
|
31 | 31 | t << [role, (row.nil? ? 0 : row['c'].to_i)] |
|
32 | 32 | end |
|
33 | 33 | result << [tracker, t] |
|
34 | 34 | end |
|
35 | 35 | result |
|
36 | 36 | end |
|
37 | 37 | |
|
38 | 38 | def self.replace_transitions(trackers, roles, transitions) |
|
39 | 39 | trackers = Array.wrap trackers |
|
40 | 40 | roles = Array.wrap roles |
|
41 | 41 | |
|
42 | 42 | transaction do |
|
43 | 43 | records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).to_a |
|
44 | 44 | |
|
45 | 45 | transitions.each do |old_status_id, transitions_by_new_status| |
|
46 | 46 | transitions_by_new_status.each do |new_status_id, transition_by_rule| |
|
47 | 47 | transition_by_rule.each do |rule, transition| |
|
48 | 48 | trackers.each do |tracker| |
|
49 | 49 | roles.each do |role| |
|
50 | 50 | w = records.select {|r| |
|
51 | 51 | r.old_status_id == old_status_id.to_i && |
|
52 | 52 | r.new_status_id == new_status_id.to_i && |
|
53 | 53 | r.tracker_id == tracker.id && |
|
54 | 54 | r.role_id == role.id && |
|
55 | 55 | !r.destroyed? |
|
56 | 56 | } |
|
57 | 57 | |
|
58 | 58 | if rule == 'always' |
|
59 | 59 | w = w.select {|r| !r.author && !r.assignee} |
|
60 | 60 | else |
|
61 | 61 | w = w.select {|r| r.author || r.assignee} |
|
62 | 62 | end |
|
63 | 63 | if w.size > 1 |
|
64 | 64 | w[1..-1].each(&:destroy) |
|
65 | 65 | end |
|
66 | 66 | w = w.first |
|
67 | 67 | |
|
68 | 68 | if transition == "1" || transition == true |
|
69 | 69 | unless w |
|
70 | 70 | w = WorkflowTransition.new(:old_status_id => old_status_id, :new_status_id => new_status_id, :tracker_id => tracker.id, :role_id => role.id) |
|
71 | 71 | records << w |
|
72 | 72 | end |
|
73 | 73 | w.author = true if rule == "author" |
|
74 | 74 | w.assignee = true if rule == "assignee" |
|
75 | 75 | w.save if w.changed? |
|
76 | 76 | elsif w |
|
77 | 77 | if rule == 'always' |
|
78 | 78 | w.destroy |
|
79 | 79 | elsif rule == 'author' |
|
80 | 80 | if w.assignee |
|
81 | 81 | w.author = false |
|
82 | 82 | w.save if w.changed? |
|
83 | 83 | else |
|
84 | 84 | w.destroy |
|
85 | 85 | end |
|
86 | 86 | elsif rule == 'assignee' |
|
87 | 87 | if w.author |
|
88 | 88 | w.assignee = false |
|
89 | 89 | w.save if w.changed? |
|
90 | 90 | else |
|
91 | 91 | w.destroy |
|
92 | 92 | end |
|
93 | 93 | end |
|
94 | 94 | end |
|
95 | 95 | end |
|
96 | 96 | end |
|
97 | 97 | end |
|
98 | 98 | end |
|
99 | 99 | end |
|
100 | 100 | end |
|
101 | 101 | end |
|
102 | 102 | end |
@@ -1,75 +1,75 | |||
|
1 | 1 | <%= render :partial => 'action_menu' %> |
|
2 | 2 | |
|
3 | 3 | <%= title l(:label_workflow) %> |
|
4 | 4 | |
|
5 | 5 | <div class="tabs"> |
|
6 | 6 | <ul> |
|
7 | 7 | <li><%= link_to l(:label_status_transitions), workflows_edit_path(:role_id => @roles, :tracker_id => @trackers), :class => 'selected' %></li> |
|
8 | 8 | <li><%= link_to l(:label_fields_permissions), workflows_permissions_path(:role_id => @roles, :tracker_id => @trackers) %></li> |
|
9 | 9 | </ul> |
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 12 | <p><%=l(:text_workflow_edit)%>:</p> |
|
13 | 13 | |
|
14 | 14 | <%= form_tag({}, :method => 'get') do %> |
|
15 | 15 | <p> |
|
16 | 16 | <label><%=l(:label_role)%>: |
|
17 | <%= options_for_workflow_select 'role_id[]', Role.sorted, @roles, :id => 'role_id', :class => 'expandable' %> | |
|
17 | <%= options_for_workflow_select 'role_id[]', Role.sorted.select(&:consider_workflow?), @roles, :id => 'role_id', :class => 'expandable' %> | |
|
18 | 18 | </label> |
|
19 | 19 | <a href="#" data-expands="#role_id"><%= image_tag 'bullet_toggle_plus.png' %></a> |
|
20 | 20 | |
|
21 | 21 | <label><%=l(:label_tracker)%>: |
|
22 | 22 | <%= options_for_workflow_select 'tracker_id[]', Tracker.sorted, @trackers, :id => 'tracker_id', :class => 'expandable' %> |
|
23 | 23 | </label> |
|
24 | 24 | <a href="#" data-expands="#tracker_id"><%= image_tag 'bullet_toggle_plus.png' %></a> |
|
25 | 25 | |
|
26 | 26 | <%= submit_tag l(:button_edit), :name => nil %> |
|
27 | 27 | |
|
28 | 28 | <%= hidden_field_tag 'used_statuses_only', '0', :id => nil %> |
|
29 | 29 | <label><%= check_box_tag 'used_statuses_only', '1', @used_statuses_only %> <%= l(:label_display_used_statuses_only) %></label> |
|
30 | 30 | |
|
31 | 31 | </p> |
|
32 | 32 | <% end %> |
|
33 | 33 | |
|
34 | 34 | <% if @trackers && @roles && @statuses.any? %> |
|
35 | 35 | <%= form_tag({}, :id => 'workflow_form' ) do %> |
|
36 | 36 | <%= @trackers.map {|tracker| hidden_field_tag 'tracker_id[]', tracker.id, :id => nil}.join.html_safe %> |
|
37 | 37 | <%= @roles.map {|role| hidden_field_tag 'role_id[]', role.id, :id => nil}.join.html_safe %> |
|
38 | 38 | <%= hidden_field_tag 'used_statuses_only', params[:used_statuses_only], :id => nil %> |
|
39 | 39 | <div class="autoscroll"> |
|
40 | 40 | <%= render :partial => 'form', :locals => {:name => 'always', :workflows => @workflows['always']} %> |
|
41 | 41 | |
|
42 | 42 | <fieldset class="collapsible" style="padding: 0; margin-top: 0.5em;"> |
|
43 | 43 | <legend onclick="toggleFieldset(this);"><%= l(:label_additional_workflow_transitions_for_author) %></legend> |
|
44 | 44 | <div id="author_workflows" style="margin: 0.5em 0 0.5em 0;"> |
|
45 | 45 | <%= render :partial => 'form', :locals => {:name => 'author', :workflows => @workflows['author']} %> |
|
46 | 46 | </div> |
|
47 | 47 | </fieldset> |
|
48 | 48 | <%= javascript_tag "hideFieldset($('#author_workflows'))" unless @workflows['author'].present? %> |
|
49 | 49 | |
|
50 | 50 | <fieldset class="collapsible" style="padding: 0;"> |
|
51 | 51 | <legend onclick="toggleFieldset(this);"><%= l(:label_additional_workflow_transitions_for_assignee) %></legend> |
|
52 | 52 | <div id="assignee_workflows" style="margin: 0.5em 0 0.5em 0;"> |
|
53 | 53 | <%= render :partial => 'form', :locals => {:name => 'assignee', :workflows => @workflows['assignee']} %> |
|
54 | 54 | </div> |
|
55 | 55 | </fieldset> |
|
56 | 56 | <%= javascript_tag "hideFieldset($('#assignee_workflows'))" unless @workflows['assignee'].present? %> |
|
57 | 57 | </div> |
|
58 | 58 | <%= submit_tag l(:button_save) %> |
|
59 | 59 | <% end %> |
|
60 | 60 | <% end %> |
|
61 | 61 | |
|
62 | 62 | <%= javascript_tag do %> |
|
63 | 63 | $("a[data-expands]").click(function(e){ |
|
64 | 64 | e.preventDefault(); |
|
65 | 65 | var target = $($(this).attr("data-expands")); |
|
66 | 66 | if (target.attr("multiple")) { |
|
67 | 67 | target.attr("multiple", false); |
|
68 | 68 | target.find("option[value=all]").show(); |
|
69 | 69 | } else { |
|
70 | 70 | target.attr("multiple", true); |
|
71 | 71 | target.find("option[value=all]").attr("selected", false).hide(); |
|
72 | 72 | } |
|
73 | 73 | }); |
|
74 | 74 | |
|
75 | 75 | <% end %> |
@@ -1,123 +1,123 | |||
|
1 | 1 | <%= render :partial => 'action_menu' %> |
|
2 | 2 | |
|
3 | 3 | <%= title l(:label_workflow) %> |
|
4 | 4 | |
|
5 | 5 | <div class="tabs"> |
|
6 | 6 | <ul> |
|
7 | 7 | <li><%= link_to l(:label_status_transitions), workflows_edit_path(:role_id => @roles, :tracker_id => @trackers) %></li> |
|
8 | 8 | <li><%= link_to l(:label_fields_permissions), workflows_permissions_path(:role_id => @roles, :tracker_id => @trackers), :class => 'selected' %></li> |
|
9 | 9 | </ul> |
|
10 | 10 | </div> |
|
11 | 11 | |
|
12 | 12 | <p><%=l(:text_workflow_edit)%>:</p> |
|
13 | 13 | |
|
14 | 14 | <%= form_tag({}, :method => 'get') do %> |
|
15 | 15 | <p> |
|
16 | 16 | <label><%=l(:label_role)%>: |
|
17 | <%= options_for_workflow_select 'role_id[]', Role.sorted, @roles, :id => 'role_id', :class => 'expandable' %> | |
|
17 | <%= options_for_workflow_select 'role_id[]', Role.sorted.select(&:consider_workflow?), @roles, :id => 'role_id', :class => 'expandable' %> | |
|
18 | 18 | </label> |
|
19 | 19 | <a href="#" data-expands="#role_id"><%= image_tag 'bullet_toggle_plus.png' %></a> |
|
20 | 20 | |
|
21 | 21 | <label><%=l(:label_tracker)%>: |
|
22 | 22 | <%= options_for_workflow_select 'tracker_id[]', Tracker.sorted, @trackers, :id => 'tracker_id', :class => 'expandable' %> |
|
23 | 23 | </label> |
|
24 | 24 | <a href="#" data-expands="#tracker_id"><%= image_tag 'bullet_toggle_plus.png' %></a> |
|
25 | 25 | |
|
26 | 26 | <%= submit_tag l(:button_edit), :name => nil %> |
|
27 | 27 | |
|
28 | 28 | <%= hidden_field_tag 'used_statuses_only', '0', :id => nil %> |
|
29 | 29 | <label><%= check_box_tag 'used_statuses_only', '1', @used_statuses_only %> <%= l(:label_display_used_statuses_only) %></label> |
|
30 | 30 | </p> |
|
31 | 31 | <% end %> |
|
32 | 32 | |
|
33 | 33 | <% if @trackers && @roles && @statuses.any? %> |
|
34 | 34 | <%= form_tag({}, :id => 'workflow_form' ) do %> |
|
35 | 35 | <%= @trackers.map {|tracker| hidden_field_tag 'tracker_id[]', tracker.id, :id => nil}.join.html_safe %> |
|
36 | 36 | <%= @roles.map {|role| hidden_field_tag 'role_id[]', role.id, :id => nil}.join.html_safe %> |
|
37 | 37 | <%= hidden_field_tag 'used_statuses_only', params[:used_statuses_only], :id => nil %> |
|
38 | 38 | <div class="autoscroll"> |
|
39 | 39 | <table class="list workflows fields_permissions"> |
|
40 | 40 | <thead> |
|
41 | 41 | <tr> |
|
42 | 42 | <th> |
|
43 | 43 | </th> |
|
44 | 44 | <th colspan="<%= @statuses.length %>"><%=l(:label_issue_status)%></th> |
|
45 | 45 | </tr> |
|
46 | 46 | <tr> |
|
47 | 47 | <td></td> |
|
48 | 48 | <% for status in @statuses %> |
|
49 | 49 | <td style="width:<%= 75 / @statuses.size %>%;"> |
|
50 | 50 | <%=h status.name %> |
|
51 | 51 | </td> |
|
52 | 52 | <% end %> |
|
53 | 53 | </tr> |
|
54 | 54 | </thead> |
|
55 | 55 | <tbody> |
|
56 | 56 | <tr class="group open"> |
|
57 | 57 | <td colspan="<%= @statuses.size + 1 %>"> |
|
58 | 58 | <span class="expander" onclick="toggleRowGroup(this);"> </span> |
|
59 | 59 | <%= l(:field_core_fields) %> |
|
60 | 60 | </td> |
|
61 | 61 | </tr> |
|
62 | 62 | <% @fields.each do |field, name| %> |
|
63 | 63 | <tr class="<%= cycle("odd", "even") %>"> |
|
64 | 64 | <td class="name"> |
|
65 | 65 | <%=h name %> <%= content_tag('span', '*', :class => 'required') if field_required?(field) %> |
|
66 | 66 | </td> |
|
67 | 67 | <% for status in @statuses -%> |
|
68 | 68 | <td class="<%= @permissions[status.id][field] %>"> |
|
69 | 69 | <%= field_permission_tag(@permissions, status, field, @roles) %> |
|
70 | 70 | <% unless status == @statuses.last %><a href="#" class="repeat-value">»</a><% end %> |
|
71 | 71 | </td> |
|
72 | 72 | <% end -%> |
|
73 | 73 | </tr> |
|
74 | 74 | <% end %> |
|
75 | 75 | <% if @custom_fields.any? %> |
|
76 | 76 | <tr class="group open"> |
|
77 | 77 | <td colspan="<%= @statuses.size + 1 %>"> |
|
78 | 78 | <span class="expander" onclick="toggleRowGroup(this);"> </span> |
|
79 | 79 | <%= l(:label_custom_field_plural) %> |
|
80 | 80 | </td> |
|
81 | 81 | </tr> |
|
82 | 82 | <% @custom_fields.each do |field| %> |
|
83 | 83 | <tr class="<%= cycle("odd", "even") %>"> |
|
84 | 84 | <td class="name"> |
|
85 | 85 | <%=h field.name %> <%= content_tag('span', '*', :class => 'required') if field_required?(field) %> |
|
86 | 86 | </td> |
|
87 | 87 | <% for status in @statuses -%> |
|
88 | 88 | <td class="<%= @permissions[status.id][field.id.to_s] %>"> |
|
89 | 89 | <%= field_permission_tag(@permissions, status, field, @roles) %> |
|
90 | 90 | <% unless status == @statuses.last %><a href="#" class="repeat-value">»</a><% end %> |
|
91 | 91 | </td> |
|
92 | 92 | <% end -%> |
|
93 | 93 | </tr> |
|
94 | 94 | <% end %> |
|
95 | 95 | <% end %> |
|
96 | 96 | </tbody> |
|
97 | 97 | </table> |
|
98 | 98 | </div> |
|
99 | 99 | <%= submit_tag l(:button_save) %> |
|
100 | 100 | <% end %> |
|
101 | 101 | <% end %> |
|
102 | 102 | |
|
103 | 103 | <%= javascript_tag do %> |
|
104 | 104 | $("a.repeat-value").click(function(e){ |
|
105 | 105 | e.preventDefault(); |
|
106 | 106 | var td = $(this).closest('td'); |
|
107 | 107 | var selected = td.find("select").find(":selected").val(); |
|
108 | 108 | td.nextAll('td').find("select").val(selected); |
|
109 | 109 | }); |
|
110 | 110 | |
|
111 | 111 | $("a[data-expands]").click(function(e){ |
|
112 | 112 | e.preventDefault(); |
|
113 | 113 | var target = $($(this).attr("data-expands")); |
|
114 | 114 | if (target.attr("multiple")) { |
|
115 | 115 | target.attr("multiple", false); |
|
116 | 116 | target.find("option[value=all]").show(); |
|
117 | 117 | } else { |
|
118 | 118 | target.attr("multiple", true); |
|
119 | 119 | target.find("option[value=all]").attr("selected", false).hide(); |
|
120 | 120 | } |
|
121 | 121 | }); |
|
122 | 122 | |
|
123 | 123 | <% end %> |
General Comments 0
You need to be logged in to leave comments.
Login now