@@ -382,10 +382,10 module IssuesHelper | |||||
382 |
|
382 | |||
383 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| |
|
383 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| | |
384 | # csv header fields |
|
384 | # csv header fields | |
385 |
csv << |
|
385 | csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } | |
386 | # csv lines |
|
386 | # csv lines | |
387 | issues.each do |issue| |
|
387 | issues.each do |issue| | |
388 |
csv << |
|
388 | csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, issue), encoding) } | |
389 | end |
|
389 | end | |
390 | end |
|
390 | end | |
391 | export |
|
391 | export |
@@ -67,7 +67,9 module QueriesHelper | |||||
67 | when 'Date' |
|
67 | when 'Date' | |
68 | format_date(value) |
|
68 | format_date(value) | |
69 | when 'Fixnum' |
|
69 | when 'Fixnum' | |
70 |
if column.name == : |
|
70 | if column.name == :id | |
|
71 | link_to value, issue_path(issue) | |||
|
72 | elsif column.name == :done_ratio | |||
71 | progress_bar(value, :width => '80px') |
|
73 | progress_bar(value, :width => '80px') | |
72 | else |
|
74 | else | |
73 | value.to_s |
|
75 | value.to_s |
@@ -20,6 +20,7 class IssueQuery < Query | |||||
20 | self.queried_class = Issue |
|
20 | self.queried_class = Issue | |
21 |
|
21 | |||
22 | self.available_columns = [ |
|
22 | self.available_columns = [ | |
|
23 | QueryColumn.new(:id, :sortable => "#{Issue.table_name}.id", :default_order => 'desc', :caption => '#', :frozen => true), | |||
23 | QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), |
|
24 | QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), | |
24 | QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true), |
|
25 | QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true), | |
25 | QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue), |
|
26 | QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue), | |
@@ -216,10 +217,6 class IssueQuery < Query | |||||
216 | @available_columns |
|
217 | @available_columns | |
217 | end |
|
218 | end | |
218 |
|
219 | |||
219 | def sortable_columns |
|
|||
220 | {'id' => "#{Issue.table_name}.id"}.merge(super) |
|
|||
221 | end |
|
|||
222 |
|
||||
223 | def default_columns_names |
|
220 | def default_columns_names | |
224 | @default_columns_names ||= begin |
|
221 | @default_columns_names ||= begin | |
225 | default_columns = Setting.issue_list_default_columns.map(&:to_sym) |
|
222 | default_columns = Setting.issue_list_default_columns.map(&:to_sym) |
@@ -28,11 +28,12 class QueryColumn | |||||
28 | end |
|
28 | end | |
29 | self.default_order = options[:default_order] |
|
29 | self.default_order = options[:default_order] | |
30 | @inline = options.key?(:inline) ? options[:inline] : true |
|
30 | @inline = options.key?(:inline) ? options[:inline] : true | |
31 | @caption_key = options[:caption] || "field_#{name}" |
|
31 | @caption_key = options[:caption] || "field_#{name}".to_sym | |
|
32 | @frozen = options[:frozen] | |||
32 | end |
|
33 | end | |
33 |
|
34 | |||
34 | def caption |
|
35 | def caption | |
35 | l(@caption_key) |
|
36 | @caption_key.is_a?(Symbol) ? l(@caption_key) : @caption_key | |
36 | end |
|
37 | end | |
37 |
|
38 | |||
38 | # Returns true if the column is sortable, otherwise false |
|
39 | # Returns true if the column is sortable, otherwise false | |
@@ -48,6 +49,10 class QueryColumn | |||||
48 | @inline |
|
49 | @inline | |
49 | end |
|
50 | end | |
50 |
|
51 | |||
|
52 | def frozen? | |||
|
53 | @frozen | |||
|
54 | end | |||
|
55 | ||||
51 | def value(object) |
|
56 | def value(object) | |
52 | object.send name |
|
57 | object.send name | |
53 | end |
|
58 | end | |
@@ -382,9 +387,10 class Query < ActiveRecord::Base | |||||
382 |
|
387 | |||
383 | def columns |
|
388 | def columns | |
384 | # preserve the column_names order |
|
389 | # preserve the column_names order | |
385 | (has_default_columns? ? default_columns_names : column_names).collect do |name| |
|
390 | cols = (has_default_columns? ? default_columns_names : column_names).collect do |name| | |
386 | available_columns.find { |col| col.name == name } |
|
391 | available_columns.find { |col| col.name == name } | |
387 | end.compact |
|
392 | end.compact | |
|
393 | available_columns.select(&:frozen?) | cols | |||
388 | end |
|
394 | end | |
389 |
|
395 | |||
390 | def inline_columns |
|
396 | def inline_columns |
@@ -9,7 +9,6 | |||||
9 | :onclick => 'toggleIssuesSelection(this); return false;', |
|
9 | :onclick => 'toggleIssuesSelection(this); return false;', | |
10 | :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> |
|
10 | :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> | |
11 | </th> |
|
11 | </th> | |
12 | <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %> |
|
|||
13 | <% query.inline_columns.each do |column| %> |
|
12 | <% query.inline_columns.each do |column| %> | |
14 | <%= column_header(column) %> |
|
13 | <%= column_header(column) %> | |
15 | <% end %> |
|
14 | <% end %> | |
@@ -32,13 +31,12 | |||||
32 | <% end %> |
|
31 | <% end %> | |
33 | <tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> |
|
32 | <tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> | |
34 | <td class="checkbox hide-when-print"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td> |
|
33 | <td class="checkbox hide-when-print"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td> | |
35 | <td class="id"><%= link_to issue.id, issue_path(issue) %></td> |
|
|||
36 | <%= raw query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, issue)}</td>"}.join %> |
|
34 | <%= raw query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, issue)}</td>"}.join %> | |
37 | </tr> |
|
35 | </tr> | |
38 | <% @query.block_columns.each do |column| |
|
36 | <% @query.block_columns.each do |column| | |
39 | if (text = column_content(column, issue)) && text.present? -%> |
|
37 | if (text = column_content(column, issue)) && text.present? -%> | |
40 | <tr class="<%= current_cycle %>"> |
|
38 | <tr class="<%= current_cycle %>"> | |
41 |
<td colspan="<%= @query.inline_columns.size + |
|
39 | <td colspan="<%= @query.inline_columns.size + 1 %>" class="<%= column.css_classes %>"><%= text %></td> | |
42 | </tr> |
|
40 | </tr> | |
43 | <% end -%> |
|
41 | <% end -%> | |
44 | <% end -%> |
|
42 | <% end -%> |
@@ -4,7 +4,7 | |||||
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).collect {|column| [column.caption, column.name]}), |
|
7 | options_for_select((query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}), | |
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> | |
@@ -18,7 +18,7 | |||||
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.collect {|column| [column.caption, column.name]}), |
|
21 | options_for_select((query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}), | |
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> |
@@ -380,7 +380,7 class IssuesControllerTest < ActionController::TestCase | |||||
380 | assert_equal 'text/csv; header=present', @response.content_type |
|
380 | assert_equal 'text/csv; header=present', @response.content_type | |
381 | assert @response.body.starts_with?("#,") |
|
381 | assert @response.body.starts_with?("#,") | |
382 | lines = @response.body.chomp.split("\n") |
|
382 | lines = @response.body.chomp.split("\n") | |
383 |
assert_equal assigns(:query).columns.size |
|
383 | assert_equal assigns(:query).columns.size, lines[0].split(',').size | |
384 | end |
|
384 | end | |
385 |
|
385 | |||
386 | def test_index_csv_with_project |
|
386 | def test_index_csv_with_project | |
@@ -397,7 +397,7 class IssuesControllerTest < ActionController::TestCase | |||||
397 | assert_equal 'text/csv; header=present', @response.content_type |
|
397 | assert_equal 'text/csv; header=present', @response.content_type | |
398 | assert @response.body.starts_with?("#,") |
|
398 | assert @response.body.starts_with?("#,") | |
399 | lines = @response.body.chomp.split("\n") |
|
399 | lines = @response.body.chomp.split("\n") | |
400 |
assert_equal assigns(:query).columns.size + |
|
400 | assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size | |
401 | end |
|
401 | end | |
402 |
|
402 | |||
403 | def test_index_csv_with_spent_time_column |
|
403 | def test_index_csv_with_spent_time_column | |
@@ -416,9 +416,9 class IssuesControllerTest < ActionController::TestCase | |||||
416 | assert_response :success |
|
416 | assert_response :success | |
417 | assert_not_nil assigns(:issues) |
|
417 | assert_not_nil assigns(:issues) | |
418 | assert_equal 'text/csv; header=present', @response.content_type |
|
418 | assert_equal 'text/csv; header=present', @response.content_type | |
419 | assert @response.body.starts_with?("#,") |
|
419 | assert_match /\A#,/, response.body | |
420 |
lines = |
|
420 | lines = response.body.chomp.split("\n") | |
421 |
assert_equal assigns(:query).available_inline_columns.size |
|
421 | assert_equal assigns(:query).available_inline_columns.size, lines[0].split(',').size | |
422 | end |
|
422 | end | |
423 |
|
423 | |||
424 | def test_index_csv_with_multi_column_field |
|
424 | def test_index_csv_with_multi_column_field | |
@@ -708,12 +708,12 class IssuesControllerTest < ActionController::TestCase | |||||
708 | # query should use specified columns |
|
708 | # query should use specified columns | |
709 | query = assigns(:query) |
|
709 | query = assigns(:query) | |
710 | assert_kind_of IssueQuery, query |
|
710 | assert_kind_of IssueQuery, query | |
711 | assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name) |
|
711 | assert_equal [:id, :project, :tracker, :subject, :assigned_to], query.columns.map(&:name) | |
712 | end |
|
712 | end | |
713 |
|
713 | |||
714 | def test_index_without_project_and_explicit_default_columns_should_not_add_project_column |
|
714 | def test_index_without_project_and_explicit_default_columns_should_not_add_project_column | |
715 | Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to'] |
|
715 | Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to'] | |
716 | columns = ['tracker', 'subject', 'assigned_to'] |
|
716 | columns = ['id', 'tracker', 'subject', 'assigned_to'] | |
717 | get :index, :set_filter => 1, :c => columns |
|
717 | get :index, :set_filter => 1, :c => columns | |
718 |
|
718 | |||
719 | # query should use specified columns |
|
719 | # query should use specified columns |
@@ -114,7 +114,7 class QueriesControllerTest < ActionController::TestCase | |||||
114 | assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q |
|
114 | assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q | |
115 | assert !q.is_public? |
|
115 | assert !q.is_public? | |
116 | assert !q.has_default_columns? |
|
116 | assert !q.has_default_columns? | |
117 | assert_equal [:tracker, :subject, :priority, :category], q.columns.collect {|c| c.name} |
|
117 | assert_equal [:id, :tracker, :subject, :priority, :category], q.columns.collect {|c| c.name} | |
118 | assert q.valid? |
|
118 | assert q.valid? | |
119 | end |
|
119 | end | |
120 |
|
120 |
@@ -750,16 +750,34 class QueryTest < ActiveSupport::TestCase | |||||
750 | def test_set_column_names |
|
750 | def test_set_column_names | |
751 | q = IssueQuery.new |
|
751 | q = IssueQuery.new | |
752 | q.column_names = ['tracker', :subject, '', 'unknonw_column'] |
|
752 | q.column_names = ['tracker', :subject, '', 'unknonw_column'] | |
753 | assert_equal [:tracker, :subject], q.columns.collect {|c| c.name} |
|
753 | assert_equal [:id, :tracker, :subject], q.columns.collect {|c| c.name} | |
754 | c = q.columns.first |
|
754 | end | |
755 | assert q.has_column?(c) |
|
755 | ||
|
756 | def test_has_column_should_accept_a_column_name | |||
|
757 | q = IssueQuery.new | |||
|
758 | q.column_names = ['tracker', :subject] | |||
|
759 | assert q.has_column?(:tracker) | |||
|
760 | assert !q.has_column?(:category) | |||
|
761 | end | |||
|
762 | ||||
|
763 | def test_has_column_should_accept_a_column | |||
|
764 | q = IssueQuery.new | |||
|
765 | q.column_names = ['tracker', :subject] | |||
|
766 | ||||
|
767 | tracker_column = q.available_columns.detect {|c| c.name==:tracker} | |||
|
768 | assert_kind_of QueryColumn, tracker_column | |||
|
769 | category_column = q.available_columns.detect {|c| c.name==:category} | |||
|
770 | assert_kind_of QueryColumn, category_column | |||
|
771 | ||||
|
772 | assert q.has_column?(tracker_column) | |||
|
773 | assert !q.has_column?(category_column) | |||
756 | end |
|
774 | end | |
757 |
|
775 | |||
758 | def test_inline_and_block_columns |
|
776 | def test_inline_and_block_columns | |
759 | q = IssueQuery.new |
|
777 | q = IssueQuery.new | |
760 | q.column_names = ['subject', 'description', 'tracker'] |
|
778 | q.column_names = ['subject', 'description', 'tracker'] | |
761 |
|
779 | |||
762 | assert_equal [:subject, :tracker], q.inline_columns.map(&:name) |
|
780 | assert_equal [:id, :subject, :tracker], q.inline_columns.map(&:name) | |
763 | assert_equal [:description], q.block_columns.map(&:name) |
|
781 | assert_equal [:description], q.block_columns.map(&:name) | |
764 | end |
|
782 | end | |
765 |
|
783 |
General Comments 0
You need to be logged in to leave comments.
Login now