Project

General

Profile

Feature #33422 » project-query-available-on-admin-project-list.patch

Takenori TAKAKI, 2021-10-07 04:28

View differences:

app/controllers/admin_controller.rb
26 26

  
27 27
  before_action :require_admin
28 28

  
29
  helper :queries
30
  include QueriesHelper
31
  helper :projects_queries
32
  helper :projects
33

  
29 34
  def index
30 35
    @no_configuration_data = Redmine::DefaultData::Loader::no_data?
31 36
  end
32 37

  
33 38
  def projects
34
    @status = params[:status] || 1
35

  
36
    scope = Project.status(@status).sorted
37
    scope = scope.like(params[:name]) if params[:name].present?
39
    retrieve_query(ProjectQuery, false, :defaults => @default_columns_names)
40
    @query.admin_projects = 1
41
    scope = @query.results_scope
38 42

  
39
    @project_count = scope.count
40
    @project_pages = Paginator.new @project_count, per_page_option, params['page']
41
    @projects = scope.limit(@project_pages.per_page).offset(@project_pages.offset).to_a
43
    @entry_count = scope.count
44
    @entry_pages = Paginator.new @entry_count, per_page_option, params['page']
45
    @projects = scope.limit(@entry_pages.per_page).offset(@entry_pages.offset).to_a
42 46

  
43 47
    render :action => "projects", :layout => false if request.xhr?
44 48
  end
app/controllers/queries_controller.rb
52 52
    @query.user = User.current
53 53
    @query.project = @project
54 54
    @query.build_from_params(params)
55
    render :layout => 'admin' if params[:admin_projects]
55 56
  end
56 57

  
57 58
  def create
......
62 63

  
63 64
    if @query.save
64 65
      flash[:notice] = l(:notice_successful_create)
65
      redirect_to_items(:query_id => @query)
66
      redirect_to_items(:query_id => @query, :admin_projects => params[:admin_projects])
66 67
    else
67 68
      render :action => 'new', :layout => !request.xhr?
68 69
    end
69 70
  end
70 71

  
71 72
  def edit
73
    render :layout => 'admin' if params[:admin_projects]
72 74
  end
73 75

  
74 76
  def update
......
76 78

  
77 79
    if @query.save
78 80
      flash[:notice] = l(:notice_successful_update)
79
      redirect_to_items(:query_id => @query)
81
      redirect_to_items(:query_id => @query, :admin_projects => params[:admin_projects])
80 82
    else
81 83
      render :action => 'edit'
82 84
    end
......
110 112
    @query ? @query.queried_class.to_s.underscore.pluralize.to_sym : nil
111 113
  end
112 114

  
115
  def current_menu(project)
116
    super if params[:admin_projects].nil?
117
  end
118

  
113 119
  private
114 120

  
115 121
  def find_query
116 122
    @query = Query.find(params[:id])
123
    @query.admin_projects = params[:admin_projects] if @query.is_a?(ProjectQuery)
117 124
    @project = @query.project
118 125
    render_403 unless @query.editable_by?(User.current)
119 126
  rescue ActiveRecord::RecordNotFound
......
163 170
  end
164 171

  
165 172
  def redirect_to_project_query(options)
166
    redirect_to projects_path(options)
173
    if params[:admin_projects]
174
      redirect_to admin_projects_path(options)
175
    else
176
      redirect_to projects_path(options)
177
    end
167 178
  end
168 179

  
169 180
  # Returns the Query subclass, IssueQuery by default
app/helpers/queries_helper.rb
462 462
    url_params =
463 463
      if controller_name == 'issues'
464 464
        {:controller => 'issues', :action => 'index', :project_id => @project}
465
      elsif controller_name == 'admin' && action_name == 'projects'
466
        {:admin_projects => '1'}
465 467
      else
466 468
        {}
467 469
      end
app/models/project_query.rb
18 18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 19

  
20 20
class ProjectQuery < Query
21
  attr_accessor :admin_projects
21 22
  self.queried_class = Project
22 23
  self.view_permission = :search_project
23 24

  
......
66 67
    add_custom_fields_filters(project_custom_fields)
67 68
  end
68 69

  
70
  def build_from_params(params, defaults={})
71
    query = super
72
    query.admin_projects = params[:admin_projects]
73
    query
74
  end
75

  
69 76
  def available_columns
70 77
    return @available_columns if @available_columns
71 78

  
......
76 83
  end
77 84

  
78 85
  def available_display_types
79
    ['board', 'list']
86
    unless self.admin_projects
87
      ['board', 'list']
88
    else
89
      ['list']
90
    end
91
  end
92

  
93
  def display_type
94
    unless self.admin_projects
95
      super
96
    else
97
      'list'
98
    end
99
  end
100

  
101
  def project_statuses_values
102
    values = super
103
    if self.admin_projects
104
      values.append([l(:project_status_archived), "#{Project::STATUS_ARCHIVED}"])
105
    end
106
    values
80 107
  end
81 108

  
82 109
  def default_columns_names
......
92 119
  end
93 120

  
94 121
  def base_scope
95
    Project.visible.where(statement)
122
    if self.admin_projects
123
      Project.where(statement)
124
    else
125
      Project.visible.where(statement)
126
    end
96 127
  end
97 128

  
98 129
  def results_scope(options={})
app/views/admin/projects.html.erb
2 2
<%= link_to l(:label_project_new), new_project_path, :class => 'icon icon-add' %>
3 3
</div>
4 4

  
5
<%= title l(:label_project_plural) %>
5
<h2><%= @query.new_record? ? l(:label_project_plural) : @query.name %></h2>
6 6

  
7
<%= form_tag({}, :method => :get) do %>
8
<fieldset><legend><%= l(:label_filter_plural) %></legend>
9
<label for='status'><%= l(:field_status) %>:</label>
10
<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;"  %>
11
<label for='name'><%= l(:label_project) %>:</label>
12
<%= text_field_tag 'name', params[:name], :size => 30 %>
13
<%= submit_tag l(:button_apply), :class => "small", :name => nil %>
14
<%= link_to l(:button_clear), admin_projects_path, :class => 'icon icon-reload' %>
15
</fieldset>
7
<%= form_tag(admin_projects_path(@project, nil), :method => :get, :id => 'query_form') do %>
8
<%= hidden_field_tag 'admin_projects', '1' %>
9
<%= render :partial => 'queries/query_form' %>
16 10
<% end %>
17
&nbsp;
18 11

  
19
<% if @projects.any? %>
20
<div class="autoscroll">
21
<table class="list">
22
  <thead><tr>
23
  <th><%=l(:label_project)%></th>
24
  <th><%=l(:field_is_public)%></th>
25
  <th><%=l(:field_created_on)%></th>
26
  <th></th>
27
  </tr></thead>
28
  <tbody>
29
<% project_tree(@projects, :init_level => true) do |project, level| %>
30
  <tr class="<%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>">
31
  <td class="name"><span><%= link_to_project_settings(project, {}, :title => project.short_description) %></span></td>
32
  <td><%= checked_image project.is_public? %></td>
33
  <td><%= format_date(project.created_on) %></td>
34
  <td class="buttons">
35
    <%= link_to(l(:button_archive), archive_project_path(project, :status => params[:status]), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock') unless project.archived? %>
36
    <%= link_to(l(:button_unarchive), unarchive_project_path(project, :status => params[:status]), :method => :post, :class => 'icon icon-unlock') if project.archived? %>
37
    <%= link_to(l(:button_copy), copy_project_path(project), :class => 'icon icon-copy') %>
38
    <%= link_to(l(:button_delete), project_path(project), :method => :delete, :class => 'icon icon-del') %>
39
  </td>
40
  </tr>
12
<% if @query.valid? %>
13
  <%if @projects.any? %>
14
    <%= render :partial => 'projects/list', :locals => { :entries => @projects }%>
15
  <% else %>
16
    <p class="nodata"><%= l(:label_no_data) %></p>
17
  <% end %>
41 18
<% end %>
42
  </tbody>
43
</table>
44
</div>
45
<span class="pagination"><%= pagination_links_full @project_pages, @project_count %></span>
46
<% else %>
47
<p class="nodata"><%= l(:label_no_data) %></p>
19

  
20
<% content_for :sidebar do %>
21
  <%= render :partial => 'projects/sidebar' %>
48 22
<% end %>
app/views/projects/_list.html.erb
6 6
    <% @query.inline_columns.each do |column| %>
7 7
      <%= column_header(@query, column) %>
8 8
    <% end %>
9
    <% if controller_name == 'admin' && action_name == 'projects' %>
10
    <th></th>
11
    <% end %>
9 12
  </tr>
10 13
</thead>
11 14
<tbody>
......
23 26
        <%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}",
24 27
                             "toggleAllRowGroups(this)", :class => 'toggle-all') %>
25 28
      </td>
29
      <% if controller_name == 'admin' && action_name == 'projects' %>
30
      <td></td>
31
      <% end %>
26 32
    </tr>
27 33
  <% end %>
28 34
  <tr id="project-<%= entry.id %>" class="<%= cycle('odd', 'even') %> <%= entry.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>">
29 35
    <% @query.inline_columns.each do |column| %>
30 36
    <%= content_tag('td', column_content(column, entry), :class => column.css_classes) %>
31 37
    <% end %>
38
    <% if controller_name == 'admin' && action_name == 'projects' %>
39
    <td class="buttons">
40
      <%= link_to(l(:button_archive), archive_project_path(entry, :status => params[:status]), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock') unless entry.archived? %>
41
      <%= link_to(l(:button_unarchive), unarchive_project_path(entry, :status => params[:status]), :method => :post, :class => 'icon icon-unlock') if entry.archived? %>
42
      <%= link_to(l(:button_copy), copy_project_path(entry), :class => 'icon icon-copy') %>
43
      <%= link_to(l(:button_delete), project_path(entry), :method => :delete, :class => 'icon icon-del') %>
44
    </td>
45
    <% end %>
32 46
  </tr>
33 47
<% end -%>
34 48
</tbody>
app/views/queries/_form.html.erb
4 4
<div class="tabular">
5 5
<%= hidden_field_tag 'gantt', '1' if params[:gantt] %>
6 6
<%= hidden_field_tag 'calendar', '1' if params[:calendar] %>
7
<%= hidden_field_tag 'admin_projects', '1' if params[:admin_projects] %>
7 8

  
8 9
<p><label for="query_name"><%=l(:field_name)%></label>
9 10
<%= text_field 'query', 'name', :size => 80 %></p>
......
34 35
      <p><label for='display_type'><%= l(:label_display_type) %></label>
35 36
        <%= available_display_types_tags(@query) %>
36 37
      </p>
38
    <% elsif @query.available_display_types.size == 1 %>
39
      <%= hidden_field_tag 'query[display_type]', @query.available_display_types.first %>
37 40
    <% end %>
38 41

  
39 42
    <p id ="default_columns"><label for="query_default_columns"><%=l(:label_default_columns)%></label>
app/views/queries/_query_form.html.erb
63 63
    <% end %>
64 64
  <% else %>
65 65
    <% if @query.editable_by?(User.current) %>
66
      <%= link_to l(:button_edit_object, object_name: l(:label_query).downcase), edit_query_path(@query), :class => 'icon icon-edit' %>
67
      <%= delete_link query_path(@query), {}, l(:button_delete_object, object_name: l(:label_query).downcase) %>
66
      <% redirect_params = (controller_name == 'admin' && action_name == 'projects') ? {:admin_projects => 1} : {} %>
67
      <%= link_to l(:button_edit_object, object_name: l(:label_query).downcase), edit_query_path(@query, redirect_params), :class => 'icon icon-edit' %>
68
      <%= delete_link query_path(@query, redirect_params), {}, l(:button_delete_object, object_name: l(:label_query).downcase) %>
68 69
    <% end %>
69 70
  <% end %>
70 71
</p>
test/functional/admin_controller_test.rb
59 59
    get(
60 60
      :projects,
61 61
      :params => {
62
        :name => 'store',
63
        :status => ''
62
        'set_filte' => '1',
63
        'f'  => ['status', 'name'],
64
        'op' => {'status' => '=', 'name' => '~'},
65
        'v'  => {'status' => ['1'], 'name' => ['store']}
64 66
      }
65 67
    )
66 68
    assert_response :success
test/functional/queries_controller_test.rb
585 585
    assert q.valid?
586 586
  end
587 587

  
588
  def test_create_admin_projects_query_should_redirect_to_admin_projects
589
    @request.session[:user_id] = 1
590

  
591
    q = new_record(ProjectQuery) do
592
      post(
593
        :create,
594
        :params => {
595
          :type => 'ProjectQuery',
596
          :default_columns => '1',
597
          :f => ["status"],
598
          :op => {
599
            "status" => "="
600
          },
601
          :v => {
602
            "status" => ['1']
603
          },
604
          :query => {
605
            "name" => "test_new_project_public_query", "visibility" => "2"
606
          },
607
          :admin_projects => 1
608
        }
609
      )
610
    end
611

  
612
    assert_redirected_to :controller => 'admin', :action => 'projects', :query_id => q.id, :admin_projects => 1
613
  end
614

  
588 615
  def test_edit_global_public_query
589 616
    @request.session[:user_id] = 1
590 617
    get(:edit, :params => {:id => 4})
......
690 717
    assert q.valid?
691 718
  end
692 719

  
720
  def test_update_admin_projects_query
721
    q = ProjectQuery.create(:name => 'project_query')
722
    @request.session[:user_id] = 1
723

  
724
    put(
725
      :update,
726
      :params => {
727
        :id => q.id,
728
        :default_columns => '1',
729
        :fields => ["status"],
730
        :operators => {
731
          "status" => "="
732
        },
733
        :values => {
734
          "status" => ['1']
735
        },
736
        :query => {
737
          "name" => "test_project_query_updated", "visibility" => "2"
738
        },
739
        :admin_projects => 1
740
      }
741
    )
742

  
743
    assert_redirected_to :controller => 'admin', :action => 'projects', :query_id => q.id, :admin_projects => 1
744
    assert Query.find_by_name('test_project_query_updated')
745
  end
746

  
693 747
  def test_update_with_failure
694 748
    @request.session[:user_id] = 1
695 749
    put(
test/unit/project_query_test.rb
61 61
    assert_include :cf_3, query.available_columns.map(&:name)
62 62
  end
63 63

  
64
  def test_available_display_types_should_returns_bord_and_list
65
    query = ProjectQuery.new
66
    query.admin_projects = nil
67
    assert_equal ['board', 'list'], query.available_display_types
68
  end
69

  
70
  def test_available_display_types_should_always_returns_list_when_admin_projects_is_set
71
    query = ProjectQuery.new
72
    query.admin_projects = 1
73
    assert_equal ['list'], query.available_display_types
74
  end
75

  
64 76
  def test_display_type_default_should_equal_with_setting_project_list_display_type
65 77
    ProjectQuery.new.available_display_types.each do |t|
66 78
      with_settings :project_list_display_type => t do
......
69 81
      end
70 82
    end
71 83
  end
84

  
85
  def test_display_type_should_returns_list_when_admin_projects_is_set
86
    q = ProjectQuery.new
87
    q.admin_projects = 1
88
    assert_equal 'list', q.display_type
89
  end
90

  
91
  def test_project_statuses_values_should_equal_ancestors_return
92
    ancestor = Query.new
93
    q = ProjectQuery.new
94
    assert_equal ancestor.project_statuses_values, q.project_statuses_values
95
  end
96

  
97
  def test_project_statuses_values_should_includes_project_status_archeved_when_admin_projects_is_set
98
    q = ProjectQuery.new
99
    q.admin_projects = 1
100
    assert_includes q.project_statuses_values, [l(:project_status_archived), "#{Project::STATUS_ARCHIVED}"]
101
    Query.new.project_statuses_values.each do |status|
102
      assert_includes q.project_statuses_values, status
103
    end
104
  end
105

  
106
  def test_base_scope_should_return_visible_projects
107
    q = ProjectQuery.new
108
    assert_equal Project.visible, q.base_scope
109
  end
110

  
111
  def test_base_scope_should_return_all_projects_when_admin_projects_is_set
112
    q = ProjectQuery.new
113
    q.admin_projects = 1
114
    assert_equal Project.all, q.base_scope
115
  end
72 116
end
(2-2/6)