Skip to content

Commit

Permalink
Hyrax-5933 - Review submission support paging (#5999)
Browse files Browse the repository at this point in the history
* Enable optional paging of scope_entities_for_the_user query

* Allow scope_entities_for_the_user to filter by workflow state names

* Switch workflows page over to using separate page requests for tabs. Restructure the response for workflow requests to mirror that of a blacklight response. Add method for getting total number of entities in workflow

* Allow for filtering by title keywords

* Filter entities query by state as well

* Remove ability to query by title, since title is not available during the initial query to get entity ids

* Pass paging parameters down to solr query

* Sort review submission results by date submitted, so there is at least some sense to the ordering

* Remove search form

* Fix rounding error when determining page size

* Switch to double star

---------

Co-authored-by: Rob Kaufman <[email protected]>
Co-authored-by: Chris Colvard <[email protected]>
Co-authored-by: April Rieger <[email protected]>
  • Loading branch information
4 people authored Jun 30, 2023
1 parent 49d6b9c commit c7dad8b
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 94 deletions.
51 changes: 48 additions & 3 deletions app/controllers/hyrax/admin/workflows_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ def index
add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path
add_breadcrumb t(:'hyrax.admin.sidebar.tasks'), '#'
add_breadcrumb t(:'hyrax.admin.sidebar.workflow_review'), request.path

@status_list = actionable_objects.reject(&:published?)
@published_list = actionable_objects.select(&:published?)
assign_action_objects_params
@response = WorkflowResponse.new(actionable_objects.to_a, actionable_objects.total_count, current_page, per_page, under_review?)
end

private
Expand All @@ -30,5 +29,51 @@ def actionable_objects
@actionable_objects ||=
Hyrax::Workflow::ActionableObjects.new(user: current_user)
end

def current_page
@page ||= params.fetch('page', 1).to_i
end

def per_page
@per_page ||= params.fetch('per_page', 10).to_i
end

def assign_action_objects_params
actionable_objects.page = current_page
actionable_objects.per_page = per_page
actionable_objects.workflow_state_filter = (under_review? ? '!' : '') + deposited_workflow_state_name
end

def under_review?
@under_review = params['state'] != 'published'
end

class WorkflowResponse
attr_reader :total_count
attr_reader :current_page
attr_reader :per_page
attr_reader :docs
attr_reader :under_review

def initialize(docs, total_count, page, per_page, under_review)
@docs = docs
@total_count = total_count
@per_page = per_page.to_i
@current_page = page.to_i
@under_review = under_review
end

def total_pages
(total_count.to_f / per_page).ceil
end

def limit_value
docs.length
end

def viewing_under_review?
under_review
end
end
end
end
12 changes: 6 additions & 6 deletions app/services/hyrax/solr_query_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@ def self.document_model
##
# execute the query using a GET request
# @return [Hash] the results returned from solr for the current query
def get
solr_service.get(build)
def get(**args)
solr_service.get(build, **args)
end

##
# execute the solr query and return results
# @return [Hash] the results returned from solr for the current query
def query_result
solr_service.query_result(build)
def query_result(**args)
solr_service.query_result(build, **args)
end

##
# @return [Enumerable<SolrDocument>]
def solr_documents
query_result['response']['docs'].map { |doc| self.class.document_model.new(doc) }
def solr_documents(**args)
query_result(**args)['response']['docs'].map { |doc| self.class.document_model.new(doc) }
end

##
Expand Down
31 changes: 28 additions & 3 deletions app/services/hyrax/workflow/actionable_objects.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,27 @@ class ActionableObjects
# @!attribute [rw] user
# @return [::User]
attr_accessor :user
##
# @!attribute [rw] workflow_state_filter
# @return [String]
attr_accessor :workflow_state_filter
##
# @!attribute [rw] page of results to return, 1 based
# @return [Integer]
attr_accessor :page
##
# @!attribute [rw] per_page number of results in the page
# @return [Integer]
attr_accessor :per_page

##
# @param [::User] user the user whose
def initialize(user:)
# @param [String] optional filter by workstate name
def initialize(user:, workflow_state_filter: nil)
@user = user
@workflow_state_filter = workflow_state_filter
@page = 1
@per_page = 10
end

##
Expand All @@ -34,7 +50,8 @@ def each
ids_and_states = id_state_pairs
return if ids_and_states.none?

docs = Hyrax::SolrQueryService.new.with_ids(ids: ids_and_states.map(&:first)).solr_documents
docs = Hyrax::SolrQueryService.new.with_ids(ids: ids_and_states.map(&:first))
.solr_documents(page: @page, rows: @per_page, sort: 'system_create_dtsi ASC')

docs.each do |solr_doc|
object = ObjectInWorkflowDecorator.new(solr_doc)
Expand All @@ -46,14 +63,22 @@ def each
end
end

##
# @return [Integer] total number of entities selected
def total_count
PermissionQuery.scope_entities_for_the_user(user: user, workflow_state_filter: workflow_state_filter)
.count
end

private

##
# @api private
# @return [Array[String, Sipity::WorkflowState]]
def id_state_pairs
gids_and_states = PermissionQuery
.scope_entities_for_the_user(user: user)
.scope_entities_for_the_user(user: user, page: page, per_page: per_page, workflow_state_filter: workflow_state_filter)
.order(created_at: :asc)
.pluck(:proxy_for_global_id, :workflow_state_id)

return [] if gids_and_states.none?
Expand Down
25 changes: 23 additions & 2 deletions app/services/hyrax/workflow/permission_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def scope_processing_agents_for(user:)
# @return [ActiveRecord::Relation<Sipity::Entity>]
#
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
def scope_entities_for_the_user(user:)
def scope_entities_for_the_user(user:, page: 1, per_page: nil, workflow_state_filter: nil)
entities = Sipity::Entity.arel_table
workflow_state_actions = Sipity::WorkflowStateAction.arel_table
workflow_states = Sipity::WorkflowState.arel_table
Expand Down Expand Up @@ -227,13 +227,34 @@ def scope_entities_for_the_user(user:)
entity_specific_where = where_builder.call(entity_responsibilities).and(
entities[:id].eq(entity_responsibilities[:entity_id])
)
entity_specific_where = filter_by_workflow_state(entity_specific_where, workflow_states, workflow_state_filter) if workflow_state_filter
workflow_specific_where = where_builder.call(workflow_responsibilities)
workflow_specific_where = filter_by_workflow_state(workflow_specific_where, workflow_states, workflow_state_filter) if workflow_state_filter

Sipity::Entity.where(
result = Sipity::Entity.where(
entities[:id].in(entity_specific_joins.where(entity_specific_where))
.or(entities[:id].in(workflow_specific_joins.where(workflow_specific_where)))
)
# Apply paging if provided
if per_page.nil?
result
else
result.page(page).per(per_page)
end
end

# @api private
#
# Append a filter by workflow state name to the provided where builder.
# If the filter begins with a !, it will filter to states not equal to the filter.
def filter_by_workflow_state(where_builder, workflow_states, filter)
if filter.start_with?('!')
where_builder.and(workflow_states[:name].not_eq(filter[1..]))
else
where_builder.and(workflow_states[:name].eq(filter))
end
end

# rubocop:enable Metrics/AbcSize, Metrics/MethodLength

# @api public
Expand Down
9 changes: 9 additions & 0 deletions app/views/hyrax/admin/workflows/_tabs.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<ul class="nav nav-tabs" id="my_nav" role="list">
<li<%= ' class="nav-item"'.html_safe if @response.viewing_under_review? %>>
<%= link_to t('hyrax.admin.workflows.index.tabs.under_review'),
hyrax.admin_workflows_path(state: 'under-review'), class: "nav-link#{' active' if @response.viewing_under_review?}" %>
</li>
<li<%= ' class="nav-item"'.html_safe if !@response.viewing_under_review? %>>
<%= link_to t('hyrax.admin.workflows.index.tabs.published'), hyrax.admin_workflows_path(state: 'published'), class: "nav-link#{' active' if !@response.viewing_under_review?}" %>
</li>
</ul>
129 changes: 53 additions & 76 deletions app/views/hyrax/admin/workflows/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,87 +4,64 @@

<div class="row">
<div class="col-md-12">
<div class="card tabs">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" href="#under-review" role="tab" data-toggle="tab"><%= t('.tabs.under_review') %></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#published" role="tab" data-toggle="tab"><%= t('.tabs.published') %></a>
</li>
</ul>
<div class="tab-content">
<div id="under-review" class="tab-pane show active">
<div class="card labels">
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm table-striped datatable">
<thead>
<tr>
<th width="40%">Work</th>
<th width="20%">Depositor</th>
<th width="20%">Submission Date</th>
<th width="20%">Status</th>
</tr>
</thead>
<tbody>
<% @status_list.each do |document| %>
<tr>
<td>
<%= link_to document, [main_app, document] %>
</td>
<td>
<%= safe_join(document.creator, tag(:br)) %>
</td>
<td>
<%= document.date_modified %>
</td>
<td>
<span class="state state-pending"><%= document.workflow_state %></span>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
<div class="tabs">
<%= render 'tabs' %>
<div class="card">
<div class="card-header">
<span class="count-display">
<% if @response.viewing_under_review? %>
<%= I18n.t('hyrax.admin.workflows.index.works_under_review', total_count: @response.total_count).html_safe %>
<% else %>
<%= I18n.t('hyrax.admin.workflows.index.works_published', total_count: @response.total_count).html_safe %>
<% end %>
</span>
</div>
<div id="published" class="tab-pane">
<div class="card labels">
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm table-striped datatable">
<thead>
<tr>
<th width="40%">Work</th>
<th width="20%">Depositor</th>
<th width="20%">Submission Date</th>
<th width="20%">Status</th>
</tr>
</thead>
<tbody>
<% @published_list.each do |document| %>
<tr>
<td>
<%= link_to document, [main_app, document] %>
</td>
<td>
<%= safe_join(document.creator, tag(:br)) %>
</td>
<td>
<%= document.date_modified %>
</td>
<td>
<span class="state state-pending"><%= document.workflow_state %></span>
</td>
</tr>
<div class="card-body">
<div class="row">
<div class="col-sm-12">
<div class="sort-toggle mt-2">
<%= form_tag hyrax.admin_workflows_path, method: :get, class: 'per_page' do %>
<fieldset class="col-12">
<legend class="sr-only"><%= t('hyrax.dashboard.my.sr.results_per_page') %></legend>
<%= label_tag :per_page do %>
Show <%= select_tag :per_page, options_for_select(Hyrax.config.range_for_number_of_results_to_display_per_page.map(&:to_s), h(params[:per_page])), title: "entries" %> per page
<% end %>
</tbody>
</table>
<%= render Blacklight::HiddenSearchStateComponent.new(params: search_state.params_for_search.except(:per_page, :sort, :utf8)) %>
</fieldset>
<% end %>
</div>
</div>
</div>
<h2 class="sr-only"><%= t('.works_listing') %></h2>
<table class="table table-sm table-striped works-list">
<thead>
<tr>
<th width="40%"><%= t(".heading.work") %></th>
<th width="20%"><%= t(".heading.depositor") %></th>
<th width="20%"><%= t(".heading.submission_date") %></th>
<th width="20%"><%= t(".heading.status") %></th>
</tr>
</thead>
<tbody>
<% @response.docs.each do |document| %>
<tr>
<td>
<%= link_to document, [main_app, document] %>
</td>
<td>
<%= safe_join(document.creator, tag(:br)) %>
</td>
<td>
<%= document.date_modified %>
</td>
<td>
<span class="state state-pending"><%= document.workflow_state %></span>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= render 'hyrax/my/results_pagination' %>
</div>
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions config/locales/hyrax.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,14 @@ en:
workflows:
index:
header: Review Submissions
heading:
work: Work
depositor: Depositor
submission_date: Submission Date
status: status
works_published: "<strong>%{total_count} works</strong> published"
works_under_review: "<strong>%{total_count} works</strong> under review"
works_listing: Works listing
tabs:
published: Published
under_review: Under Review
Expand Down
24 changes: 22 additions & 2 deletions spec/controllers/hyrax/admin/workflows_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,28 @@

get :index
expect(response).to be_successful
expect(assigns[:status_list]).to respond_to(:each)
expect(assigns[:published_list]).to respond_to(:each)
expect(assigns[:response].docs).to respond_to(:each)
expect(assigns[:response].total_pages).to eq 0
expect(assigns[:response].limit_value).to eq 0
expect(assigns[:response].current_page).to eq 1
expect(assigns[:response].per_page).to eq 10
expect(assigns[:response].viewing_under_review?).to be_truthy
end

it "is successful with parameters provided" do
expect(controller).to receive(:add_breadcrumb).with('Home', root_path)
expect(controller).to receive(:add_breadcrumb).with('Dashboard', dashboard_path)
expect(controller).to receive(:add_breadcrumb).with('Tasks', '#')
expect(controller).to receive(:add_breadcrumb).with('Review Submissions', "/admin/workflows")

get :index, params: { state: 'published', per_page: '50', page: 2 }
expect(response).to be_successful
expect(assigns[:response].docs).to respond_to(:each)
expect(assigns[:response].total_pages).to eq 0
expect(assigns[:response].limit_value).to eq 0
expect(assigns[:response].current_page).to eq 2
expect(assigns[:response].per_page).to eq 50
expect(assigns[:response].viewing_under_review?).to be_falsey
end
end
end
Loading

0 comments on commit c7dad8b

Please sign in to comment.