Revision 6
Added by Jean-Philippe Lang almost 19 years ago
trunk/redmine/app/controllers/projects_controller.rb | ||
---|---|---|
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
|
18 | 18 |
class ProjectsController < ApplicationController |
19 |
layout 'base'
|
|
20 |
before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
|
|
19 |
layout 'base'
|
|
20 |
before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
|
|
21 | 21 |
before_filter :require_admin, :only => [ :add, :destroy ] |
22 | 22 |
|
23 | 23 |
helper :sort |
24 |
include SortHelper
|
|
25 |
helper :search_filter
|
|
26 |
include SearchFilterHelper
|
|
27 |
helper :custom_fields
|
|
28 |
include CustomFieldsHelper
|
|
24 |
include SortHelper
|
|
25 |
helper :search_filter
|
|
26 |
include SearchFilterHelper
|
|
27 |
helper :custom_fields
|
|
28 |
include CustomFieldsHelper
|
|
29 | 29 |
|
30 |
def index
|
|
31 |
list
|
|
32 |
render :action => 'list'
|
|
33 |
end
|
|
30 |
def index
|
|
31 |
list
|
|
32 |
render :action => 'list'
|
|
33 |
end
|
|
34 | 34 |
|
35 | 35 |
# Lists public projects |
36 | 36 |
def list |
... | ... | |
181 | 181 |
end |
182 | 182 |
end |
183 | 183 |
|
184 |
# Show issues list of @project |
|
185 |
def list_issues |
|
186 |
sort_init 'issues.id', 'desc' |
|
187 |
sort_update |
|
188 |
|
|
189 |
search_filter_criteria 'issues.tracker_id', :values => "Tracker.find(:all)" |
|
190 |
search_filter_criteria 'issues.priority_id', :values => "Enumeration.find(:all, :conditions => ['opt=?','IPRI'])" |
|
191 |
search_filter_criteria 'issues.category_id', :values => "@project.issue_categories" |
|
192 |
search_filter_criteria 'issues.status_id', :values => "IssueStatus.find(:all)" |
|
193 |
search_filter_criteria 'issues.author_id', :values => "User.find(:all)", :label => "display_name" |
|
194 |
search_filter_update if params[:set_filter] or request.post? |
|
195 |
|
|
196 |
@issue_count = @project.issues.count(search_filter_clause) |
|
197 |
@issue_pages = Paginator.new self, @issue_count, |
|
198 |
15, |
|
199 |
@params['page'] |
|
200 |
@issues = @project.issues.find :all, :order => sort_clause, |
|
184 |
# Show issues list of @project |
|
185 |
def list_issues |
|
186 |
sort_init 'issues.id', 'desc' |
|
187 |
sort_update |
|
188 |
|
|
189 |
search_filter_init_list_issues |
|
190 |
search_filter_update if params[:set_filter] or request.post? |
|
191 |
|
|
192 |
@issue_count = Issue.count(:include => :status, :conditions => search_filter_clause) |
|
193 |
@issue_pages = Paginator.new self, @issue_count, 15, @params['page'] |
|
194 |
@issues = Issue.find :all, :order => sort_clause, |
|
201 | 195 |
:include => [ :author, :status, :tracker ], |
202 | 196 |
:conditions => search_filter_clause, |
203 | 197 |
:limit => @issue_pages.items_per_page, |
204 | 198 |
:offset => @issue_pages.current.offset |
205 |
end
|
|
199 |
end
|
|
206 | 200 |
|
201 |
# Export filtered/sorted issues list to CSV |
|
202 |
def export_issues_csv |
|
203 |
sort_init 'issues.id', 'desc' |
|
204 |
sort_update |
|
205 |
|
|
206 |
search_filter_init_list_issues |
|
207 |
|
|
208 |
@issues = Issue.find :all, :order => sort_clause, |
|
209 |
:include => [ :author, :status, :tracker ], |
|
210 |
:conditions => search_filter_clause |
|
211 |
|
|
212 |
export = StringIO.new |
|
213 |
CSV::Writer.generate(export, ',') do |csv| |
|
214 |
csv << %w(Id Status Tracker Subject Author Created Updated) |
|
215 |
@issues.each do |issue| |
|
216 |
csv << [issue.id, issue.status.name, issue.tracker.name, issue.subject, issue.author.display_name, _('(time)', issue.created_on), _('(time)', issue.updated_on)] |
|
217 |
end |
|
218 |
end |
|
219 |
export.rewind |
|
220 |
send_data(export.read, |
|
221 |
:type => 'text/csv; charset=utf-8; header=present', |
|
222 |
:filename => 'export.csv') |
|
223 |
end |
|
224 |
|
|
207 | 225 |
# Add a news to @project |
208 | 226 |
def add_news |
209 | 227 |
@news = @project.news.build(params[:news]) |
... | ... | |
216 | 234 |
end |
217 | 235 |
|
218 | 236 |
# Show news list of @project |
219 |
def list_news
|
|
237 |
def list_news
|
|
220 | 238 |
@news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC" |
221 |
end
|
|
239 |
end
|
|
222 | 240 |
|
223 | 241 |
def add_file |
224 | 242 |
if request.post? |
... | ... | |
238 | 256 |
@versions = @project.versions |
239 | 257 |
end |
240 | 258 |
|
241 |
# Show changelog of @project
|
|
242 |
def changelog
|
|
243 |
@fixed_issues = @project.issues.find(:all, |
|
244 |
:include => [ :fixed_version, :status, :tracker ],
|
|
245 |
:conditions => [ "issue_statuses.is_closed=? and trackers.is_in_chlog=? and issues.fixed_version_id is not null", true, true]
|
|
246 |
)
|
|
247 |
end
|
|
259 |
# Show changelog of @project
|
|
260 |
def changelog
|
|
261 |
@fixed_issues = @project.issues.find(:all,
|
|
262 |
:include => [ :fixed_version, :status, :tracker ], |
|
263 |
:conditions => [ "issue_statuses.is_closed=? and trackers.is_in_chlog=? and issues.fixed_version_id is not null", true, true] |
|
264 |
) |
|
265 |
end
|
|
248 | 266 |
|
249 | 267 |
private |
250 | 268 |
# Find project of id params[:id] |
trunk/redmine/app/helpers/search_filter_helper.rb | ||
---|---|---|
17 | 17 |
|
18 | 18 |
module SearchFilterHelper |
19 | 19 |
|
20 |
def search_filter_criteria(field, options = {}) |
|
21 |
session[:search_filter] ||= {} |
|
22 |
session[:search_filter][field] ||= options |
|
23 |
# session[:search_filter][field][:values] = options[:values] unless options[:values].nil? |
|
24 |
# session[:search_filter][field][:label] = options[:label] unless options[:label].nil? |
|
25 |
end |
|
20 |
def search_filter_criteria(name, options = {}) |
|
21 |
session[:search_filter] ||= {} |
|
22 |
session[:search_filter][name] ||= {} |
|
23 |
unless session[:search_filter][name][:options] and session[:search_filter][name][:conditions] |
|
24 |
session[:search_filter][name][:options] = [] |
|
25 |
session[:search_filter][name][:conditions] = {} |
|
26 |
yield.each { |c| |
|
27 |
session[:search_filter][name][:options] << [c[0], c[1].to_s] |
|
28 |
session[:search_filter][name][:conditions].store(c[1].to_s, c[2]) |
|
29 |
} |
|
30 |
end |
|
31 |
end |
|
26 | 32 |
|
27 |
def search_filter_update |
|
28 |
session[:search_filter].each_key {|field| session[:search_filter][field][:value] = params[field] } |
|
29 |
#@search_filter[:value] = params[@search_filter[:field]] |
|
30 |
end |
|
33 |
def search_filter_update |
|
34 |
session[:search_filter].each_key {|field| session[:search_filter][field][:value] = params[field] } |
|
35 |
end |
|
31 | 36 |
|
32 |
def search_filter_clause |
|
33 |
clause = "1=1" |
|
34 |
session[:search_filter].each {|field, criteria| clause = clause + " AND " + field + "='" + session[:search_filter][field][:value] + "'" unless session[:search_filter][field][:value].nil? || session[:search_filter][field][:value].empty? } |
|
35 |
clause |
|
36 |
#@search_filter[:field] + "='" + @search_filter[:value] + "'" unless @search_filter[:value].nil? || @search_filter[:value].empty? |
|
37 |
end |
|
37 |
def search_filter_clause |
|
38 |
clause = ["issues.project_id=?", @project.id] |
|
39 |
session[:search_filter].each { |k, v| |
|
40 |
v[:value] ||= v[:options][0][1] |
|
41 |
if (!v[:conditions][v[:value]][0].empty?) |
|
42 |
clause[0] = clause[0] + " AND " + v[:conditions][v[:value]][0] |
|
43 |
clause << v[:conditions][v[:value]][1] if !v[:conditions][v[:value]][1].nil? |
|
44 |
end |
|
45 |
} |
|
46 |
clause |
|
47 |
end |
|
38 | 48 |
|
39 |
def search_filter_tag(field) |
|
40 |
option_values = [] |
|
41 |
#values = eval @search_filter[:values_expr] |
|
42 |
option_values = eval session[:search_filter][field][:values] |
|
43 |
|
|
44 |
content_tag("select", |
|
45 |
content_tag("option", "[All]", :value => "") + |
|
46 |
options_from_collection_for_select(option_values, |
|
47 |
"id", |
|
48 |
session[:search_filter][field][:label] || "name", |
|
49 |
session[:search_filter][field][:value].to_i |
|
50 |
), |
|
51 |
:name => field |
|
49 |
def search_filter_tag(criteria) |
|
50 |
content_tag("select", |
|
51 |
options_for_select(session[:search_filter][criteria][:options], session[:search_filter][criteria][:value]), |
|
52 |
:name => criteria |
|
52 | 53 |
) |
53 |
end |
|
54 |
end |
|
55 |
|
|
56 |
def search_filter_init_list_issues |
|
57 |
search_filter_criteria('status_id') { |
|
58 |
[ ["[Open]", "O", ["issue_statuses.is_closed=?", false]], |
|
59 |
["[All]", "A", ["", false]] |
|
60 |
] + IssueStatus.find(:all).collect {|s| [s.name, s.id, ["issues.status_id=?", s.id]] } |
|
61 |
} |
|
62 |
|
|
63 |
search_filter_criteria('tracker_id') { |
|
64 |
[ ["[All]", "A", ["", false]] |
|
65 |
] + Tracker.find(:all).collect {|s| [s.name, s.id, ["issues.tracker_id=?", s.id]] } |
|
66 |
} |
|
67 |
|
|
68 |
search_filter_criteria('priority_id') { |
|
69 |
[ ["[All]", "A", ["", false]] |
|
70 |
] + Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect {|s| [s.name, s.id, ["issues.priority_id=?", s.id]] } |
|
71 |
} |
|
72 |
|
|
73 |
search_filter_criteria('category_id') { |
|
74 |
[ ["[All]", "A", ["", false]], |
|
75 |
["[None]", "N", ["issues.category_id is null"]] |
|
76 |
] + @project.issue_categories.find(:all).collect {|s| [s.name, s.id, ["issues.category_id=?", s.id]] } |
|
77 |
} |
|
54 | 78 |
|
79 |
search_filter_criteria('assigned_to_id') { |
|
80 |
[ ["[All]", "A", ["", false]], |
|
81 |
["[Nobody]", "N", ["issues.assigned_to_id is null"]] |
|
82 |
] + User.find(:all).collect {|s| [s.display_name, s.id, ["issues.assigned_to_id=?", s.id]] } |
|
83 |
} |
|
84 |
end |
|
55 | 85 |
end |
trunk/redmine/app/views/projects/list_issues.rhtml | ||
---|---|---|
3 | 3 |
<form method="post" class="noborder"> |
4 | 4 |
<table cellpadding=2> |
5 | 5 |
<tr> |
6 |
<td><%=_('Status')%>:<br /><%= search_filter_tag("issues.status_id") %></td>
|
|
7 |
<td><%=_('Tracker')%>:<br /><%= search_filter_tag("issues.tracker_id") %></td>
|
|
8 |
<td><%=_('Priority')%>:<br /><%= search_filter_tag("issues.priority_id") %></td>
|
|
9 |
<td><%=_('Category')%>:<br /><%= search_filter_tag("issues.category_id") %></td>
|
|
10 |
<td><%=_('Author')%>:<br /><%= search_filter_tag("issues.author_id") %></td>
|
|
6 |
<td><%=_('Status')%>:<br /><%= search_filter_tag("status_id") %></td> |
|
7 |
<td><%=_('Tracker')%>:<br /><%= search_filter_tag("tracker_id") %></td> |
|
8 |
<td><%=_('Priority')%>:<br /><%= search_filter_tag("priority_id") %></td> |
|
9 |
<td><%=_('Category')%>:<br /><%= search_filter_tag("category_id") %></td> |
|
10 |
<td><%=_('Assigned to')%>:<br /><%= search_filter_tag("assigned_to_id") %></td>
|
|
11 | 11 |
<td valign="bottom"> |
12 | 12 |
<%= submit_tag _('Apply filter') %> |
13 | 13 |
<%= end_form_tag %> |
... | ... | |
17 | 17 |
<%= end_form_tag %> |
18 | 18 |
</td> |
19 | 19 |
</tr> |
20 |
</table> |
|
21 |
|
|
22 |
|
|
23 |
|
|
20 |
</table> |
|
21 |
|
|
24 | 22 |
<table border="0" cellspacing="1" cellpadding="2" class="listTableContent"> |
25 | 23 |
|
24 |
<tr><td colspan="7" align="right"> |
|
25 |
<small><%= link_to 'Export to CSV', :action => 'export_issues_csv', :id => @project.id %></small> |
|
26 |
</td></tr> |
|
27 |
|
|
26 | 28 |
<tr class="ListHead"> |
27 | 29 |
<%= sort_header_tag('issues.id', :caption => '#') %> |
28 | 30 |
<%= sort_header_tag('issue_statuses.name', :caption => _('Status')) %> |
... | ... | |
48 | 50 |
<p> |
49 | 51 |
<%= pagination_links_full @issue_pages %> |
50 | 52 |
[ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ] |
51 |
</p>
|
|
52 |
|
|
53 |
</p>
|
|
54 |
|
|
53 | 55 |
|
54 | 56 |
<p> |
55 | 57 |
<%= link_to_if_authorized '» ' + _('Report an issue'), :controller => 'projects', :action => 'add_issue', :id => @project %> |
trunk/redmine/app/views/reports/_simple.rhtml | ||
---|---|---|
15 | 15 |
<tr style="background-color:#CEE1ED"> |
16 | 16 |
<td><%= link_to row.name, :controller => 'projects', :action => 'list_issues', :id => @project, |
17 | 17 |
:set_filter => 1, |
18 |
"issues.#{field_name}" => row.id %></td>
|
|
18 |
"#{field_name}" => row.id %></td> |
|
19 | 19 |
<% for status in @statuses %> |
20 | 20 |
<td align="center"><%= link_to (aggregate data, { field_name => row.id, "status_id" => status.id }), |
21 | 21 |
:controller => 'projects', :action => 'list_issues', :id => @project, |
22 | 22 |
:set_filter => 1, |
23 |
"issues.status_id" => status.id,
|
|
24 |
"issues.#{field_name}" => row.id %></td>
|
|
23 |
"status_id" => status.id, |
|
24 |
"#{field_name}" => row.id %></td> |
|
25 | 25 |
<% end %> |
26 |
<td align="center"><%= aggregate data, { field_name => row.id, "closed" => 0 } %></td> |
|
26 |
<td align="center"><%= link_to (aggregate data, { field_name => row.id, "closed" => 0 }), |
|
27 |
:controller => 'projects', :action => 'list_issues', :id => @project, |
|
28 |
:set_filter => 1, |
|
29 |
"#{field_name}" => row.id, |
|
30 |
"status_id" => "O" %></td> |
|
27 | 31 |
<td align="center"><%= aggregate data, { field_name => row.id, "closed" => 1 } %></td> |
28 | 32 |
<td align="center"><%= link_to (aggregate data, { field_name => row.id }), |
29 | 33 |
:controller => 'projects', :action => 'list_issues', :id => @project, |
30 | 34 |
:set_filter => 1, |
31 |
"issues.#{field_name}" => row.id %></td> |
|
35 |
"#{field_name}" => row.id, |
|
36 |
"status_id" => "A" %></td> |
|
32 | 37 |
<% end %> |
33 | 38 |
</tr> |
34 | 39 |
</table> |
trunk/redmine/doc/CHANGELOG | ||
---|---|---|
5 | 5 |
http://redmine.sourceforge.net/ |
6 | 6 |
|
7 | 7 |
|
8 |
== xx/xx/2006 |
|
9 |
|
|
10 |
* More filter options in issues list |
|
11 |
* Issues list exportable to CSV |
|
12 |
* Fixed: Error on tables creation with PostgreSQL (rev5) |
|
13 |
* Fixed: SQL error in "issue reports" view with PostgreSQL (rev5) |
|
14 |
|
|
15 |
|
|
8 | 16 |
== 06/25/2006 - v0.1.0 |
9 | 17 |
|
10 | 18 |
* multiple users/multiple projects |
Also available in: Unified diff