diff --git a/app/controllers/paginable/plans_controller.rb b/app/controllers/paginable/plans_controller.rb
index e9e4311..85c2957 100644
--- a/app/controllers/paginable/plans_controller.rb
+++ b/app/controllers/paginable/plans_controller.rb
@@ -3,20 +3,24 @@
# /paginable/plans/privately_visible/:page
def privately_visible
raise Pundit::NotAuthorizedError unless Paginable::PlanPolicy.new(current_user).privately_visible?
- if params[:page] == 'ALL'
- plans = current_user.active_plans
+ plans = Plan.active(current_user)
+ if params[:search].present?
+ plans = plans.search(params[:search])
+ plans = params[:page] == 'ALL' ? plans.page(1) : plans.page(params[:page])
else
- plans = current_user.active_plans.page(params[:page])
+ plans = params[:page] == 'ALL' ? plans : plans.page(params[:page])
end
paginable_renderise(partial: 'privately_visible', scope: plans)
end
# GET /paginable/plans/organisationally_or_publicly_visible/:page
def organisationally_or_publicly_visible
raise Pundit::NotAuthorizedError unless Paginable::PlanPolicy.new(current_user).organisationally_or_publicly_visible?
- if params[:page] == 'ALL'
- plans = Plan.organisationally_or_publicly_visible(current_user)
+ plans = Plan.organisationally_or_publicly_visible(current_user)
+ if params[:search].present?
+ plans = plans.search(params[:search])
+ plans = params[:page] == 'ALL' ? plans.page(1) : plans.page(params[:page])
else
- plans = Plan.organisationally_or_publicly_visible(current_user).page(params[:page])
+ plans = params[:page] == 'ALL' ? plans : plans.page(params[:page])
end
paginable_renderise(partial: 'organisationally_or_publicly_visible', scope: plans)
end
diff --git a/app/controllers/paginable/themes_controller.rb b/app/controllers/paginable/themes_controller.rb
index 8a4bb30..03d1ec3 100644
--- a/app/controllers/paginable/themes_controller.rb
+++ b/app/controllers/paginable/themes_controller.rb
@@ -4,9 +4,13 @@
# /paginable/themes/index/:page
def index
authorize(Theme)
- themes = params[:page] == 'ALL' ?
- Theme.updated_at_desc :
- Theme.updated_at_desc.page(params[:page])
+ themes = Theme.updated_at_desc
+ if params[:search].present?
+ themes = themes.search(params[:search])
+ themes = params[:page] == 'ALL' ? themes.page(1) : themes.page(params[:page])
+ else
+ themes = params[:page] == 'ALL' ? themes : themes.page(params[:page])
+ end
paginable_renderise(partial: 'index', scope: themes)
end
end
diff --git a/app/controllers/paginable/users_controller.rb b/app/controllers/paginable/users_controller.rb
index 7637573..d840c32 100644
--- a/app/controllers/paginable/users_controller.rb
+++ b/app/controllers/paginable/users_controller.rb
@@ -3,9 +3,13 @@
# /paginable/users/index/:page
def index
authorize User
- users = params[:page] == 'ALL' ?
- current_user.org.users.includes(:roles) :
- current_user.org.users.includes(:roles).page(params[:page])
+ users = current_user.org.users.includes(:roles)
+ if params[:search].present?
+ users = users.search(params[:search])
+ users = params[:page] == 'ALL' ? users.page(1) : users.page(params[:page])
+ else
+ users = params[:page] == 'ALL' ? users : users.page(params[:page])
+ end
paginable_renderise(partial: 'index', scope: users)
end
end
\ No newline at end of file
diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb
index 3bae0a0..38ae6d7 100644
--- a/app/controllers/plans_controller.rb
+++ b/app/controllers/plans_controller.rb
@@ -7,7 +7,7 @@
def index
authorize Plan
- @plans = current_user.active_plans.page(1)
+ @plans = Plan.active(current_user).page(1)
@organisationally_or_publicly_visible = Plan.organisationally_or_publicly_visible(current_user).page(1)
end
diff --git a/app/models/plan.rb b/app/models/plan.rb
index 011c9b1..e09ecb0 100644
--- a/app/models/plan.rb
+++ b/app/models/plan.rb
@@ -54,9 +54,14 @@
# Note that in ActiveRecord::Enum the mappings are exposed through a class method with the pluralized attribute name (e.g visibilities rather than visibility)
scope :publicly_visible, -> { where(:visibility => visibilities[:publicly_visible]).order(:title => :asc) }
+ # Retrieves any plan in which the user has an active role and it is not a reviewer
+ scope :active, -> (user) {
+ includes([:template, :roles]).where({ "roles.active": true, "roles.user_id": user.id }).where(Role.not_reviewer_condition)
+ }
+
# Retrieves any plan organisationally or publicly visible for a given org id
scope :organisationally_or_publicly_visible, -> (user) {
- Plan.includes(:template)
+ includes([:template, :roles])
.where({
visibility: [visibilities[:organisationally_visible], visibilities[:publicly_visible]],
"templates.org_id": user.org_id})
@@ -64,6 +69,11 @@
.order(:title => :asc)
}
+ scope :search, -> (term) {
+ search_pattern = "%#{term}%"
+ joins(:template).where("plans.title LIKE ? OR templates.title LIKE ?", search_pattern, search_pattern)
+ }
+
# Retrieves plan, template, org, phases, sections and questions
scope :overview, -> (id) {
Plan.includes(:phases, :sections, :questions, template: [ :org ]).find(id)
diff --git a/app/models/theme.rb b/app/models/theme.rb
index 5a95c48..9b5fe8e 100644
--- a/app/models/theme.rb
+++ b/app/models/theme.rb
@@ -16,6 +16,11 @@
validates :title, presence: {message: _("can't be blank")}
scope :updated_at_desc, -> { self.all.order(updated_at: 'DESC') }
+
+ scope :search, -> (term) {
+ search_pattern = "%#{term}%"
+ where("title LIKE ? OR description LIKE ?", search_pattern, search_pattern)
+ }
##
# returns the title of the theme
#
diff --git a/app/models/user.rb b/app/models/user.rb
index 3089e93..f6a87ba 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -54,6 +54,11 @@
['grant_permissions', 'modify_templates', 'modify_guidance', 'change_org_details'])
}
+ scope :search, -> (term) {
+ search_pattern = "%#{term}%"
+ where("firstname LIKE ? OR surname LIKE ? OR email LIKE ?", search_pattern, search_pattern, search_pattern)
+ }
+
# EVALUATE CLASS AND INSTANCE METHODS BELOW
#
# What do they do? do they do it efficiently, and do we need them?
diff --git a/app/views/layouts/_paginable.html.erb b/app/views/layouts/_paginable.html.erb
index e899eb1..b16b60b 100644
--- a/app/views/layouts/_paginable.html.erb
+++ b/app/views/layouts/_paginable.html.erb
@@ -3,22 +3,33 @@
# locals: { controller, action, paginable, scope }
%>
-
-
- <%= yield %>
+
+
+
+ <%= render(partial: '/shared/search', locals: { url: url_for(controller: controller, action: action, page: 'ALL') }) %>
+
-
-
-
+
+
+
+ <% if scope.length > 0 %>
+ <%= yield %>
+ <% else %>
+
+ <%= _('There are no records associated') %>
+
+ <% end %>
+
+
+
+
<% total = paginable ? scope.total_count : scope.length %>
- <% if total > Kaminari.config.default_per_page %>
- <% if paginable %>
- <%= link_to(_('View all'), url_for(controller: controller, action: action, page: 'ALL'), { 'data-remote': true }) %>
- <% else %>
- <%= link_to(_('View less'), url_for(controller: controller, action: action, page: 1), { 'data-remote': true }) %>
- <% end %>
+ <% if paginable %>
+ <%= link_to(_('View all'), url_for(controller: controller, action: action, page: 'ALL'), { 'data-remote': true, class: 'view-all' }) %>
+ <% else %>
+ <%= link_to(_('View less'), url_for(controller: controller, action: action, page: 1), { 'data-remote': true }) if total > Kaminari.config.default_per_page %>
<% end %>
@@ -30,4 +41,4 @@
-
\ No newline at end of file
+
diff --git a/app/views/paginable/plans/_organisationally_or_publicly_visible.html.erb b/app/views/paginable/plans/_organisationally_or_publicly_visible.html.erb
index 9075978..65a57dd 100644
--- a/app/views/paginable/plans/_organisationally_or_publicly_visible.html.erb
+++ b/app/views/paginable/plans/_organisationally_or_publicly_visible.html.erb
@@ -9,14 +9,6 @@
- <% if scope.length > TABLE_FILTER_MIN_ROWS %>
-
- |
- <%= render(partial: "shared/table_filter",
- locals: { placeholder: _('Filter plans')}) %>
- |
-
- <% end %>
| <%= _('Project Title') %> |
<%= _('Template') %> |
diff --git a/app/views/paginable/plans/_privately_visible.html.erb b/app/views/paginable/plans/_privately_visible.html.erb
index 93fe83b..cfbce39 100644
--- a/app/views/paginable/plans/_privately_visible.html.erb
+++ b/app/views/paginable/plans/_privately_visible.html.erb
@@ -1,13 +1,6 @@
- <% if scope.length > TABLE_FILTER_MIN_ROWS %>
-
- |
- <%= render(partial: "shared/table_filter", locals: { placeholder: _('Filter plans')}) %>
- |
-
- <% end %>
| <%= _('Project Title') %> |
<%= _('Template') %> |
diff --git a/app/views/paginable/users/_index.html.erb b/app/views/paginable/users/_index.html.erb
index 6b0caa3..2872ca8 100644
--- a/app/views/paginable/users/_index.html.erb
+++ b/app/views/paginable/users/_index.html.erb
@@ -1,67 +1,43 @@
-
-
-
<%= _('List of users') %>
-
- <%= _('Below is a list of users registered for your organisation. You can sort the data by each field.')%>
-
-
-
-
-
-
-
-
-
- <% if scope.count > TABLE_FILTER_MIN_ROWS %>
-
- |
- <%= render(partial: "shared/table_filter",
- locals: {path: admin_index_users_path,
- placeholder: _('Filter users')}) %>
- |
-
- <% end %>
-
- | <%= _('Name') %> |
- <%= _('Email address') %> |
- <%= _('Last logged in') %> |
- <%= _('How many plans?') %> |
- <%= _('Privileges') %> |
-
-
-
- <% scope.each do |user| %>
- <% if !user.nil? then%>
-
- |
- <% if !user.name.nil? %>
- <%= user.name(false) %>
- <% end %>
- |
-
- <%= user.email %>
- |
-
- <% if !user.last_sign_in_at.nil? %>
- <%= l user.last_sign_in_at.to_date, :formats => :short %>
- <% end %>
- |
-
- <% if !user.roles.nil? %>
- <%= user.roles.length %>
- <% end %>
- |
-
- <% unless current_user == user %>
- <% b_label = _('Edit')%>
- <%= link_to b_label, admin_grant_permissions_user_path(user)%>
- <% end %>
- |
-
- <% end %>
- <% end %>
-
-
-
-
-
\ No newline at end of file
+
+
+
+ | <%= _('Name') %> |
+ <%= _('Email address') %> |
+ <%= _('Last logged in') %> |
+ <%= _('How many plans?') %> |
+ <%= _('Privileges') %> |
+
+
+
+ <% scope.each do |user| %>
+ <% if !user.nil? then%>
+
+ |
+ <% if !user.name.nil? %>
+ <%= user.name(false) %>
+ <% end %>
+ |
+
+ <%= user.email %>
+ |
+
+ <% if !user.last_sign_in_at.nil? %>
+ <%= l user.last_sign_in_at.to_date, :formats => :short %>
+ <% end %>
+ |
+
+ <% if !user.roles.nil? %>
+ <%= user.roles.length %>
+ <% end %>
+ |
+
+ <% unless current_user == user %>
+ <% b_label = _('Edit')%>
+ <%= link_to b_label, admin_grant_permissions_user_path(user)%>
+ <% end %>
+ |
+
+ <% end %>
+ <% end %>
+
+
\ No newline at end of file
diff --git a/app/views/shared/_search.html.erb b/app/views/shared/_search.html.erb
new file mode 100644
index 0000000..0b73a2c
--- /dev/null
+++ b/app/views/shared/_search.html.erb
@@ -0,0 +1,11 @@
+<%= form_tag(url, method: :get, remote: true, class: 'form-inline') do %>
+
+ <%= submit_tag(_('Search'), class: 'btn btn-default', style: 'margin-top: 8px;') %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/users/admin_index.html.erb b/app/views/users/admin_index.html.erb
index 21ca2da..0e15e76 100644
--- a/app/views/users/admin_index.html.erb
+++ b/app/views/users/admin_index.html.erb
@@ -1,5 +1,19 @@
-<%= paginable_renderise(
- partial: '/paginable/users/index',
- controller: 'paginable/users',
- action: 'index',
- scope: @users) %>
\ No newline at end of file
+
+
+
<%= _('List of users') %>
+
+ <%= _('Below is a list of users registered for your organisation. You can sort the data by each field.')%>
+
+
+
+
+
+
+ <%= paginable_renderise(
+ partial: '/paginable/users/index',
+ controller: 'paginable/users',
+ action: 'index',
+ scope: @users) %>
+
+
+
\ No newline at end of file
diff --git a/lib/assets/javascripts/utils/paginable.js b/lib/assets/javascripts/utils/paginable.js
index 9abef4a..491382e 100644
--- a/lib/assets/javascripts/utils/paginable.js
+++ b/lib/assets/javascripts/utils/paginable.js
@@ -1,7 +1,21 @@
+import { isValidText } from './isValidInputType';
+
$(() => {
- // Event delegation for paginable class so that any children a[data-remote="true"]
- // now or in future will be handled through this eventListener
- $('.paginable').on('ajax:success', 'a[data-remote="true"]', (e, data) => {
- $(e.target).closest('.paginable').html(data);
+ const onAjaxSuccessHandler = (e, data) => {
+ $(e.target).closest('.paginable').find('.paginable-results').html($(data).find('.paginable-results').children());
+ };
+ $('.paginable-search form[data-remote="true"]').on('ajax:before', e => isValidText($(e.target).find('input[name="search"]').val()));
+ $('.paginable-results').on('ajax:before', (e) => {
+ const target = $(e.target);
+ if (target.hasClass('view-all')) {
+ // Clears out search box when view-all link was triggered
+ $(e.target).closest('.paginable').find('.paginable-search input[name="search"]').val('');
+ }
});
+ // Event listener for Ajax success event in response to search button clicked
+ $('.paginable-search form[data-remote="true"]').on('ajax:success', '', onAjaxSuccessHandler);
+ // Event listener for Ajax success event captured in response to a paginable link clicked.
+ // Note the presence of a selector for on (e.g. a[data-remote="true"]) so that descendant elements
+ // from .paginable-results that are added in future are also automatically handled.
+ $('.paginable-results').on('ajax:success', 'a[data-remote="true"]', onAjaxSuccessHandler);
});