mirror of
https://github.com/redmine/redmine.git
synced 2025-11-08 06:15:59 +01:00
Adds Watcher list to the list of available query columns for issues (#29894).
Patch by Felix Schäfer (@felix). git-svn-id: https://svn.redmine.org/redmine/trunk@22793 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -292,10 +292,11 @@ tr.project.closed, tr.project.archived { color: #aaa; }
|
|||||||
tr.project.closed a, tr.project.archived a { color: #aaa; }
|
tr.project.closed a, tr.project.archived a { color: #aaa; }
|
||||||
|
|
||||||
tr.issue { text-align: center; white-space: nowrap; }
|
tr.issue { text-align: center; white-space: nowrap; }
|
||||||
tr.issue td.subject, tr.issue td.parent-subject, tr.issue td.category, td.assigned_to, td.last_updated_by, tr.issue td.string, tr.issue td.text, tr.issue td.list, tr.issue td.relations, tr.issue td.parent { white-space: normal; }
|
tr.issue td.subject, tr.issue td.parent-subject, tr.issue td.category, td.assigned_to, td.last_updated_by, tr.issue td.string, tr.issue td.text, tr.issue td.list, tr.issue td.relations, tr.issue td.parent, tr.issue td.watcher_users { white-space: normal; }
|
||||||
tr.issue td.relations { text-align: left; }
|
tr.issue td.relations { text-align: left; }
|
||||||
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
|
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
|
||||||
tr.issue td.relations span {white-space: nowrap;}
|
tr.issue td.relations span, tr.issue td.watcher_users a {white-space: nowrap;}
|
||||||
|
tr.issue td.watcher_users ul {list-style: none; padding: 0; margin: 0}
|
||||||
table.issues td.block_column {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
|
table.issues td.block_column {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
|
||||||
table.issues td.block_column span {font-weight: bold; display: block; margin-bottom: 4px;}
|
table.issues td.block_column span {font-weight: bold; display: block; margin-bottom: 4px;}
|
||||||
table.issues td.block_column pre {white-space:normal;}
|
table.issues td.block_column pre {white-space:normal;}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ tr.project.idnt-7 td.name {padding-left:0; padding-right:9.5em;}
|
|||||||
tr.project.idnt-8 td.name {padding-left:0; padding-right:11em;}
|
tr.project.idnt-8 td.name {padding-left:0; padding-right:11em;}
|
||||||
tr.project.idnt-9 td.name {padding-left:0; padding-right:12.5em;}
|
tr.project.idnt-9 td.name {padding-left:0; padding-right:12.5em;}
|
||||||
|
|
||||||
tr.issue td.subject, tr.issue td.relations { text-align:right; }
|
tr.issue td.subject, tr.issue td.relations, tr.issue td.watcher_users { text-align:right; }
|
||||||
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
|
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
|
||||||
|
|
||||||
table.issues td.description {padding:4px 24px 4px 4px; text-align:right;}
|
table.issues td.description {padding:4px 24px 4px 4px; text-align:right;}
|
||||||
|
|||||||
@@ -277,6 +277,8 @@ module QueriesHelper
|
|||||||
link_to_if(value > 0, format_hours(value), project_time_entries_path(item.project, :issue_id => "~#{item.id}"))
|
link_to_if(value > 0, format_hours(value), project_time_entries_path(item.project, :issue_id => "~#{item.id}"))
|
||||||
when :attachments
|
when :attachments
|
||||||
value.to_a.map {|a| format_object(a)}.join(" ").html_safe
|
value.to_a.map {|a| format_object(a)}.join(" ").html_safe
|
||||||
|
when :watcher_users
|
||||||
|
content_tag('ul', value.to_a.map {|user| content_tag('li', format_object(user))}.join.html_safe)
|
||||||
else
|
else
|
||||||
format_object(value)
|
format_object(value)
|
||||||
end
|
end
|
||||||
@@ -300,6 +302,8 @@ module QueriesHelper
|
|||||||
case column.name
|
case column.name
|
||||||
when :attachments
|
when :attachments
|
||||||
value.to_a.map {|a| a.filename}.join("\n")
|
value.to_a.map {|a| a.filename}.join("\n")
|
||||||
|
when :watcher_users
|
||||||
|
value.to_a.join("\n")
|
||||||
else
|
else
|
||||||
format_object(value, false) do |value|
|
format_object(value, false) do |value|
|
||||||
case value.class.name
|
case value.class.name
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class IssueQuery < Query
|
|||||||
QueryColumn.new(:assigned_to,
|
QueryColumn.new(:assigned_to,
|
||||||
:sortable => lambda {User.fields_for_order_statement},
|
:sortable => lambda {User.fields_for_order_statement},
|
||||||
:groupable => true),
|
:groupable => true),
|
||||||
|
WatcherQueryColumn.new(:watcher_users, :caption => :label_issue_watchers),
|
||||||
TimestampQueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on",
|
TimestampQueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on",
|
||||||
:default_order => 'desc', :groupable => true),
|
:default_order => 'desc', :groupable => true),
|
||||||
QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true),
|
QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true),
|
||||||
@@ -404,6 +405,9 @@ class IssueQuery < Query
|
|||||||
if has_custom_field_column?
|
if has_custom_field_column?
|
||||||
scope = scope.preload(:custom_values)
|
scope = scope.preload(:custom_values)
|
||||||
end
|
end
|
||||||
|
if has_column?(:watcher_users)
|
||||||
|
scope = scope.preload(:watcher_users)
|
||||||
|
end
|
||||||
|
|
||||||
issues = scope.to_a
|
issues = scope.to_a
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ class TimestampQueryColumn < QueryColumn
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class WatcherQueryColumn < QueryColumn
|
||||||
|
def value_object(object)
|
||||||
|
return nil unless User.current.allowed_to?(:"view_#{object.class.name.underscore}_watchers", object.try(:project))
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class QueryAssociationColumn < QueryColumn
|
class QueryAssociationColumn < QueryColumn
|
||||||
def initialize(association, attribute, options={})
|
def initialize(association, attribute, options={})
|
||||||
@association = association
|
@association = association
|
||||||
|
|||||||
@@ -402,6 +402,8 @@ module Redmine
|
|||||||
value = " " * level + value
|
value = " " * level + value
|
||||||
when :attachments
|
when :attachments
|
||||||
value = value.to_a.map {|a| a.filename}.join("\n")
|
value = value.to_a.map {|a| a.filename}.join("\n")
|
||||||
|
when :watcher_users
|
||||||
|
value = value.to_a.join("\n")
|
||||||
end
|
end
|
||||||
if value.is_a?(Date)
|
if value.is_a?(Date)
|
||||||
format_date(value)
|
format_date(value)
|
||||||
|
|||||||
@@ -1923,6 +1923,67 @@ class IssuesControllerTest < Redmine::ControllerTest
|
|||||||
assert_include "\"source.rb\npicture.jpg\"", response.body
|
assert_include "\"source.rb\npicture.jpg\"", response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_index_with_watchers_column
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
get(
|
||||||
|
:index,
|
||||||
|
:params => {
|
||||||
|
:c => %w(subject watcher_users),
|
||||||
|
:set_filter => '1',
|
||||||
|
:sort => 'id',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_select 'td.watcher_users'
|
||||||
|
assert_select 'tr#issue-2' do
|
||||||
|
assert_select 'td.watcher_users' do
|
||||||
|
assert_select 'a[href=?]', '/users/1', :text => User.find(1).name
|
||||||
|
assert_select 'a[href=?]', '/users/3', :text => User.find(3).name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_index_with_watchers_column_only_visible_watchers
|
||||||
|
@request.session[:user_id] = 3
|
||||||
|
User.find(3).roles.first.remove_permission! :view_issue_watchers
|
||||||
|
get(
|
||||||
|
:index,
|
||||||
|
:params => {
|
||||||
|
:c => %w(subject watcher_users),
|
||||||
|
:set_filter => '1',
|
||||||
|
:sort => 'id',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_select 'td.watcher_users'
|
||||||
|
assert_select 'tr#issue-2' do
|
||||||
|
assert_select 'td.watcher_users' do
|
||||||
|
assert_select 'a[href=?]', '/users/1', 0
|
||||||
|
# Currently not implemented, see https://www.redmine.org/issues/29894#note-17
|
||||||
|
# You can only know that you are a watcher yourself
|
||||||
|
# assert_select 'a[href=?]', '/users/3', :text => User.find(3).name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_index_with_watchers_column_as_csv
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
get(
|
||||||
|
:index,
|
||||||
|
:params => {
|
||||||
|
:c => %w(subject watcher_users),
|
||||||
|
:set_filter => '1',
|
||||||
|
:sort => 'id',
|
||||||
|
:format => 'csv',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_include "\"#{User.find(1).name}\n#{User.find(3).name}\"", response.body
|
||||||
|
end
|
||||||
|
|
||||||
def test_index_with_estimated_hours_total
|
def test_index_with_estimated_hours_total
|
||||||
Issue.delete_all
|
Issue.delete_all
|
||||||
Issue.generate!(:estimated_hours => '5:30')
|
Issue.generate!(:estimated_hours => '5:30')
|
||||||
|
|||||||
Reference in New Issue
Block a user