Feature #29482 » 0005-Option-to-switch-between-table-list-and-board-list.patch
app/controllers/projects_controller.rb | ||
---|---|---|
34 | 34 |
helper :issues |
35 | 35 |
helper :queries |
36 | 36 |
include QueriesHelper |
37 |
helper :projects_queries |
|
38 |
include ProjectsQueriesHelper |
|
37 | 39 |
helper :repositories |
38 | 40 |
helper :members |
39 | 41 |
helper :trackers |
... | ... | |
50 | 52 | |
51 | 53 |
respond_to do |format| |
52 | 54 |
format.html { |
53 |
@projects = scope.to_a |
|
55 |
@entry_count = scope.count |
|
56 |
@entry_pages = Paginator.new @entry_count, per_page_option, params['page'] |
|
57 |
@entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).to_a |
|
54 | 58 |
} |
55 | 59 |
format.api { |
56 | 60 |
@offset, @limit = api_offset_and_limit |
... | ... | |
61 | 65 |
projects = scope.reorder(:created_on => :desc).limit(Setting.feeds_limit.to_i).to_a |
62 | 66 |
render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") |
63 | 67 |
} |
68 |
format.csv { |
|
69 |
# Export all entries |
|
70 |
@entries = scope.to_a |
|
71 |
send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'projects.csv') |
|
72 |
} |
|
64 | 73 |
end |
65 | 74 |
end |
66 | 75 |
app/helpers/projects_helper.rb | ||
---|---|---|
158 | 158 |
url = bookmark_project_url(project) |
159 | 159 |
link_to text, url, remote: true, method: method, class: css |
160 | 160 |
end |
161 | ||
162 |
def grouped_project_list(projects, query, &block) |
|
163 |
ancestors = [] |
|
164 |
grouped_query_results(projects, query) do |project, group_name, group_count, group_totals| |
|
165 |
ancestors.pop while ancestors.any? && !project.is_descendant_of?(ancestors.last) |
|
166 |
yield project, ancestors.size, group_name, group_count, group_totals |
|
167 |
ancestors << project unless project.leaf? |
|
168 |
end |
|
169 |
end |
|
161 | 170 |
end |
app/helpers/projects_queries_helper.rb | ||
---|---|---|
1 |
# frozen_string_literal: true |
|
2 | ||
3 |
# Redmine - project management software |
|
4 |
# Copyright (C) 2006-2017 Jean-Philippe Lang |
|
5 |
# |
|
6 |
# This program is free software; you can redistribute it and/or |
|
7 |
# modify it under the terms of the GNU General Public License |
|
8 |
# as published by the Free Software Foundation; either version 2 |
|
9 |
# of the License, or (at your option) any later version. |
|
10 |
# |
|
11 |
# This program is distributed in the hope that it will be useful, |
|
12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
# GNU General Public License for more details. |
|
15 |
# |
|
16 |
# You should have received a copy of the GNU General Public License |
|
17 |
# along with this program; if not, write to the Free Software |
|
18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
19 |
module ProjectsQueriesHelper |
|
20 |
include ApplicationHelper |
|
21 | ||
22 |
def column_value(column, item, value) |
|
23 |
if item.is_a?(Project) |
|
24 |
case column.name |
|
25 |
when :name |
|
26 |
link_to_project(item) + (content_tag('span', '', :class => 'icon icon-user my-project', :title => l(:label_my_projects)) if User.current.member_of?(item)) |
|
27 |
when :short_description |
|
28 |
item.description? ? content_tag('div', textilizable(item, :short_description), :class => "wiki") : '' |
|
29 |
when :homepage |
|
30 |
item.homepage? ? content_tag('div', textilizable(item, :homepage), :class => "wiki") : '' |
|
31 |
when :status |
|
32 |
get_project_status_label[column.value_object(item)] |
|
33 |
when :parent_id |
|
34 |
link_to_project(item.parent) unless item.parent.nil? |
|
35 |
else |
|
36 |
super |
|
37 |
end |
|
38 |
end |
|
39 |
end |
|
40 | ||
41 |
def csv_content(column, item) |
|
42 |
if item.is_a?(Project) |
|
43 |
case column.name |
|
44 |
when :status |
|
45 |
get_project_status_label[column.value_object(item)] |
|
46 |
when :parent_id |
|
47 |
return item.parent.name unless item.parent.nil? |
|
48 |
end |
|
49 |
end |
|
50 |
super |
|
51 |
end |
|
52 | ||
53 |
private |
|
54 | ||
55 |
def get_project_status_label |
|
56 |
{ |
|
57 |
Project::STATUS_ACTIVE => l(:project_status_active), |
|
58 |
Project::STATUS_CLOSED => l(:project_status_closed) |
|
59 |
} |
|
60 |
end |
|
61 |
end |
app/helpers/queries_helper.rb | ||
---|---|---|
120 | 120 |
render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name} |
121 | 121 |
end |
122 | 122 | |
123 |
def available_display_types_tags(query) |
|
124 |
available_display_types = [] |
|
125 |
query.available_display_types.each do |t| |
|
126 |
available_display_types << [l(:"label_display_type_#{t}"), t] |
|
127 |
end |
|
128 |
select_tag('display_type', options_for_select(available_display_types, @query.display_type), :id => 'display_type') |
|
129 |
end |
|
130 | ||
123 | 131 |
def grouped_query_results(items, query, &block) |
124 | 132 |
result_count_by_group = query.result_count_by_group |
125 | 133 |
previous_group, first = false, true |
app/models/project_query.rb | ||
---|---|---|
22 | 22 |
self.queried_class = Project |
23 | 23 |
self.view_permission = :search_project |
24 | 24 | |
25 |
self.available_columns = [] |
|
25 |
self.available_columns = [ |
|
26 |
QueryColumn.new(:name, :sortable => "#{Project.table_name}.name"), |
|
27 |
QueryColumn.new(:status, :sortable => "#{Project.table_name}.status"), |
|
28 |
QueryColumn.new(:short_description, :sortable => "#{Project.table_name}.description", :caption => :field_description), |
|
29 |
QueryColumn.new(:homepage, :sortable => "#{Project.table_name}.homepage"), |
|
30 |
QueryColumn.new(:identifier, :sortable => "#{Project.table_name}.identifier"), |
|
31 |
QueryColumn.new(:parent_id, :sortable => "#{Project.table_name}.lft ASC", :default_order => 'desc', :caption => :field_parent), |
|
32 |
QueryColumn.new(:is_public, :sortable => "#{Project.table_name}.is_public", :groupable => true), |
|
33 |
QueryColumn.new(:created_on, :sortable => "#{Project.table_name}.created_on", :default_order => 'desc') |
|
34 |
] |
|
26 | 35 | |
27 | 36 |
def initialize(attributes=nil, *args) |
28 | 37 |
super attributes |
... | ... | |
48 | 57 |
end |
49 | 58 | |
50 | 59 |
def available_columns |
51 |
[] |
|
60 |
return @available_columns if @available_columns |
|
61 |
@available_columns = self.class.available_columns.dup |
|
62 |
@available_columns += ProjectCustomField.visible. |
|
63 |
map {|cf| QueryAssociationCustomFieldColumn.new(:project, cf) } |
|
64 |
@available_columns |
|
65 |
end |
|
66 | ||
67 |
def available_display_types |
|
68 |
['board', 'list'] |
|
69 |
end |
|
70 | ||
71 |
def default_columns_names |
|
72 |
@default_columns_names ||= [:name, :identifier, :short_description] |
|
73 |
end |
|
74 | ||
75 |
def default_sort_criteria |
|
76 |
[[]] |
|
52 | 77 |
end |
53 | 78 | |
54 | 79 |
def base_scope |
app/models/query.rb | ||
---|---|---|
408 | 408 |
self.column_names = params[:c] || query_params[:column_names] || self.column_names |
409 | 409 |
self.totalable_names = params[:t] || query_params[:totalable_names] || self.totalable_names |
410 | 410 |
self.sort_criteria = params[:sort] || query_params[:sort_criteria] || self.sort_criteria |
411 |
self.display_type = params[:display_type] || query_params[:display_type] || self.display_type |
|
411 | 412 |
self |
412 | 413 |
end |
413 | 414 | |
... | ... | |
982 | 983 |
end |
983 | 984 |
end |
984 | 985 | |
986 |
def display_type |
|
987 |
options[:display_type] || self.available_display_types.first |
|
988 |
end |
|
989 | ||
990 |
def display_type=(type) |
|
991 |
unless type || self.available_display_types.include?(type) |
|
992 |
type = self.available_display_types.first |
|
993 |
end |
|
994 |
options[:display_type] = type |
|
995 |
end |
|
996 | ||
997 |
def available_display_types |
|
998 |
['list'] |
|
999 |
end |
|
1000 | ||
985 | 1001 |
private |
986 | 1002 | |
987 | 1003 |
def grouped_query(&block) |
app/views/projects/_board.html.erb | ||
---|---|---|
1 |
<div id="projects-index"> |
|
2 |
<%= render_project_hierarchy(@entries) %> |
|
3 |
</div> |
app/views/projects/_list.html.erb | ||
---|---|---|
1 |
<div class="autoscroll"> |
|
2 |
<table class="list projects odd-even <%= @query.css_classes %>"> |
|
3 |
<thead> |
|
4 |
<tr> |
|
5 |
<% @query.inline_columns.each do |column| %> |
|
6 |
<%= column_header(@query, column) %> |
|
7 |
<% end %> |
|
8 |
</tr> |
|
9 |
</thead> |
|
10 |
<tbody> |
|
11 |
<% grouped_project_list(entries, @query) do |entry, level, group_name, group_count, group_totals| -%> |
|
12 |
<% if group_name %> |
|
13 |
<% reset_cycle %> |
|
14 |
<tr class="group open"> |
|
15 |
<td colspan="<%= @query.inline_columns.size %>"> |
|
16 |
<span class="expander" onclick="toggleRowGroup(this);"> </span> |
|
17 |
<span class="name"><%= group_name %></span> |
|
18 |
<% if group_count %> |
|
19 |
<span class="count"><%= group_count %></span> |
|
20 |
<% end %> |
|
21 |
<span class="totals"><%= group_totals %></span> |
|
22 |
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", |
|
23 |
"toggleAllRowGroups(this)", :class => 'toggle-all') %> |
|
24 |
</td> |
|
25 |
</tr> |
|
26 |
<% end %> |
|
27 |
<tr id="project-<%= entry.id %>" class="<%= cycle('odd', 'even') %> <%= entry.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> |
|
28 |
<% @query.inline_columns.each do |column| %> |
|
29 |
<%= content_tag('td', column_content(column, entry), :class => column.css_classes) %> |
|
30 |
<% end %> |
|
31 |
</tr> |
|
32 |
<% end -%> |
|
33 |
</tbody> |
|
34 |
</table> |
|
35 |
</div> |
app/views/projects/index.html.erb | ||
---|---|---|
11 | 11 |
<% end %> |
12 | 12 | |
13 | 13 |
<% if @query.valid? %> |
14 |
<% if @projects.empty? %>
|
|
14 |
<% if @entries.empty? %>
|
|
15 | 15 |
<p class="nodata"><%= l(:label_no_data) %></p> |
16 | 16 |
<% else %> |
17 |
<div id="projects-index"> |
|
18 |
<%= render_project_hierarchy(@projects) %> |
|
19 |
</div> |
|
17 |
<%= render :partial => @query.display_type, :locals => { :entries => @entries }%> |
|
18 |
<span class="pagination"><%= pagination_links_full @entry_pages, @entry_count %></span> |
|
20 | 19 |
<% end %> |
21 | 20 |
<% end %> |
22 | 21 |
app/views/queries/_form.html.erb | ||
---|---|---|
29 | 29 |
<% end %> |
30 | 30 | |
31 | 31 |
<fieldset id="options"><legend><%= l(:label_options) %></legend> |
32 |
<p><label for="query_default_columns"><%=l(:label_default_columns)%></label> |
|
32 |
<% if @query.available_display_types.size > 1 %> |
|
33 |
<p><label for='display_type'><%= l(:label_display_type) %></label> |
|
34 |
<%= available_display_types_tags(@query) %> |
|
35 |
</p> |
|
36 |
<% end %> |
|
37 | ||
38 |
<p id ="default_columns"><label for="query_default_columns"><%=l(:label_default_columns)%></label> |
|
33 | 39 |
<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns', |
34 | 40 |
:data => {:disables => "#columns, .block_columns input"} %></p> |
35 | 41 | |
36 | 42 |
<% unless params[:gantt] %> |
37 |
<p><label for="query_group_by"><%= l(:field_group_by) %></label>
|
|
43 |
<p id="group_by"><label id="group_by" for="query_group_by"><%= l(:field_group_by) %></label>
|
|
38 | 44 |
<%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p> |
39 | 45 | |
40 | 46 |
<% unless @query.available_block_columns.empty? %> |
... | ... | |
99 | 105 |
$("input.disable-unless-private").attr('disabled', !private_checked); |
100 | 106 |
}).trigger('change'); |
101 | 107 |
}); |
108 | ||
109 |
$(function ($) { |
|
110 |
$('#display_type').change(function (e) { |
|
111 |
var option = $(e.target).val() |
|
112 |
if (option == 'board') { |
|
113 |
$('fieldset#columns, fieldset#sort, p#default_columns, p#group_by').hide(); |
|
114 |
} else { |
|
115 |
$('fieldset#columns, fieldset#sort, p#default_columns, p#group_by').show(); |
|
116 |
} |
|
117 |
}).change() |
|
118 |
}); |
|
102 | 119 |
<% end %> |
app/views/queries/_query_form.html.erb | ||
---|---|---|
14 | 14 |
<% if @query.available_columns.any? %> |
15 | 15 |
<fieldset id="options" class="collapsible collapsed"> |
16 | 16 |
<legend onclick="toggleFieldset(this);" class="icon icon-collapsed"><%= l(:label_options) %></legend> |
17 |
<div style="display: none;"> |
|
18 |
<table> |
|
17 |
<div class="hidden"> |
|
18 |
<% if @query.available_display_types.size > 1 %> |
|
19 |
<div> |
|
20 |
<span class="field"><label for='display_type'><%= l(:label_display_type) %></label></span> |
|
21 |
<%= available_display_types_tags(@query) %> |
|
22 |
</div> |
|
23 |
<% end %> |
|
24 |
<table id="list" class="<%= 'hidden' if (@query.display_type == 'board') %>"> |
|
19 | 25 |
<% if @query.available_columns.any? %> |
20 | 26 |
<tr> |
21 | 27 |
<td class="field"><%= l(:field_column_names) %></td> |
... | ... | |
65 | 71 |
</div> |
66 | 72 | |
67 | 73 |
<%= error_messages_for @query %> |
74 | ||
75 |
<%= javascript_tag do %> |
|
76 |
$(function ($) { |
|
77 |
$('#display_type').change(function (e) { |
|
78 |
var option = $(e.target).val() |
|
79 |
if (option == 'board') { |
|
80 |
$('table#list').hide(); |
|
81 |
} else { |
|
82 |
$('table#list').show(); |
|
83 |
} |
|
84 | ||
85 |
}) |
|
86 |
}); |
|
87 | ||
88 |
<% end %> |
config/locales/en.yml | ||
---|---|---|
1071 | 1071 |
label_password_char_class_lowercase: lowercase letters |
1072 | 1072 |
label_password_char_class_digits: digits |
1073 | 1073 |
label_password_char_class_special_chars: special characters |
1074 |
label_display_type: Display results as |
|
1075 |
label_display_type_list: List |
|
1076 |
label_display_type_board: Board |
|
1074 | 1077 | |
1075 | 1078 |
button_login: Login |
1076 | 1079 |
button_submit: Submit |
public/stylesheets/application.css | ||
---|---|---|
130 | 130 |
.clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } |
131 | 131 | |
132 | 132 |
.mobile-show {display: none;} |
133 |
.hidden {display: none;} |
|
133 | 134 | |
134 | 135 |
/***** Links *****/ |
135 | 136 |
a, a:link, a:visited{ color: #169; text-decoration: none; } |
... | ... | |
235 | 236 |
table.list th, .table-list-header { background-color:#EEEEEE; padding: 4px; white-space:nowrap; font-weight:bold; } |
236 | 237 |
table.list td {text-align:center; vertical-align:middle; padding-right:10px;} |
237 | 238 |
table.list td.id { width: 2%; text-align: center;} |
238 |
table.list td.name, table.list td.description, table.list td.subject, table.list td.comments, table.list td.roles, table.list td.attachments, table.list td.text {text-align: left;} |
|
239 |
table.list td.name, table.list td.description, table.list td.subject, table.list td.comments, table.list td.roles, table.list td.attachments, table.list td.text, table.list td.short_description {text-align: left;} |
|
240 | ||
239 | 241 |
table.list td.attachments a {display:block;} |
240 | 242 |
table.list td.tick {width:15%} |
241 | 243 |
table.list td.checkbox { width: 15px; padding: 2px 0 0 0; } |
... | ... | |
257 | 259 |
tr.project.closed, tr.project.archived { color: #aaa; } |
258 | 260 |
tr.project.closed a, tr.project.archived a { color: #aaa; } |
259 | 261 | |
260 |
tr.project.idnt td.name span {background: url(../images/arrow_right.png) no-repeat 2px 50%; padding-left: 16px;} |
|
261 |
tr.project.idnt-1 td.name {padding-left: 0.5em;} |
|
262 |
tr.project.idnt-2 td.name {padding-left: 2em;} |
|
263 |
tr.project.idnt-3 td.name {padding-left: 3.5em;} |
|
264 |
tr.project.idnt-4 td.name {padding-left: 5em;} |
|
265 |
tr.project.idnt-5 td.name {padding-left: 6.5em;} |
|
266 |
tr.project.idnt-6 td.name {padding-left: 8em;} |
|
267 |
tr.project.idnt-7 td.name {padding-left: 9.5em;} |
|
268 |
tr.project.idnt-8 td.name {padding-left: 11em;} |
|
269 |
tr.project.idnt-9 td.name {padding-left: 12.5em;} |
|
270 | ||
271 | 262 |
tr.issue { text-align: center; white-space: nowrap; } |
272 | 263 |
tr.issue td.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; } |
273 | 264 |
tr.issue td.relations { text-align: left; } |
... | ... | |
277 | 268 |
table.issues td.block_column span {font-weight: bold; display: block; margin-bottom: 4px;} |
278 | 269 |
table.issues td.block_column pre {white-space:normal;} |
279 | 270 | |
280 |
tr.issue.idnt td.subject {background: url(../images/arrow_right.png) no-repeat 2px 50%;} |
|
281 |
tr.issue.idnt-1 td.subject {padding-left: 24px; background-position: 8px 50%;} |
|
282 |
tr.issue.idnt-2 td.subject {padding-left: 40px; background-position: 24px 50%;} |
|
283 |
tr.issue.idnt-3 td.subject {padding-left: 56px; background-position: 40px 50%;} |
|
284 |
tr.issue.idnt-4 td.subject {padding-left: 72px; background-position: 56px 50%;} |
|
285 |
tr.issue.idnt-5 td.subject {padding-left: 88px; background-position: 72px 50%;} |
|
286 |
tr.issue.idnt-6 td.subject {padding-left: 104px; background-position: 88px 50%;} |
|
287 |
tr.issue.idnt-7 td.subject {padding-left: 120px; background-position: 104px 50%;} |
|
288 |
tr.issue.idnt-8 td.subject {padding-left: 136px; background-position: 120px 50%;} |
|
289 |
tr.issue.idnt-9 td.subject {padding-left: 152px; background-position: 136px 50%;} |
|
271 |
tr.issue.idnt td.subject, tr.project.idnt td.name {background: url(../images/arrow_right.png) no-repeat 2px 50%;}
|
|
272 |
tr.issue.idnt-1 td.subject, tr.project.idnt-1 td.name {padding-left: 24px; background-position: 8px 50%;}
|
|
273 |
tr.issue.idnt-2 td.subject, tr.project.idnt-2 td.name {padding-left: 40px; background-position: 24px 50%;}
|
|
274 |
tr.issue.idnt-3 td.subject, tr.project.idnt-3 td.name {padding-left: 56px; background-position: 40px 50%;}
|
|
275 |
tr.issue.idnt-4 td.subject, tr.project.idnt-4 td.name {padding-left: 72px; background-position: 56px 50%;}
|
|
276 |
tr.issue.idnt-5 td.subject, tr.project.idnt-5 td.name {padding-left: 88px; background-position: 72px 50%;}
|
|
277 |
tr.issue.idnt-6 td.subject, tr.project.idnt-6 td.name {padding-left: 104px; background-position: 88px 50%;}
|
|
278 |
tr.issue.idnt-7 td.subject, tr.project.idnt-7 td.name {padding-left: 120px; background-position: 104px 50%;}
|
|
279 |
tr.issue.idnt-8 td.subject, tr.project.idnt-8 td.name {padding-left: 136px; background-position: 120px 50%;}
|
|
280 |
tr.issue.idnt-9 td.subject, tr.project.idnt-9 td.name {padding-left: 152px; background-position: 136px 50%;}
|
|
290 | 281 | |
291 | 282 |
table.issue-report {table-layout:fixed;} |
292 | 283 |
.issue-report-graph {width: 75%; margin: 2em 0;} |
test/functional/projects_controller_test.rb | ||
---|---|---|
94 | 94 |
end |
95 | 95 |
end |
96 | 96 | |
97 |
def test_index_as_list_should_format_column_value |
|
98 |
get :index, :params => { |
|
99 |
:c => ['name', 'status', 'short_description', 'homepage', 'parent_id', 'identifier', 'is_public', 'created_on', 'project.cf_3'], |
|
100 |
:display_type => 'list' |
|
101 |
} |
|
102 |
assert_response :success |
|
103 | ||
104 |
assert_select 'table.projects' do |
|
105 |
assert_select 'tr[id=?]', 'project-1' do |
|
106 |
assert_select 'td.name a[href=?]', '/projects/ecookbook', :text => 'eCookbook' |
|
107 |
assert_select 'td.status', :text => 'active' |
|
108 |
assert_select 'td.short_description', :text => 'Recipes management application' |
|
109 |
assert_select 'td.homepage a.external', :text => 'http://ecookbook.somenet.foo/' |
|
110 |
assert_select 'td.identifier', :text => 'ecookbook' |
|
111 |
assert_select 'td.is_public', :text => 'Yes' |
|
112 |
assert_select 'td.created_on', :text => '07/19/2006 05:13 PM' |
|
113 |
assert_select 'td.project_cf_3.list', :text => 'Stable' |
|
114 |
end |
|
115 |
assert_select 'tr[id=?]', 'project-4' do |
|
116 |
assert_select 'td.parent_id a[href=?]', '/projects/ecookbook', :text => 'eCookbook' |
|
117 |
end |
|
118 |
end |
|
119 |
end |
|
120 | ||
121 |
def test_index_as_list_should_show_my_favourite_projects |
|
122 |
@request.session[:user_id] = 1 |
|
123 |
get :index, :params => { |
|
124 |
:display_type => 'list' |
|
125 |
} |
|
126 | ||
127 |
assert_response :success |
|
128 |
assert_select 'tr[id=?] td.name span[class=?]', 'project-5', 'icon icon-user my-project' |
|
129 |
end |
|
130 | ||
131 |
def test_index_as_list_should_indent_projects |
|
132 |
@request.session[:user_id] = 1 |
|
133 |
get :index, :params => { |
|
134 |
:c => ['name', 'short_description'], |
|
135 |
:sort => 'parent_id:desc,lft:desc', |
|
136 |
:display_type => 'list' |
|
137 |
} |
|
138 |
assert_response :success |
|
139 | ||
140 |
child_level1 = css_select('tr#project-5').map {|e| e.attr('class')}.first.split(' ') |
|
141 |
child_level2 = css_select('tr#project-6').map {|e| e.attr('class')}.first.split(' ') |
|
142 | ||
143 |
assert_include 'idnt', child_level1 |
|
144 |
assert_include 'idnt-1', child_level1 |
|
145 | ||
146 |
assert_include 'idnt', child_level2 |
|
147 |
assert_include 'idnt-2', child_level2 |
|
148 |
end |
|
149 | ||
97 | 150 |
def test_autocomplete_js |
98 | 151 |
get :autocomplete, :params => { |
99 | 152 |
:format => 'js', |
test/unit/project_query_test.rb | ||
---|---|---|
44 | 44 |
values = query.available_filters['status'][:values] |
45 | 45 |
assert_equal ['active', 'closed'], values.map(&:first) |
46 | 46 |
assert_equal ['1', '5'], values.map(&:second) |
47 |
end |
|
48 | ||
49 |
def test_default_columns |
|
50 |
q = ProjectQuery.new |
|
51 |
assert q.columns.any? |
|
52 |
assert q.inline_columns.any? |
|
53 |
assert q.block_columns.empty? |
|
54 |
end |
|
47 | 55 | |
56 |
def test_available_columns_should_include_project_custom_fields |
|
57 |
query = ProjectQuery.new |
|
58 |
assert_include :"project.cf_3", query.available_columns.map(&:name) |
|
48 | 59 |
end |
49 | 60 |
end |