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 |