##// END OF EJS Templates
Adds helpers for query columns selection....
Jean-Philippe Lang -
r11221:1ac8fd8c4214
parent child
Show More
@@ -1,71 +1,73
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 SettingsController < ApplicationController
18 class SettingsController < ApplicationController
19 layout 'admin'
19 layout 'admin'
20 menu_item :plugins, :only => :plugin
20 menu_item :plugins, :only => :plugin
21
21
22 helper :queries
23
22 before_filter :require_admin
24 before_filter :require_admin
23
25
24 def index
26 def index
25 edit
27 edit
26 render :action => 'edit'
28 render :action => 'edit'
27 end
29 end
28
30
29 def edit
31 def edit
30 @notifiables = Redmine::Notifiable.all
32 @notifiables = Redmine::Notifiable.all
31 if request.post? && params[:settings] && params[:settings].is_a?(Hash)
33 if request.post? && params[:settings] && params[:settings].is_a?(Hash)
32 settings = (params[:settings] || {}).dup.symbolize_keys
34 settings = (params[:settings] || {}).dup.symbolize_keys
33 settings.each do |name, value|
35 settings.each do |name, value|
34 # remove blank values in array settings
36 # remove blank values in array settings
35 value.delete_if {|v| v.blank? } if value.is_a?(Array)
37 value.delete_if {|v| v.blank? } if value.is_a?(Array)
36 Setting[name] = value
38 Setting[name] = value
37 end
39 end
38 flash[:notice] = l(:notice_successful_update)
40 flash[:notice] = l(:notice_successful_update)
39 redirect_to settings_path(:tab => params[:tab])
41 redirect_to settings_path(:tab => params[:tab])
40 else
42 else
41 @options = {}
43 @options = {}
42 user_format = User::USER_FORMATS.collect{|key, value| [key, value[:setting_order]]}.sort{|a, b| a[1] <=> b[1]}
44 user_format = User::USER_FORMATS.collect{|key, value| [key, value[:setting_order]]}.sort{|a, b| a[1] <=> b[1]}
43 @options[:user_format] = user_format.collect{|f| [User.current.name(f[0]), f[0].to_s]}
45 @options[:user_format] = user_format.collect{|f| [User.current.name(f[0]), f[0].to_s]}
44 @deliveries = ActionMailer::Base.perform_deliveries
46 @deliveries = ActionMailer::Base.perform_deliveries
45
47
46 @guessed_host_and_path = request.host_with_port.dup
48 @guessed_host_and_path = request.host_with_port.dup
47 @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank?
49 @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank?
48
50
49 Redmine::Themes.rescan
51 Redmine::Themes.rescan
50 end
52 end
51 end
53 end
52
54
53 def plugin
55 def plugin
54 @plugin = Redmine::Plugin.find(params[:id])
56 @plugin = Redmine::Plugin.find(params[:id])
55 unless @plugin.configurable?
57 unless @plugin.configurable?
56 render_404
58 render_404
57 return
59 return
58 end
60 end
59
61
60 if request.post?
62 if request.post?
61 Setting.send "plugin_#{@plugin.id}=", params[:settings]
63 Setting.send "plugin_#{@plugin.id}=", params[:settings]
62 flash[:notice] = l(:notice_successful_update)
64 flash[:notice] = l(:notice_successful_update)
63 redirect_to plugin_settings_path(@plugin)
65 redirect_to plugin_settings_path(@plugin)
64 else
66 else
65 @partial = @plugin.settings[:partial]
67 @partial = @plugin.settings[:partial]
66 @settings = Setting.send "plugin_#{@plugin.id}"
68 @settings = Setting.send "plugin_#{@plugin.id}"
67 end
69 end
68 rescue Redmine::PluginNotFound
70 rescue Redmine::PluginNotFound
69 render_404
71 render_404
70 end
72 end
71 end
73 end
@@ -1,186 +1,194
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module QueriesHelper
20 module QueriesHelper
21 def filters_options_for_select(query)
21 def filters_options_for_select(query)
22 options_for_select(filters_options(query))
22 options_for_select(filters_options(query))
23 end
23 end
24
24
25 def filters_options(query)
25 def filters_options(query)
26 options = [[]]
26 options = [[]]
27 options += query.available_filters.map do |field, field_options|
27 options += query.available_filters.map do |field, field_options|
28 [field_options[:name], field]
28 [field_options[:name], field]
29 end
29 end
30 end
30 end
31
31
32 def available_block_columns_tags(query)
32 def available_block_columns_tags(query)
33 tags = ''.html_safe
33 tags = ''.html_safe
34 query.available_block_columns.each do |column|
34 query.available_block_columns.each do |column|
35 tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column)) + " #{column.caption}", :class => 'inline')
35 tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column)) + " #{column.caption}", :class => 'inline')
36 end
36 end
37 tags
37 tags
38 end
38 end
39
39
40 def query_available_inline_columns_options(query)
41 (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
42 end
43
44 def query_selected_inline_columns_options(query)
45 (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
46 end
47
40 def column_header(column)
48 def column_header(column)
41 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
49 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
42 :default_order => column.default_order) :
50 :default_order => column.default_order) :
43 content_tag('th', h(column.caption))
51 content_tag('th', h(column.caption))
44 end
52 end
45
53
46 def column_content(column, issue)
54 def column_content(column, issue)
47 value = column.value(issue)
55 value = column.value(issue)
48 if value.is_a?(Array)
56 if value.is_a?(Array)
49 value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
57 value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
50 else
58 else
51 column_value(column, issue, value)
59 column_value(column, issue, value)
52 end
60 end
53 end
61 end
54
62
55 def column_value(column, issue, value)
63 def column_value(column, issue, value)
56 case value.class.name
64 case value.class.name
57 when 'String'
65 when 'String'
58 if column.name == :subject
66 if column.name == :subject
59 link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
67 link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
60 elsif column.name == :description
68 elsif column.name == :description
61 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
69 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
62 else
70 else
63 h(value)
71 h(value)
64 end
72 end
65 when 'Time'
73 when 'Time'
66 format_time(value)
74 format_time(value)
67 when 'Date'
75 when 'Date'
68 format_date(value)
76 format_date(value)
69 when 'Fixnum'
77 when 'Fixnum'
70 if column.name == :id
78 if column.name == :id
71 link_to value, issue_path(issue)
79 link_to value, issue_path(issue)
72 elsif column.name == :done_ratio
80 elsif column.name == :done_ratio
73 progress_bar(value, :width => '80px')
81 progress_bar(value, :width => '80px')
74 else
82 else
75 value.to_s
83 value.to_s
76 end
84 end
77 when 'Float'
85 when 'Float'
78 sprintf "%.2f", value
86 sprintf "%.2f", value
79 when 'User'
87 when 'User'
80 link_to_user value
88 link_to_user value
81 when 'Project'
89 when 'Project'
82 link_to_project value
90 link_to_project value
83 when 'Version'
91 when 'Version'
84 link_to(h(value), :controller => 'versions', :action => 'show', :id => value)
92 link_to(h(value), :controller => 'versions', :action => 'show', :id => value)
85 when 'TrueClass'
93 when 'TrueClass'
86 l(:general_text_Yes)
94 l(:general_text_Yes)
87 when 'FalseClass'
95 when 'FalseClass'
88 l(:general_text_No)
96 l(:general_text_No)
89 when 'Issue'
97 when 'Issue'
90 value.visible? ? link_to_issue(value) : "##{value.id}"
98 value.visible? ? link_to_issue(value) : "##{value.id}"
91 when 'IssueRelation'
99 when 'IssueRelation'
92 other = value.other_issue(issue)
100 other = value.other_issue(issue)
93 content_tag('span',
101 content_tag('span',
94 (l(value.label_for(issue)) + " " + link_to_issue(other, :subject => false, :tracker => false)).html_safe,
102 (l(value.label_for(issue)) + " " + link_to_issue(other, :subject => false, :tracker => false)).html_safe,
95 :class => value.css_classes_for(issue))
103 :class => value.css_classes_for(issue))
96 else
104 else
97 h(value)
105 h(value)
98 end
106 end
99 end
107 end
100
108
101 def csv_content(column, issue)
109 def csv_content(column, issue)
102 value = column.value(issue)
110 value = column.value(issue)
103 if value.is_a?(Array)
111 if value.is_a?(Array)
104 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
112 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
105 else
113 else
106 csv_value(column, issue, value)
114 csv_value(column, issue, value)
107 end
115 end
108 end
116 end
109
117
110 def csv_value(column, issue, value)
118 def csv_value(column, issue, value)
111 case value.class.name
119 case value.class.name
112 when 'Time'
120 when 'Time'
113 format_time(value)
121 format_time(value)
114 when 'Date'
122 when 'Date'
115 format_date(value)
123 format_date(value)
116 when 'Float'
124 when 'Float'
117 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
125 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
118 when 'IssueRelation'
126 when 'IssueRelation'
119 other = value.other_issue(issue)
127 other = value.other_issue(issue)
120 l(value.label_for(issue)) + " ##{other.id}"
128 l(value.label_for(issue)) + " ##{other.id}"
121 else
129 else
122 value.to_s
130 value.to_s
123 end
131 end
124 end
132 end
125
133
126 def query_to_csv(items, query, options={})
134 def query_to_csv(items, query, options={})
127 encoding = l(:general_csv_encoding)
135 encoding = l(:general_csv_encoding)
128 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
136 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
129 query.available_block_columns.each do |column|
137 query.available_block_columns.each do |column|
130 if options[column.name].present?
138 if options[column.name].present?
131 columns << column
139 columns << column
132 end
140 end
133 end
141 end
134
142
135 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
143 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
136 # csv header fields
144 # csv header fields
137 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
145 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
138 # csv lines
146 # csv lines
139 items.each do |item|
147 items.each do |item|
140 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) }
148 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) }
141 end
149 end
142 end
150 end
143 export
151 export
144 end
152 end
145
153
146 # Retrieve query from session or build a new query
154 # Retrieve query from session or build a new query
147 def retrieve_query
155 def retrieve_query
148 if !params[:query_id].blank?
156 if !params[:query_id].blank?
149 cond = "project_id IS NULL"
157 cond = "project_id IS NULL"
150 cond << " OR project_id = #{@project.id}" if @project
158 cond << " OR project_id = #{@project.id}" if @project
151 @query = IssueQuery.find(params[:query_id], :conditions => cond)
159 @query = IssueQuery.find(params[:query_id], :conditions => cond)
152 raise ::Unauthorized unless @query.visible?
160 raise ::Unauthorized unless @query.visible?
153 @query.project = @project
161 @query.project = @project
154 session[:query] = {:id => @query.id, :project_id => @query.project_id}
162 session[:query] = {:id => @query.id, :project_id => @query.project_id}
155 sort_clear
163 sort_clear
156 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
164 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
157 # Give it a name, required to be valid
165 # Give it a name, required to be valid
158 @query = IssueQuery.new(:name => "_")
166 @query = IssueQuery.new(:name => "_")
159 @query.project = @project
167 @query.project = @project
160 @query.build_from_params(params)
168 @query.build_from_params(params)
161 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
169 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
162 else
170 else
163 # retrieve from session
171 # retrieve from session
164 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
172 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
165 @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
173 @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
166 @query.project = @project
174 @query.project = @project
167 end
175 end
168 end
176 end
169
177
170 def retrieve_query_from_session
178 def retrieve_query_from_session
171 if session[:query]
179 if session[:query]
172 if session[:query][:id]
180 if session[:query][:id]
173 @query = IssueQuery.find_by_id(session[:query][:id])
181 @query = IssueQuery.find_by_id(session[:query][:id])
174 return unless @query
182 return unless @query
175 else
183 else
176 @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
184 @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
177 end
185 end
178 if session[:query].has_key?(:project_id)
186 if session[:query].has_key?(:project_id)
179 @query.project_id = session[:query][:project_id]
187 @query.project_id = session[:query][:project_id]
180 else
188 else
181 @query.project = @project
189 @query.project = @project
182 end
190 end
183 @query
191 @query
184 end
192 end
185 end
193 end
186 end
194 end
@@ -1,34 +1,34
1 <table class="query-columns">
1 <table class="query-columns">
2 <tr>
2 <tr>
3 <td style="padding-left:0">
3 <td style="padding-left:0">
4 <%= label_tag "available_columns", l(:description_available_columns) %>
4 <%= label_tag "available_columns", l(:description_available_columns) %>
5 <br />
5 <br />
6 <%= select_tag 'available_columns',
6 <%= select_tag 'available_columns',
7 options_for_select((query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}),
7 options_for_select(query_available_inline_columns_options(query)),
8 :multiple => true, :size => 10, :style => "width:150px",
8 :multiple => true, :size => 10, :style => "width:150px",
9 :ondblclick => "moveOptions(this.form.available_columns, this.form.selected_columns);" %>
9 :ondblclick => "moveOptions(this.form.available_columns, this.form.selected_columns);" %>
10 </td>
10 </td>
11 <td class="buttons">
11 <td class="buttons">
12 <input type="button" value="&#8594;"
12 <input type="button" value="&#8594;"
13 onclick="moveOptions(this.form.available_columns, this.form.selected_columns);" /><br />
13 onclick="moveOptions(this.form.available_columns, this.form.selected_columns);" /><br />
14 <input type="button" value="&#8592;"
14 <input type="button" value="&#8592;"
15 onclick="moveOptions(this.form.selected_columns, this.form.available_columns);" />
15 onclick="moveOptions(this.form.selected_columns, this.form.available_columns);" />
16 </td>
16 </td>
17 <td>
17 <td>
18 <%= label_tag "selected_columns", l(:description_selected_columns) %>
18 <%= label_tag "selected_columns", l(:description_selected_columns) %>
19 <br />
19 <br />
20 <%= select_tag((defined?(tag_name) ? tag_name : 'c[]'),
20 <%= select_tag((defined?(tag_name) ? tag_name : 'c[]'),
21 options_for_select((query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}),
21 options_for_select(query_selected_inline_columns_options(query)),
22 :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px",
22 :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px",
23 :ondblclick => "moveOptions(this.form.selected_columns, this.form.available_columns);") %>
23 :ondblclick => "moveOptions(this.form.selected_columns, this.form.available_columns);") %>
24 </td>
24 </td>
25 <td class="buttons">
25 <td class="buttons">
26 <input type="button" value="&#8593;" onclick="moveOptionUp(this.form.selected_columns);" /><br />
26 <input type="button" value="&#8593;" onclick="moveOptionUp(this.form.selected_columns);" /><br />
27 <input type="button" value="&#8595;" onclick="moveOptionDown(this.form.selected_columns);" />
27 <input type="button" value="&#8595;" onclick="moveOptionDown(this.form.selected_columns);" />
28 </td>
28 </td>
29 </tr>
29 </tr>
30 </table>
30 </table>
31
31
32 <% content_for :header_tags do %>
32 <% content_for :header_tags do %>
33 <%= javascript_include_tag 'select_list_move' %>
33 <%= javascript_include_tag 'select_list_move' %>
34 <% end %>
34 <% end %>
General Comments 0
You need to be logged in to leave comments. Login now