Commit fc9dc187 authored by jplang's avatar jplang

Allow multiple instances of custom queries on My page (#1565).

git-svn-id: https://svn.redmine.org/redmine/trunk@16413 e93f8b46-1217-0410-a6f0-8f06a7374b81
parent 568c23b9
......@@ -47,26 +47,29 @@ module MyHelper
# Renders a single block content
def render_block_content(block, user)
unless block_definition = Redmine::MyPage.blocks[block]
unless block_definition = Redmine::MyPage.find_block(block)
Rails.logger.warn("Unknown block \"#{block}\" found in #{user.login} (id=#{user.id}) preferences")
return
end
settings = user.pref.my_page_settings(block)
partial = block_definition[:partial]
begin
render(:partial => partial, :locals => {:user => user, :settings => settings, :block => block})
rescue ActionView::MissingTemplate
Rails.logger.warn("Partial \"#{partial}\" missing for block \"#{block}\" found in #{user.login} (id=#{user.id}) preferences")
return nil
if partial = block_definition[:partial]
begin
render(:partial => partial, :locals => {:user => user, :settings => settings, :block => block})
rescue ActionView::MissingTemplate
Rails.logger.warn("Partial \"#{partial}\" missing for block \"#{block}\" found in #{user.login} (id=#{user.id}) preferences")
return nil
end
else
send "render_#{block_definition[:name]}_block", block, settings
end
end
def block_select_tag(user)
disabled = user.pref.my_page_layout.values.flatten
blocks_in_use = user.pref.my_page_layout.values.flatten
options = content_tag('option')
Redmine::MyPage.block_options.each do |label, block|
options << content_tag('option', label, :value => block, :disabled => disabled.include?(block))
Redmine::MyPage.block_options(blocks_in_use).each do |label, block|
options << content_tag('option', label, :value => block, :disabled => block.blank?)
end
select_tag('block', options, :id => "block-select", :onchange => "$('#block-form').submit();")
end
......@@ -88,45 +91,47 @@ module MyHelper
send "#{block}_items", settings
end
def issuesassignedtome_items(settings)
def render_issuesassignedtome_block(block, settings)
query = IssueQuery.new(:name => l(:label_assigned_to_me_issues), :user => User.current)
query.add_filter 'assigned_to_id', '=', ['me']
query.column_names = settings[:columns].presence || ['project', 'tracker', 'status', 'subject']
query.sort_criteria = settings[:sort].presence || [['priority', 'desc'], ['updated_on', 'desc']]
issues = query.issues(:limit => 10)
return issues, query
render :partial => 'my/blocks/issues', :locals => {:query => query, :issues => issues, :block => block}
end
def issuesreportedbyme_items(settings)
def render_issuesreportedbyme_block(block, settings)
query = IssueQuery.new(:name => l(:label_reported_issues), :user => User.current)
query.add_filter 'author_id', '=', ['me']
query.column_names = settings[:columns].presence || ['project', 'tracker', 'status', 'subject']
query.sort_criteria = settings[:sort].presence || [['updated_on', 'desc']]
issues = query.issues(:limit => 10)
return issues, query
render :partial => 'my/blocks/issues', :locals => {:query => query, :issues => issues, :block => block}
end
def issueswatched_items(settings)
def render_issueswatched_block(block, settings)
query = IssueQuery.new(:name => l(:label_watched_issues), :user => User.current)
query.add_filter 'watcher_id', '=', ['me']
query.column_names = settings[:columns].presence || ['project', 'tracker', 'status', 'subject']
query.sort_criteria = settings[:sort].presence || [['updated_on', 'desc']]
issues = query.issues(:limit => 10)
return issues, query
render :partial => 'my/blocks/issues', :locals => {:query => query, :issues => issues, :block => block}
end
def issuequery_items(settings)
def render_issuequery_block(block, settings)
query = IssueQuery.visible.find_by_id(settings[:query_id])
return unless query
query.column_names = settings[:columns] if settings[:columns].present?
query.sort_criteria = settings[:sort] if settings[:sort].present?
issues = query.issues(:limit => 10)
return issues, query
if query
query.column_names = settings[:columns] if settings[:columns].present?
query.sort_criteria = settings[:sort] if settings[:sort].present?
issues = query.issues(:limit => 10)
render :partial => 'my/blocks/issues', :locals => {:query => query, :issues => issues, :block => block, :settings => settings}
else
render :partial => 'my/blocks/issue_query_selection', :locals => {:block => block, :settings => settings}
end
end
def news_items
......
......@@ -109,6 +109,7 @@ class UserPreference < ActiveRecord::Base
self[:my_page_settings] = arg
end
# Removes block from the user page layout
def remove_block(block)
block = block.to_s.underscore
%w(top left right).each do |f|
......@@ -117,9 +118,12 @@ class UserPreference < ActiveRecord::Base
my_page_layout
end
# Adds block to the user page layout
# Returns nil if block is not valid or if it's already
# present in the user page layout
def add_block(block)
block = block.to_s.underscore
return unless Redmine::MyPage.blocks.key?(block)
return unless Redmine::MyPage.valid_block?(block, my_page_layout.values.flatten)
remove_block(block)
# add it on top
......
<% visible_queries = IssueQuery.visible.sorted %>
<h3>
<%= l(:label_issue_plural) %>
</h3>
<div id="<%= block %>-settings">
<%= form_tag(my_page_path, :remote => true) do %>
<div class="box">
<p>
<label>
<%= l(:label_query) %>
<%= select_tag "settings[#{block}][query_id]", content_tag("option") + options_from_collection_for_select(visible_queries, :id, :name, settings[:query_id]) %>
</label>
</p>
</div>
<p>
<%= submit_tag l(:button_save) %>
</p>
<% end %>
</div>
<% issues, query = issues_items(block, settings) %>
<% if query %>
<div class="contextual">
<%= link_to_function l(:label_options), "$('##{block}-settings').toggle();", :class => 'icon-only icon-settings', :title => l(:label_options) %>
</div>
......@@ -42,28 +39,3 @@
_project_issues_path(query.project, query.as_params.merge(:format => 'atom', :key => User.current.rss_key)),
{:title => query.name}) %>
<% end %>
<% else %>
<% visible_queries = IssueQuery.visible.sorted %>
<h3>
<%= l(:label_issue_plural) %>
</h3>
<div id="<%= block %>-settings">
<%= form_tag(my_page_path, :remote => true) do %>
<div class="box">
<p>
<label>
<%= l(:label_query) %>
<%= select_tag 'settings[issuequery][query_id]', content_tag("option") + options_from_collection_for_select(visible_queries, :id, :name, settings[:query_id]) %>
</label>
</p>
</div>
<p>
<%= submit_tag l(:button_save) %>
</p>
<% end %>
</div>
<% end %>
......@@ -20,10 +20,10 @@ module Redmine
include Redmine::I18n
CORE_BLOCKS = {
'issuesassignedtome' => {:label => :label_assigned_to_me_issues, :partial => 'my/blocks/issues'},
'issuesreportedbyme' => {:label => :label_reported_issues, :partial => 'my/blocks/issues'},
'issueswatched' => {:label => :label_watched_issues, :partial => 'my/blocks/issues'},
'issuequery' => {:label => :label_issue_plural, :partial => 'my/blocks/issues'},
'issuesassignedtome' => {:label => :label_assigned_to_me_issues},
'issuesreportedbyme' => {:label => :label_reported_issues},
'issueswatched' => {:label => :label_watched_issues},
'issuequery' => {:label => :label_issue_plural, :max_occurs => 3},
'news' => {:label => :label_news_latest, :partial => 'my/blocks/news'},
'calendar' => {:label => :label_calendar, :partial => 'my/blocks/calendar'},
'documents' => {:label => :label_document_plural, :partial => 'my/blocks/documents'},
......@@ -35,15 +35,36 @@ module Redmine
CORE_BLOCKS.merge(additional_blocks).freeze
end
def self.block_options
def self.block_options(blocks_in_use=[])
options = []
blocks.each do |block, block_options|
indexes = blocks_in_use.map {|n|
if n =~ /\A#{block}(__(\d+))?\z/
$2.to_i
end
}.compact
occurs = indexes.size
block_id = indexes.any? ? "#{block}__#{indexes.max + 1}" : block
disabled = (occurs >= (Redmine::MyPage.blocks[block][:max_occurs] || 1))
block_id = nil if disabled
label = block_options[:label]
options << [l("my.blocks.#{label}", :default => [label, label.to_s.humanize]), block.dasherize]
options << [l("my.blocks.#{label}", :default => [label, label.to_s.humanize]), block_id]
end
options
end
def self.valid_block?(block, blocks_in_use=[])
block.present? && block_options(blocks_in_use).map(&:last).include?(block)
end
def self.find_block(block)
block.to_s =~ /\A(.*?)(__\d+)?\z/
name = $1
blocks.has_key?(name) ? blocks[name].merge(:name => name) : nil
end
# Returns the additional blocks that are defined by plugin partials
def self.additional_blocks
@@additional_blocks ||= Dir.glob("#{Redmine::Plugin.directory}/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file|
......
......@@ -165,6 +165,35 @@ class MyControllerTest < Redmine::ControllerTest
end
end
def test_page_with_multiple_issuequery_blocks
user = User.find(2)
query1 = IssueQuery.create!(:name => 'All issues', :user => user, :column_names => [:tracker, :subject, :status, :assigned_to])
query2 = IssueQuery.create!(:name => 'Other issues', :user => user, :column_names => [:tracker, :subject, :priority])
user.pref.my_page_layout = {'top' => ['issuequery__1', 'issuequery']}
user.pref.my_page_settings = {
'issuequery' => {:query_id => query1.id, :columns => [:subject, :due_date]},
'issuequery__1' => {:query_id => query2.id}
}
user.pref.save!
get :page
assert_response :success
assert_select '#block-issuequery' do
assert_select 'h3', :text => /All issues/
assert_select 'table.issues th', :text => 'Due date'
end
assert_select '#block-issuequery__1' do
assert_select 'h3', :text => /Other issues/
assert_select 'table.issues th', :text => 'Priority'
end
assert_select '#block-select' do
assert_select 'option[value=?]:not([disabled])', 'issuequery__2', :text => 'Issues'
end
end
def test_page_with_all_blocks
blocks = Redmine::MyPage.blocks.keys
preferences = User.find(2).pref
......@@ -348,15 +377,15 @@ class MyControllerTest < Redmine::ControllerTest
end
def test_add_block
post :add_block, :block => 'issuesreportedbyme'
post :add_block, :block => 'issueswatched'
assert_redirected_to '/my/page'
assert User.find(2).pref[:my_page_layout]['top'].include?('issuesreportedbyme')
assert User.find(2).pref[:my_page_layout]['top'].include?('issueswatched')
end
def test_add_block_xhr
xhr :post, :add_block, :block => 'issuesreportedbyme'
xhr :post, :add_block, :block => 'issueswatched'
assert_response :success
assert_include 'issuesreportedbyme', User.find(2).pref[:my_page_layout]['top']
assert_include 'issueswatched', User.find(2).pref[:my_page_layout]['top']
end
def test_add_invalid_block_should_error
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment