diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2017-03-16 18:02:43 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2017-03-16 18:02:43 +0000 |
commit | 4cfd5133733a08ebf5ba89aa3994e4a86679c809 (patch) | |
tree | 562cc4d5d11453a058134de4aa95c2c9f121ebf5 | |
parent | 1a180a67be5c205653e5d006fd027c0cafb3b597 (diff) | |
download | redmine-4cfd5133733a08ebf5ba89aa3994e4a86679c809.tar.gz redmine-4cfd5133733a08ebf5ba89aa3994e4a86679c809.zip |
Allow multiple instances of custom queries on My page (#1565).
git-svn-id: http://svn.redmine.org/redmine/trunk@16413 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r-- | app/helpers/my_helper.rb | 51 | ||||
-rw-r--r-- | app/models/user_preference.rb | 6 | ||||
-rw-r--r-- | app/views/my/blocks/_issue_query_selection.html.erb | 21 | ||||
-rw-r--r-- | app/views/my/blocks/_issues.erb | 28 | ||||
-rw-r--r-- | lib/redmine/my_page.rb | 33 | ||||
-rw-r--r-- | test/functional/my_controller_test.rb | 37 |
6 files changed, 114 insertions, 62 deletions
diff --git a/app/helpers/my_helper.rb b/app/helpers/my_helper.rb index 2fa127226..e40ccc27d 100644 --- a/app/helpers/my_helper.rb +++ b/app/helpers/my_helper.rb @@ -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 diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb index e0b17631c..836ad3978 100644 --- a/app/models/user_preference.rb +++ b/app/models/user_preference.rb @@ -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 diff --git a/app/views/my/blocks/_issue_query_selection.html.erb b/app/views/my/blocks/_issue_query_selection.html.erb new file mode 100644 index 000000000..64a3f32af --- /dev/null +++ b/app/views/my/blocks/_issue_query_selection.html.erb @@ -0,0 +1,21 @@ +<% 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> diff --git a/app/views/my/blocks/_issues.erb b/app/views/my/blocks/_issues.erb index 47fb28136..845ef5b85 100644 --- a/app/views/my/blocks/_issues.erb +++ b/app/views/my/blocks/_issues.erb @@ -1,6 +1,3 @@ -<% 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 %> diff --git a/lib/redmine/my_page.rb b/lib/redmine/my_page.rb index dc9c6928f..34195bbcd 100644 --- a/lib/redmine/my_page.rb +++ b/lib/redmine/my_page.rb @@ -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| diff --git a/test/functional/my_controller_test.rb b/test/functional/my_controller_test.rb index 09cb1a834..5e3e9e940 100644 --- a/test/functional/my_controller_test.rb +++ b/test/functional/my_controller_test.rb @@ -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 |