# 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
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
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|
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
--- /dev/null
+<% 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>
_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 %>
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'},
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|
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
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