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