Implemented for PostgreSQL only for now. git-svn-id: http://svn.redmine.org/redmine/trunk@17724 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/4.1.0
@@ -128,7 +128,7 @@ module QueriesHelper | |||
items.each do |item| | |||
group_name = group_count = nil | |||
if query.grouped? | |||
group = query.group_by_column.value(item) | |||
group = query.group_by_column.group_value(item) | |||
if first || group != previous_group | |||
if group.blank? && group != false | |||
group_name = "(#{l(:label_blank_value)})" |
@@ -30,7 +30,7 @@ class IssueQuery < Query | |||
QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"), | |||
QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true), | |||
QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), | |||
QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'), | |||
TimestampQueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc', :groupable => true), | |||
QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true), | |||
QueryColumn.new(:fixed_version, :sortable => lambda {Version.fields_for_order_statement}, :groupable => true), | |||
QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date", :groupable => true), | |||
@@ -41,8 +41,8 @@ class IssueQuery < Query | |||
" WHERE subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)", | |||
:default_order => 'desc'), | |||
QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true), | |||
QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'), | |||
QueryColumn.new(:closed_on, :sortable => "#{Issue.table_name}.closed_on", :default_order => 'desc'), | |||
TimestampQueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc', :groupable => true), | |||
TimestampQueryColumn.new(:closed_on, :sortable => "#{Issue.table_name}.closed_on", :default_order => 'desc', :groupable => true), | |||
QueryColumn.new(:last_updated_by, :sortable => lambda {User.fields_for_order_statement("last_journal_user")}), | |||
QueryColumn.new(:relations, :caption => :label_related_issues), | |||
QueryColumn.new(:attachments, :caption => :label_attachment_plural), |
@@ -71,11 +71,31 @@ class QueryColumn | |||
object.send name | |||
end | |||
# Returns the group that object belongs to when grouping query results | |||
def group_value(object) | |||
value(object) | |||
end | |||
def css_classes | |||
name | |||
end | |||
end | |||
class TimestampQueryColumn < QueryColumn | |||
def groupable | |||
if @groupable | |||
Redmine::Database.timestamp_to_date(sortable, User.current.time_zone) | |||
end | |||
end | |||
def group_value(object) | |||
if time = value(object) | |||
User.current.time_to_date(time) | |||
end | |||
end | |||
end | |||
class QueryAssociationColumn < QueryColumn | |||
def initialize(association, attribute, options={}) |
@@ -64,6 +64,19 @@ module Redmine | |||
end | |||
end | |||
# Returns a SQL statement to cast a timestamp column to a date given a time zone | |||
# Returns nil if not implemented for the current database | |||
def timestamp_to_date(column, time_zone) | |||
if postgresql? | |||
if time_zone | |||
identifier = ActiveSupport::TimeZone.find_tzinfo(time_zone.name).identifier | |||
"(#{column}::timestamptz AT TIME ZONE '#{identifier}')::date" | |||
else | |||
"#{column}::date" | |||
end | |||
end | |||
end | |||
# Resets database information | |||
def reset | |||
@postgresql_unaccent = nil |
@@ -303,7 +303,7 @@ module Redmine | |||
issue_list(issues) do |issue, level| | |||
if query.grouped? && | |||
(group = query.group_by_column.value(issue)) != previous_group | |||
(group = query.group_by_column.group_value(issue)) != previous_group | |||
pdf.SetFontStyle('B',10) | |||
group_label = group.blank? ? 'None' : group.to_s.dup | |||
group_label << " (#{result_count_by_group[group]})" |
@@ -352,6 +352,32 @@ class IssuesControllerTest < Redmine::ControllerTest | |||
end | |||
end | |||
def test_index_grouped_by_created_on | |||
skip unless IssueQuery.new.groupable_columns.detect {|c| c.name == :created_on} | |||
get :index, :params => { | |||
:set_filter => 1, | |||
:group_by => 'created_on' | |||
} | |||
assert_response :success | |||
assert_select 'tr.group span.name', :text => '07/19/2006' do | |||
assert_select '+ span.count', :text => '2' | |||
end | |||
end | |||
def test_index_grouped_by_created_on_as_pdf | |||
skip unless IssueQuery.new.groupable_columns.detect {|c| c.name == :created_on} | |||
get :index, :params => { | |||
:set_filter => 1, | |||
:group_by => 'created_on', | |||
:format => 'pdf' | |||
} | |||
assert_response :success | |||
assert_equal 'application/pdf', response.content_type | |||
end | |||
def test_index_with_query_grouped_by_list_custom_field | |||
get :index, :params => { | |||
:project_id => 1, |