curation_concerns 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile +1 -1
  4. data/Rakefile +3 -11
  5. data/VERSION +1 -1
  6. data/app/assets/javascripts/curation_concerns/application.js +3 -0
  7. data/app/assets/javascripts/curation_concerns/curation_concerns.js +5 -0
  8. data/app/assets/javascripts/curation_concerns/file_manager/affix.es6 +13 -0
  9. data/app/assets/javascripts/curation_concerns/file_manager/list_toggle.es6 +6 -0
  10. data/app/assets/javascripts/curation_concerns/file_manager/member.es6 +82 -0
  11. data/app/assets/javascripts/curation_concerns/file_manager/save_manager.es6 +70 -0
  12. data/app/assets/javascripts/curation_concerns/file_manager/sorting.es6 +82 -0
  13. data/app/assets/stylesheets/curation_concerns/_modules.scss +1 -1
  14. data/app/assets/stylesheets/curation_concerns/_typography.scss +0 -11
  15. data/app/assets/stylesheets/curation_concerns/modules/file_manager.scss +115 -0
  16. data/app/controllers/concerns/curation_concerns/collections_controller_behavior.rb +1 -1
  17. data/app/controllers/concerns/curation_concerns/curation_concern_controller.rb +5 -1
  18. data/app/forms/curation_concerns/forms/work_form.rb +3 -1
  19. data/app/views/catalog/_document_list.html.erb +1 -1
  20. data/app/views/collections/_search_collection_dashboard_form.html.erb +1 -1
  21. data/app/views/collections/_search_form.html.erb +1 -1
  22. data/app/views/collections/show.html.erb +24 -17
  23. data/app/views/curation_concerns/base/_file_manager_actions.html.erb +3 -0
  24. data/app/views/curation_concerns/base/_file_manager_attributes.html.erb +0 -0
  25. data/app/views/curation_concerns/base/_file_manager_extra_tools.html.erb +0 -0
  26. data/app/views/curation_concerns/base/_file_manager_member.html.erb +31 -0
  27. data/app/views/curation_concerns/base/_file_manager_thumbnail.html.erb +1 -0
  28. data/app/views/curation_concerns/base/_show_actions.html.erb +1 -0
  29. data/app/views/curation_concerns/base/file_manager.html.erb +34 -0
  30. data/app/views/shared/_site_search.html.erb +3 -3
  31. data/config/locales/curation_concerns.en.yml +2 -0
  32. data/curation_concerns.gemspec +2 -0
  33. data/lib/curation_concerns/engine.rb +1 -0
  34. data/lib/curation_concerns/rails/routes.rb +5 -0
  35. data/lib/curation_concerns/version.rb +1 -1
  36. data/spec/actors/curation_concerns/work_actor_spec.rb +21 -5
  37. data/spec/controllers/curation_concerns/collections_controller_spec.rb +9 -0
  38. data/spec/controllers/curation_concerns/generic_works_controller_spec.rb +24 -4
  39. data/spec/javascripts/file_manager_member_spec.coffee +87 -0
  40. data/spec/javascripts/fixtures/.gitkeep +0 -0
  41. data/spec/javascripts/fixtures/file_manager_member.html +40 -0
  42. data/spec/javascripts/fixtures/save_button.html +3 -0
  43. data/spec/javascripts/helpers/jasmine-jquery.js +841 -0
  44. data/spec/javascripts/helpers/mock-ajax.js +736 -0
  45. data/spec/javascripts/helpers/test_responses.js +12 -0
  46. data/spec/javascripts/jasmine_spec.rb +25 -0
  47. data/spec/javascripts/save_manager_spec.coffee +84 -0
  48. data/spec/javascripts/support/jasmine.yml +136 -0
  49. data/spec/javascripts/support/jasmine_helper.rb +15 -0
  50. data/spec/routing/route_spec.rb +4 -0
  51. data/spec/support/rake_support.rb +41 -0
  52. data/spec/views/catalog/index.html.erb_spec.rb +2 -2
  53. data/spec/views/curation_concerns/base/file_manager.html.erb_spec.rb +72 -0
  54. data/tasks/jasmine.rake +18 -0
  55. metadata +71 -4
@@ -0,0 +1,34 @@
1
+ <h1><%= t("file_manager.link_text") %></h1>
2
+ <ul class="breadcrumb">
3
+ <li>
4
+ Back to <%= link_to @presenter.to_s, [main_app, @presenter] %>
5
+ </li>
6
+ </ul>
7
+
8
+ <% if !@presenter.file_presenters.empty? %>
9
+ <div data-action="file-manager">
10
+ <div class="col-md-3" id="file-manager-tools">
11
+ <h2>Toolbar</h2>
12
+ <%= render "file_manager_actions" %>
13
+ </div>
14
+ <div class="col-md-3" id="label-tools-spacer" class="fixed"></div>
15
+ <div class="col-md-9" id="order-grid">
16
+ <div class="btn-group" role="group" data-action="list-toggle">
17
+ <button type="button" class="btn btn-default list" aria-label="List">
18
+ <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
19
+ </button>
20
+ <button type="button" class="btn btn-default active grid" aria-label="Grid">
21
+ <span class="glyphicon glyphicon-th" aria-hidden="true"></span>
22
+ </button>
23
+ </div>
24
+ <ul id="sortable" data-id="<%= @presenter.id %>" data-class-name="<%= @presenter.model_name.plural %>" data-singular-class-name="<%= @presenter.model_name.singular %>" class="list-unstyled grid">
25
+ <% @presenter.file_presenters.each do |member| %>
26
+ <%= render "file_manager_member", node: member %>
27
+ <% end %>
28
+ </ul>
29
+ </div>
30
+ </div>
31
+ <% end %>
32
+ <div id="file-manager-extra-tools">
33
+ <%= render "file_manager_extra_tools" %>
34
+ </div>
@@ -1,12 +1,12 @@
1
1
  <%= form_tag main_app.search_catalog_path, method: :get, class: "search-form" do %>
2
2
  <fieldset>
3
- <legend class="accessible-hidden">Search <%= t('curation_concerns.product_name') %></legend>
4
- <%= label_tag :catalog_search, t('curation_concerns.search.form.q.label'), class: "accessible-hidden" %>
3
+ <legend class="sr-only">Search <%= t('curation_concerns.product_name') %></legend>
4
+ <%= label_tag :catalog_search, t('curation_concerns.search.form.q.label'), class: "sr-only" %>
5
5
  <%= render_hash_as_hidden_fields(search_state.params_for_search.except(:q, :search_field, :qt, :page, :utf8)) %>
6
6
  <%= text_field_tag(:q, params[:q], class: "q search-query", id: "catalog_search",
7
7
  placeholder: t('curation_concerns.search.form.q.placeholder'), tabindex: "1", type: "search") %>
8
8
  <button type="submit" class="search-submit btn btn-primary" id="keyword-search-submit" tabindex="2">
9
- <i class="glyphicon glyphicon-search"></i><span class="accessible-hidden">Search</span>
9
+ <i class="glyphicon glyphicon-search"></i><span class="sr-only">Search</span>
10
10
  </button>
11
11
  </fieldset>
12
12
  <% end %>
@@ -147,6 +147,8 @@ en:
147
147
  human_readable_type_tesim: "Resource Type"
148
148
  format_tesim: "File Format"
149
149
  identifier_tesim: "Identifier"
150
+ file_manager:
151
+ link_text: 'File Manager'
150
152
  simple_form:
151
153
  hints:
152
154
  defaults:
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency 'hydra-editor', '~> 1.1'
26
26
  spec.add_dependency 'blacklight_advanced_search', '~> 6.0'
27
27
  spec.add_dependency 'rails_autolink'
28
+ spec.add_dependency 'sprockets-es6'
28
29
 
29
30
  spec.add_development_dependency 'solr_wrapper', '~> 0.4'
30
31
  spec.add_development_dependency 'fcrepo_wrapper', '~> 0.1'
@@ -42,4 +43,5 @@ Gem::Specification.new do |spec|
42
43
  spec.add_development_dependency "factory_girl"
43
44
  spec.add_development_dependency "database_cleaner", "< 1.1.0"
44
45
  spec.add_development_dependency 'mida', '~> 0.3.4'
46
+ spec.add_development_dependency 'jasmine'
45
47
  end
@@ -5,6 +5,7 @@ require 'hydra-collections'
5
5
  require 'hydra-editor'
6
6
  require 'jquery-ui-rails'
7
7
  require 'qa'
8
+ require 'sprockets/es6'
8
9
 
9
10
  module CurationConcerns
10
11
  # Ensures that routes to curation_concerns are prefixed with `curation_concerns_`
@@ -12,6 +12,11 @@ module ActionDispatch::Routing
12
12
  namespace :curation_concerns, path: :concern do
13
13
  concerns_to_route.each do |curation_concern_name|
14
14
  namespaced_resources curation_concern_name, except: [:index], &block
15
+ namespaced_resources curation_concern_name, only: [] do
16
+ member do
17
+ get :file_manager
18
+ end
19
+ end
15
20
  end
16
21
 
17
22
  resources :permissions, only: [] do
@@ -1,3 +1,3 @@
1
1
  module CurationConcerns
2
- VERSION = "0.7.0".freeze
2
+ VERSION = "0.8.0".freeze
3
3
  end
@@ -247,15 +247,31 @@ describe CurationConcerns::GenericWorkActor do
247
247
  context 'with multiple file sets' do
248
248
  let(:file_set1) { create(:file_set) }
249
249
  let(:file_set2) { create(:file_set) }
250
- let(:curation_concern) { FactoryGirl.create(:generic_work, user: user, members: [file_set1, file_set2]) }
250
+ let(:curation_concern) { FactoryGirl.create(:generic_work, user: user, ordered_members: [file_set1, file_set2]) }
251
251
  let(:attributes) do
252
- FactoryGirl.attributes_for(:generic_work, members: [file_set2, file_set1])
252
+ FactoryGirl.attributes_for(:generic_work, ordered_member_ids: [file_set2.id, file_set1.id])
253
253
  end
254
- xit 'updates the order of file sets' do
255
- expect(curation_concern.ordered_members).to eq [file_set1, file_set2]
254
+ it 'updates the order of file sets' do
255
+ expect(curation_concern.ordered_members.to_a).to eq [file_set1, file_set2]
256
+
256
257
  expect(subject.update).to be true
258
+
257
259
  curation_concern.reload
258
- expect(curation_concern.ordered_members).to eq [file_set2, file_set1]
260
+ expect(curation_concern.ordered_members.to_a).to eq [file_set2, file_set1]
261
+ end
262
+ ## Is this something we want to support?
263
+ context "when told to stop ordering a file set" do
264
+ let(:attributes) do
265
+ FactoryGirl.attributes_for(:generic_work, ordered_member_ids: [file_set2.id])
266
+ end
267
+ it "works" do
268
+ expect(curation_concern.ordered_members.to_a).to eq [file_set1, file_set2]
269
+
270
+ expect(subject.update).to be true
271
+
272
+ curation_concern.reload
273
+ expect(curation_concern.ordered_members.to_a).to eq [file_set2]
274
+ end
259
275
  end
260
276
  end
261
277
  end
@@ -163,6 +163,15 @@ describe CollectionsController do
163
163
  expect(assigns[:presenter].title).to eq collection.title
164
164
  expect(assigns[:member_docs].map(&:id)).to match_array [asset1, asset2, asset3].map(&:id)
165
165
  end
166
+
167
+ context 'when the q parameter is passed' do
168
+ it 'loads the collection (paying no attention to the q param)' do
169
+ get :show, id: collection, q: 'no matches'
170
+ expect(response).to be_successful
171
+ expect(assigns[:presenter]).to be_kind_of CurationConcerns::CollectionPresenter
172
+ expect(assigns[:presenter].title).to eq collection.title
173
+ end
174
+ end
166
175
  end
167
176
 
168
177
  context 'not signed in' do
@@ -122,7 +122,7 @@ describe CurationConcerns::GenericWorksController do
122
122
  describe '#update' do
123
123
  let(:a_work) { create(:private_generic_work, user: user) }
124
124
  before do
125
- allow(controller).to receive(:actor).and_return(actor)
125
+ allow(CurationConcerns::CurationConcern).to receive(:actor).and_return(actor)
126
126
  end
127
127
  let(:actor) { double(update: true, visibility_changed?: false) }
128
128
 
@@ -131,6 +131,13 @@ describe CurationConcerns::GenericWorksController do
131
131
  expect(response).to redirect_to main_app.curation_concerns_generic_work_path(a_work)
132
132
  end
133
133
 
134
+ it "can update file membership" do
135
+ file = create(:file_set, user: user)
136
+
137
+ patch :update, id: a_work, generic_work: { ordered_member_ids: [file.id] }
138
+ expect(CurationConcerns::CurationConcern).to have_received(:actor).with(anything, anything, ordered_member_ids: [file.id])
139
+ end
140
+
134
141
  describe 'changing rights' do
135
142
  let(:actor) { double(update: true, visibility_changed?: true) }
136
143
 
@@ -138,14 +145,14 @@ describe CurationConcerns::GenericWorksController do
138
145
  let(:a_work) { create(:work_with_one_file, user: user) }
139
146
 
140
147
  it 'prompts to change the files access' do
141
- patch :update, id: a_work
148
+ patch :update, id: a_work, generic_work: {}
142
149
  expect(response).to redirect_to main_app.confirm_curation_concerns_permission_path(controller.curation_concern)
143
150
  end
144
151
  end
145
152
 
146
153
  context 'without children' do
147
154
  it "doesn't prompt to change the files access" do
148
- patch :update, id: a_work
155
+ patch :update, id: a_work, generic_work: {}
149
156
  expect(response).to redirect_to main_app.curation_concerns_generic_work_path(a_work)
150
157
  end
151
158
  end
@@ -155,7 +162,7 @@ describe CurationConcerns::GenericWorksController do
155
162
  let(:actor) { double(update: false, visibility_changed?: false) }
156
163
 
157
164
  it 'renders the form' do
158
- patch :update, id: a_work
165
+ patch :update, id: a_work, generic_work: {}
159
166
  expect(assigns[:form]).to be_kind_of CurationConcerns::GenericWorkForm
160
167
  expect(response).to render_template('edit')
161
168
  end
@@ -207,4 +214,17 @@ describe CurationConcerns::GenericWorksController do
207
214
  end
208
215
  end
209
216
  end
217
+
218
+ describe '#file_manager' do
219
+ let(:work) { create(:private_generic_work, user: user) }
220
+ before do
221
+ sign_in user
222
+ end
223
+ it "is successful" do
224
+ get :file_manager, id: work.id
225
+
226
+ expect(response).to be_success
227
+ expect(assigns(:presenter)).not_to be_blank
228
+ end
229
+ end
210
230
  end
@@ -0,0 +1,87 @@
1
+ describe "FileManagerMember", ->
2
+ file_manager_member = null
3
+ save_manager = null
4
+ beforeEach () ->
5
+ loadFixtures('file_manager_member.html')
6
+ save_manager = {
7
+ push_changed: () -> {},
8
+ mark_unchanged: () -> {}
9
+ }
10
+ file_manager_member = new FileManagerMember($("li"), save_manager)
11
+ describe "#is_changed", ->
12
+ it "is true when the form's label input is changed", ->
13
+ $("#file_set_title").val("testing")
14
+ $("#file_set_title").change()
15
+
16
+ expect(file_manager_member.is_changed).toEqual(true)
17
+ it "is false when the form's label input isn't changed", ->
18
+ $("#file_set_title").change()
19
+
20
+ expect(file_manager_member.is_changed).toEqual(false)
21
+ it "is false when the form's label input returns", ->
22
+ initial_val = $("#file_set_title").val()
23
+ $("#file_set_title").val("testing")
24
+ $("#file_set_title").change()
25
+ $("#file_set_title").val(initial_val)
26
+ $("#file_set_title").change()
27
+
28
+ expect(file_manager_member.is_changed).toEqual(false)
29
+ it "triggers save_manager's push_changed when changed", ->
30
+ spyOn(save_manager, "push_changed")
31
+ $("#file_set_title").val("testing")
32
+ $("#file_set_title").change()
33
+
34
+ expect(save_manager.push_changed).toHaveBeenCalledWith(file_manager_member)
35
+ it "triggers save_manager's mark_unchanged when no longer changed", ->
36
+ spyOn(save_manager, "mark_unchanged")
37
+ initial_val = $("#file_set_title").val()
38
+ $("#file_set_title").val("testing")
39
+ $("#file_set_title").change()
40
+ $("#file_set_title").val(initial_val)
41
+ $("#file_set_title").change()
42
+
43
+ expect(save_manager.mark_unchanged).toHaveBeenCalledWith(file_manager_member)
44
+ it "doesn't trigger save_manager's mark_unchanged when there are still changed elements", ->
45
+ spyOn(save_manager, "mark_unchanged")
46
+ file_manager_member.elements.push {}
47
+ initial_val = $("#file_set_title").val()
48
+ $("#file_set_title").val("testing")
49
+ $("#file_set_title").change()
50
+ $("#file_set_title").val(initial_val)
51
+ $("#file_set_title").change()
52
+
53
+ expect(save_manager.mark_unchanged).not.toHaveBeenCalled()
54
+ describe "#persist", ->
55
+ describe "when nothing has changed", ->
56
+ it "returns a resolved deferred object", ->
57
+ expect(file_manager_member.persist().state()).toEqual("resolved")
58
+ describe "when updates need to be sent", ->
59
+ request = null
60
+ beforeEach () ->
61
+ jasmine.Ajax.install()
62
+ afterEach () ->
63
+ jasmine.Ajax.uninstall()
64
+ it "returns a deferred object which is resolved with the ajax request", ->
65
+ $("#file_set_title").val("testing")
66
+ $("#file_set_title").change()
67
+ result = file_manager_member.persist()
68
+ request = jasmine.Ajax.requests.mostRecent()
69
+
70
+ expect(result.state()).toEqual("pending")
71
+
72
+ request.respondWith(TestResponses.file_manager_member.success)
73
+
74
+ expect(result.state()).toEqual("resolved")
75
+ expect(file_manager_member.is_changed).toEqual(false)
76
+ it "rejects the deferred object when the ajax request fails", ->
77
+ $("#file_set_title").val("testing")
78
+ $("#file_set_title").change()
79
+ result = file_manager_member.persist()
80
+ request = jasmine.Ajax.requests.mostRecent()
81
+
82
+ expect(result.state()).toEqual("pending")
83
+
84
+ request.respondWith(TestResponses.file_manager_member.failure)
85
+
86
+ expect(result.state()).toEqual("rejected")
87
+ expect(file_manager_member.is_changed).toEqual(true)
File without changes
@@ -0,0 +1,40 @@
1
+ <li data-reorder-id="j38606956">
2
+ <form accept-charset="UTF-8" action="/concern/file_sets/j38606956" class=
3
+ "simple_form edit_file_set" data-remote="true" id="edit_file_set_j38606956"
4
+ method="post" name="edit_file_set_j38606956">
5
+ <input name="utf8" type="hidden" value="✓"><input name="_method" type=
6
+ "hidden" value="patch">
7
+ <div class="panel panel-default">
8
+ <div class="panel-heading ui-sortable-handle">
9
+ <div class="order-title">
10
+ <div class="form-group string required file_set_title">
11
+ <div>
12
+ <input aria-required="true" class=
13
+ "string required title form-control" id="file_set_title" name=
14
+ "file_set[title][]" required="required" type="text" value=
15
+ "01.tif">
16
+ </div>
17
+ </div>
18
+ </div>
19
+ <div class="file-set-link pull-right">
20
+ <a href="/concern/file_sets/j38606956" title=
21
+ "Edit file"><span aria-hidden="true" class=
22
+ "glyphicon glyphicon-edit"></span></a>
23
+ </div>
24
+ <div class="order-filename">
25
+ <em title="01.tif">(01.tif)</em>
26
+ </div>
27
+ </div>
28
+ <div class="panel-body">
29
+ <div class="text-center thumbnail">
30
+ <a data-context-href="/catalog/j38606956/track?search_id=1" href=
31
+ "/concern/file_sets/j38606956"><img alt="J38606956?file=thumbnail"
32
+ class="thumbnail-inner" src=
33
+ "/downloads/j38606956?file=thumbnail"></a>
34
+ </div>
35
+ <div class="attributes"></div>
36
+ <div class="spacer"></div>
37
+ </div>
38
+ </div>
39
+ </form>
40
+ </li>
@@ -0,0 +1,3 @@
1
+ <div class="actions form-horizontal panel panel-default">
2
+ <button name="button" type="submit" class="btn btn-primary disabled" data-action="save-actions">Save</button>
3
+ </div>