Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #72 from alphagov/speed_up_artefacts_index

Speed up artefacts index page
  • Loading branch information...
commit 70d45e53e0b9561c4ba50095f561a423b21b86a7 2 parents ff605f4 + 331479a
@fatbusinessman fatbusinessman authored
View
1  Gemfile
@@ -24,6 +24,7 @@ gem 'rummageable', "~> 0.3.0"
gem "mongoid", "~> 2.4.2"
gem "mongoid_rails_migrations", "1.0.0"
gem "mongo", "1.6.2"
+gem "kaminari", "0.14.1"
gem "bson_ext", "1.6.2"
gem "bson", "1.6.2"
gem 'lograge', '~> 0.1.0'
View
4 Gemfile.lock
@@ -144,6 +144,9 @@ GEM
json (1.7.7)
jwt (0.1.8)
multi_json (>= 1.5)
+ kaminari (0.14.1)
+ actionpack (>= 3.0.0)
+ activesupport (>= 3.0.0)
kgio (2.7.4)
kramdown (0.13.8)
launchy (2.1.2)
@@ -325,6 +328,7 @@ DEPENDENCIES
govuk_content_models (= 4.12.0)
jquery-rails (= 2.0.2)
jquery-ui-rails (= 3.0.1)
+ kaminari (= 0.14.1)
launchy
less-rails-bootstrap
lograge (~> 0.1.0)
View
64 app/assets/stylesheets/application.css
@@ -13,35 +13,6 @@
*= require formtastic-bootstrap
*/
-/* Styling for tablesorter plugin */
-table thead tr th {
- cursor: pointer;
-}
-
-table thead tr th.header {
- padding-right: 20px;
- background: url(bg.gif) no-repeat right 75%;
-}
-
-table thead tr .header.headerSortUp {
- background: url(asc.gif) no-repeat right 75%;
-}
-
-table thead tr .header.headerSortDown {
- background: url(desc.gif) no-repeat right 75%;
-}
-
-table#artefact-list tr.archived {
- opacity: 0.5;
-}
-
-
-tr.top-level-section {
- font-weight: bold;
-}
-
-/* end of tablesorter styling */
-
.related-artefact-group, .curated-artefact-group {
margin-bottom: 10px;
}
@@ -79,3 +50,38 @@ tr.top-level-section {
height: 16px;
background: url(language_cy.png) no-repeat center center;
}
+
+
+/* Pagination tweaks copied from Migratorator */
+.pagination span.current, .pagination span.gap {
+ float: left;
+ padding: 0 14px;
+ line-height: 34px;
+ text-decoration: none;
+ border: 1px solid #DDD;
+ border-left-width: 0;
+}
+.pagination span.current { background: #eee; }
+.pagination span:first-child, .pagination span:first-child a {
+ border-left-width: 1px;
+}
+
+th .asc {
+ background-image: url(/assets/asc.gif);
+ background-color: #eee;
+}
+
+th .desc {
+ background-image: url(/assets/desc.gif);
+ background-color: #eee;
+}
+
+th .current {
+ padding-right: 20px;
+ background-repeat: no-repeat;
+ background-position: right center;
+}
+
+#current td {
+ background-color: #adf;
+}
View
23 app/controllers/artefacts_controller.rb
@@ -3,19 +3,28 @@ class ArtefactsController < ApplicationController
before_filter :build_artefact, :only => [:new, :create]
before_filter :tag_collection, :except => [:show]
helper_method :relatable_items
+ helper_method :sort_column, :sort_direction
respond_to :html, :json
+ ITEMS_PER_PAGE = 100
+
def index
- @section = params[:section] || "all"
+ @section = params[:section].present? ? params[:section] : "all"
if @section != "all"
tags = Tag.where(tag_type: "section", parent_id: @section)
tag_ids = tags.collect {|t| t.tag_id}
tag_ids << @section
- @artefacts = Artefact.any_in(tag_ids: tag_ids).order_by([[:name, :asc]])
+ @artefacts = Artefact.any_in(tag_ids: tag_ids)
else
- @artefacts = Artefact.order_by([[:name, :asc]])
+ @artefacts = Artefact
+ end
+ if params[:filter].present?
+ search = /#{Regexp.escape(params[:filter])}/i
+ @artefacts = @artefacts.any_of({name: search}, {description: search}, {slug: search}, {kind: search}, {owning_app: search})
end
+ @artefacts = @artefacts.order_by([[sort_column, sort_direction]])
+ @artefacts = @artefacts.page(params[:page]).per(ITEMS_PER_PAGE)
respond_with @artefacts, @tag_collection
end
@@ -183,4 +192,12 @@ def build_actions
DiffEnabledAction.new(action, previous)
}
end
+
+ def sort_column
+ Artefact.fields.keys.include?(params[:sort]) ? params[:sort] : :name
+ end
+
+ def sort_direction
+ %w[asc desc].include?(params[:direction]) ? params[:direction] : :asc
+ end
end
View
7 app/helpers/application_helper.rb
@@ -19,4 +19,11 @@ def nav_link(text, link)
end
end
end
+
+ def sortable(column, title = nil)
+ title ||= column.titleize
+ css_class = column == sort_column ? "current #{sort_direction}" : "sortable"
+ direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc"
+ link_to title, params.merge({:sort => column, :direction => direction}), {:class => css_class}
+ end
end
View
5 app/helpers/sections_helper.rb
@@ -55,7 +55,10 @@ def parent_section_tab_list(options)
css_class = "active"
end
content_tag(:li, :class => css_class) do
- link_to(title, :section => tag_id)
+ link_params = { :section => tag_id, :filter => params[:filter] }
+ link_params.reject! { |key, value| value.blank? }
+
+ link_to(title, link_params)
end
end
safe_join(output)
View
36 app/views/artefacts/index.html.erb
@@ -3,7 +3,12 @@
<div class="span12">
<div class="page-header">
- <h1>Artefacts</h1>
+ <h1>
+ Artefacts
+ <% if params[:filter].present? %>
+ filtered for "<%= params[:filter] %>"
+ <% end %>
+ </h1>
</div>
<div class="row-fluid">
@@ -13,23 +18,29 @@
<li class="nav-header">Filter by Section</li>
<%= parent_section_tab_list(:current => @section) %>
</ul>
-
</div>
-
+ <%= form_tag "", method: :get do |f| %>
+ <% if params[:section].present? %>
+ <%= hidden_field_tag :section, params[:section] %>
+ <% end %>
+ <label for="filter" class="visuallyhidden">Filter results</label>
+ <%= text_field_tag "filter", params[:filter], class: "span12", type: "search" %>
+ <input class="btn btn-primary" type="submit" value="Filter">
+ <% end %>
</div>
<div class="span10">
<table class="table table-striped table-bordered table-condensed" id="artefact-list" summary="List of everything">
<thead>
<tr>
- <th scope="col">Need</th>
- <th scope="col">Title</th>
- <th scope="col">Format</th>
+ <th scope="col"><%= sortable "need_id", "Need" %></th>
+ <th scope="col"><%= sortable "name", "Title" %></th>
+ <th scope="col"><%= sortable "kind", "Format" %></th>
<th scope="col">Primary section</th>
<th scope="col">Other sections</th>
<th scope="col">Related items</th>
- <th scope="col">App</th>
- <th scope="col">Slug</th>
+ <th scope="col"><%= sortable "owning_app", "App" %></th>
+ <th scope="col"><%= sortable "slug", "Slug" %></th>
</tr>
</thead>
<tbody>
@@ -50,15 +61,8 @@
<% end %>
</tbody>
</table>
+ <%= paginate @artefacts %>
</div><!-- ./span10 -->
</div><!-- ./row fluid -->
</div><!-- ./span12 -->
</div><!-- ./row-fluid-->
-
-<%= content_for :extra_javascript do %>
- <script type="text/javascript">
- $(function () {
- $('#artefact-list').tablesorter();
- });
- </script>
-<% end %>
View
1  config/application.rb
@@ -4,6 +4,7 @@
require "action_mailer/railtie"
require "rails/test_unit/railtie"
require "sprockets/railtie"
+require 'kaminari' # has to be loaded before the models, otherwise the methods aren't added
require "govuk_content_models"
if defined?(Bundler)
View
41 test/functional/artefacts_controller_test.rb
@@ -28,6 +28,47 @@ class ArtefactsControllerTest < ActionController::TestCase
assert_select "tbody tr td", /crime/i
assert_select "tbody tr td", artefact1.name
end
+
+ should "treat a blank section parameter as 'All'" do
+ artefact1 = FactoryGirl.create(:artefact, name: "Cheese")
+
+ get :index, filter: "cheese", section: ""
+ assert_select "tbody tr", count: 1
+ assert_select "tbody tr td", artefact1.name
+ end
+
+ should "filter by 'filter' parameter" do
+ artefact1 = FactoryGirl.create(:artefact, name: "Cheese")
+ artefact2 = FactoryGirl.create(:artefact, name: "Chalk")
+
+ get :index, filter: "cheese"
+ assert_select "tbody tr", count: 1
+ assert_select "tbody tr td", artefact1.name
+ end
+ end
+
+ should "show links to filter by section" do
+ FactoryGirl.create(:tag, tag_id: "crime", title: "Crime", tag_type: "section")
+
+ get :index
+ assert_select "a[href=/artefacts?section=all]"
+ assert_select "a[href=/artefacts?section=crime]"
+ end
+
+ should "include the filter parameter in section links" do
+ FactoryGirl.create(:tag, tag_id: "crime", title: "Crime", tag_type: "section")
+
+ get :index, filter: "tax"
+ assert_select "a[href=/artefacts?filter=tax&amp;section=all]"
+ assert_select "a[href=/artefacts?filter=tax&amp;section=crime]"
+ end
+
+ should "not include empty filters in section links" do
+ FactoryGirl.create(:tag, tag_id: "crime", title: "Crime", tag_type: "section")
+
+ get :index, filter: ""
+ assert_select "a[href=/artefacts?section=all]"
+ assert_select "a[href=/artefacts?section=crime]"
end
context "GET new" do
Please sign in to comment.
Something went wrong with that request. Please try again.