Skip to content

Commit

Permalink
Add state transition widget to show pages.
Browse files Browse the repository at this point in the history
Closes #68, closes #48.
  • Loading branch information
tpendragon committed Aug 9, 2017
1 parent bad484c commit 7dd2b63
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 4 deletions.
3 changes: 3 additions & 0 deletions app/assets/stylesheets/components/form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
margin-left: 0;
}
}
.form-group .radio input.radio_buttons {
margin-left: 0;
}
15 changes: 15 additions & 0 deletions app/change_sets/scanned_resource_change_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ class ScannedResourceChangeSet < Valkyrie::ChangeSet
property :logical_structure, multiple: true, required: false, type: Types::Strict::Array.member(Structure), default: [Structure.new(label: "Logical", nodes: [])]
property :state, multiple: false, required: true, default: BookWorkflow.aasm.initial_state.to_s
property :read_groups, multiple: true, required: false
property :workflow_note, multiple: true, required: false, default: []
# Virtual Attributes
property :refresh_remote_metadata, virtual: true, multiple: false
property :files, virtual: true, multiple: true, required: false
property :pending_uploads, multiple: true, required: false
# Necessary for SimpleForm to show the nested record.
property :new_workflow_note_attributes, virtual: true

validates_with StateValidator
validates_with ViewingDirectionValidator
Expand All @@ -50,6 +53,18 @@ def primary_terms
]
end

def new_workflow_note_attributes=(attributes)
return unless new_workflow_note.validate(attributes)
new_workflow_note.sync
workflow_note << new_workflow_note.model
end

# Default is set this way so that the WorkflowNoteChangeSet validations don't
# show in the nested form.
def new_workflow_note
@new_workflow_note ||= DynamicChangeSet.new(WorkflowNote.new)
end

def visibility=(visibility)
super.tap do |_result|
case visibility
Expand Down
6 changes: 6 additions & 0 deletions app/change_sets/workflow_note_change_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
class WorkflowNoteChangeSet < Valkyrie::ChangeSet
validates :author, :note, presence: true
property :note, multiple: false, required: false
property :author, multiple: false
end
7 changes: 7 additions & 0 deletions app/controllers/catalog_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def self.search_config
config.show.partials = config.show.partials.insert(1, :parent_breadcrumb)
config.show.partials += [:universal_viewer]
config.show.partials += [:resource_attributes]
config.show.partials += [:workflow_controls]
config.index.thumbnail_method = :figgy_thumbnail_path
end

Expand All @@ -49,6 +50,12 @@ def has_search_parameters?
!params[:q].nil? || !params[:f].blank? || !params[:search_field].blank?
end

def show
super
@change_set = DynamicChangeSet.new(@document.resource)
@change_set.prepopulate!
end

def parent_document
return unless params[:parent_id]
_, @parent_document = fetch("id-#{params[:parent_id]}")
Expand Down
10 changes: 10 additions & 0 deletions app/decorators/workflow_note_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true
class WorkflowNoteDecorator < Valkyrie::ResourceDecorator
def note
super.first
end

def author
super.first
end
end
50 changes: 47 additions & 3 deletions app/models/controlled_vocabulary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,57 @@ def notable?
end
end

class BookWorkflow < ControlledVocabulary
include Draper::ViewHelpers
ControlledVocabulary.register(:state_book_workflow, self)

def all(scope = nil)
@all ||=
::BookWorkflow.new(scope.state).valid_transitions.unshift(scope.state).map do |state|
Term.new(label: view_label(state), value: state)
end
end

def view_label(state)
badge(state) + label(state)
end

def badge(state)
h.content_tag(:span, I18n.t("state.#{state}.label"), class: "label #{dom_label_class(state)}")
end

def label(state)
" " + I18n.t("state.#{state}.desc")
end

def dom_label_class(state)
state_classes[state.to_sym] if state
end

def state_classes
@state_classes ||= {
pending: 'label-default',
needs_qa: 'label-info',
metadata_review: 'label-info',
final_review: 'label-primary',
complete: 'label-success',
flagged: 'label-warning',
takedown: 'label-danger',
ready_to_ship: 'label-info',
shipped: 'label-info',
received: 'label-default',
all_in_production: 'label-success'
}
end
end

class RightsStatement < ControlledVocabulary
ControlledVocabulary.register(:rights_statement, self)
def self.authority_config
@authority_config ||= YAML.safe_load(File.read(Rails.root.join("config", "authorities", "rights_statement.yml")), [Symbol])
end

def all
def all(_scope = nil)
@all ||=
self.class.authority_config[:terms].map do |term|
Term.new(term)
Expand All @@ -45,7 +89,7 @@ def all
class PDFType < ControlledVocabulary
ControlledVocabulary.register(:pdf_type, self)

def all
def all(_scope = nil)
[
Term.new(label: 'Color PDF', value: 'color'),
Term.new(label: 'Grayscale PDF', value: 'gray'),
Expand All @@ -58,7 +102,7 @@ def all
class HoldingLocation < ControlledVocabulary
ControlledVocabulary.register(:holding_location, self)

def all
def all(_scope = nil)
json.map do |record|
Term.new(label: record[:label], value: record[:url].gsub('.json', ''))
end
Expand Down
1 change: 1 addition & 0 deletions app/models/scanned_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ScannedResource < Valhalla::Resource
attribute :state
attribute :logical_structure, Valkyrie::Types::Array.member(Structure.optional).optional
attribute :pending_uploads, Valkyrie::Types::Array.member(PendingUpload)
attribute :workflow_note, Valkyrie::Types::Array.member(WorkflowNote).optional

def to_s
"#{human_readable_type}: #{title.to_sentence}"
Expand Down
6 changes: 6 additions & 0 deletions app/models/workflow_note.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
class WorkflowNote < Valhalla::Resource
attribute :id, Valkyrie::Types::ID.optional
attribute :author
attribute :note
end
37 changes: 37 additions & 0 deletions app/views/catalog/_workflow_controls_default.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<% if can?(:edit, resource) && @change_set.respond_to?(:workflow_class) %>
<div id="workflow_controls"class="panel panel-default workflow-affix">
<div class="panel-heading">
<h2 class="panel-title">Review and Approval</h2>
</div>
<div id="workflow_controls_collapse" class="row panel-body">
<%= simple_form_for @change_set do |f| %>
<div class="col-sm-6 workflow-actions">
<h3>Actions</h3>

<%= f.input :state, as: :radio_buttons,
collection: ControlledVocabulary.for(:"state_#{f.object.workflow_class.to_s.underscore}").all(f.object),
required: f.object.required?(:state),
label_method: :label,
value_method: :value,
label: false %>
</div>
<div class="col-sm-6 workflow-comments">
<%= f.simple_fields_for :new_workflow_note do |note| %>
<%= note.input :note, as: :text, required: note.object.required?(:note), label: "Review comment" %>
<%= note.input :author, as: :hidden, input_html: { value: current_user.uid }, required: note.object.required?(:author) %>
<% end %>

<input class="btn btn-primary" type="submit" value="Submit">

<h4>Previous Comments</h4>
<dl>
<% @change_set.workflow_note.map(&:decorate).each do |comment| %>
<dt><%= comment.author %></dt>
<dd><%= comment.note %></dd>
<% end %>
</dl>
</div>
<% end %>
</div>
</div>
<% end %>
34 changes: 34 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,37 @@ en:
q:
label: 'Search'
placeholder: 'Enter search terms'
state:
pending:
label: 'Pending'
desc: 'Initial digitization, suppressed from display'
metadata_review:
label: 'Metadata Review'
desc: 'Awaiting metadata approval'
final_review:
label: 'Final Review'
desc: 'Awaiting final approval before being published'
complete:
label: 'Complete'
desc: 'Published and accessible according to access control rules'
needs_qa:
label: 'Needs QA'
desc: 'Awaiting approval for images to be public.'
flagged:
label: 'Flagged'
desc: 'In need of attention, but still accessible according to access rules'
takedown:
label: 'Takedown'
desc: 'Formerly-published but suppressed from display'
ready_to_ship:
label: 'Ready to Ship'
desc: 'Ready to ship.'
shipped:
label: 'Shipped'
desc: 'Shipped'
received:
label: 'Received'
desc: 'Received'
all_in_production:
label: 'All in Production'
desc: 'Mark all contained folders as having received QA, and put them into the public display.'
15 changes: 14 additions & 1 deletion spec/controllers/catalog_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
end
render_views
it "renders administration buttons" do
resource = persister.save(resource: FactoryGirl.build(:scanned_resource))
resource = persister.save(resource: FactoryGirl.build(:scanned_resource, workflow_note: WorkflowNote.new(author: "Shakespeare", note: "Test Comment")))

get :show, params: { id: "id-#{resource.id}" }

Expand All @@ -139,6 +139,9 @@
expect(response.body).to have_link "Edit Structure", href: structure_scanned_resource_path(resource)
expect(response.body).to have_button "Attach Child"
expect(response.body).to have_link "Attach Scanned Resource", href: parent_new_scanned_resource_path(resource)
expect(response.body).to have_content "Review and Approval"
expect(response.body).to have_content "Shakespeare"
expect(response.body).to have_content "Test Comment"
end

it "renders for a FileSet" do
Expand All @@ -161,6 +164,16 @@
expect(response.body).not_to have_link "File Manager"
end
end
context "when rendered for a user" do
render_views
it "doesn't render the workflow panel" do
resource = persister.save(resource: FactoryGirl.build(:complete_open_scanned_resource))

get :show, params: { id: "id-#{resource.id}" }

expect(response.body).not_to have_content "Review and Approval"
end
end
end

describe "#has_search_parameters?" do
Expand Down
25 changes: 25 additions & 0 deletions spec/controllers/scanned_resources_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,31 @@

expect(response).to render_template "valhalla/base/edit"
end
it "can create a workflow note" do
scanned_resource = FactoryGirl.create_for_repository(:scanned_resource)

patch :update, params: { id: scanned_resource.id.to_s, scanned_resource: { new_workflow_note_attributes: { note: "Test", author: "Shakespeare" } } }

reloaded = find_resource(scanned_resource.id)
expect(reloaded.workflow_note.first.author).to eq ["Shakespeare"]
expect(reloaded.workflow_note.first.note).to eq ["Test"]
end
it "doesn't create a workflow note with an empty note" do
scanned_resource = FactoryGirl.create_for_repository(:scanned_resource)

patch :update, params: { id: scanned_resource.id.to_s, scanned_resource: { new_workflow_note_attributes: { author: "Test" } } }

reloaded = find_resource(scanned_resource.id)
expect(reloaded.workflow_note).to be_blank
end
it "doesn't create a workflow note without an author" do
scanned_resource = FactoryGirl.create_for_repository(:scanned_resource)

patch :update, params: { id: scanned_resource.id.to_s, scanned_resource: { new_workflow_note_attributes: { note: "Test" } } }

reloaded = find_resource(scanned_resource.id)
expect(reloaded.workflow_note).to be_blank
end
end
end

Expand Down

0 comments on commit 7dd2b63

Please sign in to comment.