curation_concerns 2.0.0.rc1 → 2.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -12
  3. data/.travis.yml +6 -1
  4. data/CONTRIBUTING.md +68 -20
  5. data/app/actors/curation_concerns/actors/add_as_member_of_collections_actor.rb +3 -0
  6. data/app/actors/curation_concerns/actors/add_to_work_actor.rb +16 -4
  7. data/app/actors/curation_concerns/actors/apply_order_actor.rb +16 -5
  8. data/app/actors/curation_concerns/optimistic_lock_validator.rb +28 -0
  9. data/app/assets/javascripts/curation_concerns/file_manager/sorting.es6 +17 -7
  10. data/app/controllers/concerns/curation_concerns/curation_concern_controller.rb +11 -1
  11. data/app/controllers/concerns/curation_concerns/download_behavior.rb +6 -0
  12. data/app/forms/curation_concerns/forms/file_manager_form.rb +27 -0
  13. data/app/forms/curation_concerns/forms/work_form.rb +8 -0
  14. data/app/indexers/curation_concerns/file_set_indexer.rb +2 -2
  15. data/app/jobs/characterize_job.rb +12 -5
  16. data/app/jobs/create_derivatives_job.rb +10 -5
  17. data/app/jobs/ingest_file_job.rb +13 -9
  18. data/app/models/concerns/curation_concerns/ability.rb +1 -0
  19. data/app/models/concerns/curation_concerns/collection_behavior.rb +1 -1
  20. data/app/models/concerns/curation_concerns/work_behavior.rb +6 -0
  21. data/app/presenters/curation_concerns/admin/workflow_role_presenter.rb +4 -0
  22. data/app/presenters/curation_concerns/member_presenter_factory.rb +70 -0
  23. data/app/presenters/curation_concerns/work_show_presenter.rb +7 -47
  24. data/app/services/curation_concerns/actors/actor_factory.rb +2 -1
  25. data/app/services/curation_concerns/workflow/grant_edit_to_depositor.rb +1 -1
  26. data/app/services/curation_concerns/workflow/permission_query.rb +4 -1
  27. data/app/services/curation_concerns/workflow/workflow_importer.rb +1 -0
  28. data/app/services/curation_concerns/workflow/workflow_schema.rb +1 -0
  29. data/app/views/curation_concerns/admin/workflow_roles/index.html.erb +1 -2
  30. data/app/views/curation_concerns/base/_file_manager_member_resource_options.html.erb +2 -2
  31. data/app/views/curation_concerns/base/_file_manager_members.html.erb +13 -5
  32. data/app/views/curation_concerns/base/_file_manager_resource_form.html.erb +1 -1
  33. data/app/views/curation_concerns/base/_form.html.erb +5 -0
  34. data/app/views/curation_concerns/base/_form_in_works_error.html.erb +3 -0
  35. data/app/views/curation_concerns/base/_form_ordered_members_error.html.erb +3 -0
  36. data/app/views/curation_concerns/base/file_manager.html.erb +2 -2
  37. data/app/views/curation_concerns/base/show.json.jbuilder +2 -1
  38. data/config/locales/curation_concerns.en.yml +4 -0
  39. data/curation_concerns.gemspec +1 -1
  40. data/db/migrate/20170308175556_add_allows_access_grant_to_workflow.rb +5 -0
  41. data/lib/curation_concerns/data_migration/collections_migration.rb +16 -0
  42. data/lib/curation_concerns/version.rb +1 -1
  43. data/lib/generators/curation_concerns/templates/workflow.json.erb +1 -0
  44. data/lib/tasks/curation_concerns.rake +12 -0
  45. data/spec/actors/curation_concerns/add_as_member_of_collections_actor_spec.rb +58 -0
  46. data/spec/actors/curation_concerns/apply_order_actor_spec.rb +20 -0
  47. data/spec/actors/curation_concerns/optimistic_lock_validator_spec.rb +50 -0
  48. data/spec/actors/curation_concerns/work_actor_spec.rb +9 -6
  49. data/spec/controllers/curation_concerns/generic_works_controller_spec.rb +2 -1
  50. data/spec/controllers/downloads_controller_spec.rb +5 -6
  51. data/spec/features/create_child_work_spec.rb +16 -2
  52. data/spec/forms/curation_concerns/forms/file_manager_form_spec.rb +19 -0
  53. data/spec/forms/work_form_spec.rb +8 -0
  54. data/spec/lib/curation_concerns/data_migration/collections_migration_spec.rb +34 -0
  55. data/spec/presenters/curation_concerns/member_presenter_factory_spec.rb +25 -0
  56. data/spec/presenters/curation_concerns/work_show_presenter_spec.rb +11 -21
  57. data/spec/services/curation_concerns/workflow/grant_edit_to_depositor_spec.rb +15 -4
  58. data/spec/services/curation_concerns/workflow/permission_query_spec.rb +7 -1
  59. data/spec/services/curation_concerns/workflow/workflow_importer_spec.rb +5 -2
  60. data/spec/services/curation_concerns/workflow/workflow_schema_spec.rb +1 -0
  61. data/spec/views/curation_concerns/admin/workflow_roles/index.html.erb_spec.rb +33 -0
  62. data/spec/views/curation_concerns/base/_form.html.erb_spec.rb +35 -0
  63. data/spec/views/curation_concerns/base/file_manager.html.erb_spec.rb +10 -8
  64. data/spec/views/curation_concerns/base/show.json.jbuilder_spec.rb +3 -1
  65. metadata +26 -5
@@ -27,6 +27,10 @@ module CurationConcerns
27
27
  super(model)
28
28
  end
29
29
 
30
+ def version
31
+ model.etag
32
+ end
33
+
30
34
  # The value for embargo_relase_date and lease_expiration_date should not
31
35
  # be initialized to empty string
32
36
  def initialize_field(key)
@@ -59,6 +63,10 @@ module CurationConcerns
59
63
  super
60
64
  end
61
65
  end
66
+
67
+ def build_permitted_params
68
+ super + [:version]
69
+ end
62
70
  end
63
71
 
64
72
  private
@@ -1,7 +1,7 @@
1
1
  module CurationConcerns
2
2
  class FileSetIndexer < ActiveFedora::IndexingService
3
3
  include IndexesThumbnails
4
- STORED_INTEGER = Solrizer::Descriptor.new(:integer, :stored)
4
+ STORED_LONG = Solrizer::Descriptor.new(:long, :stored)
5
5
 
6
6
  def generate_solr_document
7
7
  super.tap do |solr_doc|
@@ -12,7 +12,7 @@ module CurationConcerns
12
12
  solr_doc[Solrizer.solr_name('label', :stored_sortable)] = object.label
13
13
  solr_doc[Solrizer.solr_name('file_format')] = file_format
14
14
  solr_doc[Solrizer.solr_name('file_format', :facetable)] = file_format
15
- solr_doc[Solrizer.solr_name(:file_size, STORED_INTEGER)] = object.file_size[0]
15
+ solr_doc[Solrizer.solr_name(:file_size, STORED_LONG)] = object.file_size[0]
16
16
  solr_doc['all_text_timv'] = object.extracted_text.content if object.extracted_text.present?
17
17
  solr_doc['height_is'] = Integer(object.height.first) if object.height.present?
18
18
  solr_doc['width_is'] = Integer(object.width.first) if object.width.present?
@@ -1,4 +1,6 @@
1
1
  class CharacterizeJob < ActiveJob::Base
2
+ include CurationConcerns::Lockable
3
+
2
4
  queue_as CurationConcerns.config.ingest_queue_name
3
5
 
4
6
  # @param [FileSet] file_set
@@ -7,11 +9,16 @@ class CharacterizeJob < ActiveJob::Base
7
9
  def perform(file_set, file_id, filepath = nil)
8
10
  filename = CurationConcerns::WorkingDirectory.find_or_retrieve(file_id, file_set.id, filepath)
9
11
  raise LoadError, "#{file_set.class.characterization_proxy} was not found" unless file_set.characterization_proxy?
10
- Hydra::Works::CharacterizationService.run(file_set.characterization_proxy, filename)
11
- Rails.logger.debug "Ran characterization on #{file_set.characterization_proxy.id} (#{file_set.characterization_proxy.mime_type})"
12
- file_set.characterization_proxy.save!
13
- file_set.update_index
14
- file_set.parent.in_collections.each(&:update_index) if file_set.parent
12
+
13
+ # Prevent other jobs from trying to modify the FileSet at the same time
14
+ acquire_lock_for(file_set.id) do
15
+ Hydra::Works::CharacterizationService.run(file_set.characterization_proxy, filename)
16
+ Rails.logger.debug "Ran characterization on #{file_set.characterization_proxy.id} (#{file_set.characterization_proxy.mime_type})"
17
+ file_set.characterization_proxy.save!
18
+ file_set.update_index
19
+ file_set.parent.in_collections.each(&:update_index) if file_set.parent
20
+ end
21
+
15
22
  CreateDerivativesJob.perform_later(file_set, file_id, filename)
16
23
  end
17
24
  end
@@ -1,4 +1,6 @@
1
1
  class CreateDerivativesJob < ActiveJob::Base
2
+ include CurationConcerns::Lockable
3
+
2
4
  queue_as CurationConcerns.config.ingest_queue_name
3
5
 
4
6
  # @param [FileSet] file_set
@@ -8,12 +10,15 @@ class CreateDerivativesJob < ActiveJob::Base
8
10
  return if file_set.video? && !CurationConcerns.config.enable_ffmpeg
9
11
  filename = CurationConcerns::WorkingDirectory.find_or_retrieve(file_id, file_set.id, filepath)
10
12
 
11
- file_set.create_derivatives(filename)
13
+ # Prevent other jobs from trying to modify the FileSet at the same time
14
+ acquire_lock_for(file_set.id) do
15
+ file_set.create_derivatives(filename)
12
16
 
13
- # Reload from Fedora and reindex for thumbnail and extracted text
14
- file_set.reload
15
- file_set.update_index
16
- file_set.parent.update_index if parent_needs_reindex?(file_set)
17
+ # Reload from Fedora and reindex for thumbnail and extracted text
18
+ file_set.reload
19
+ file_set.update_index
20
+ file_set.parent.update_index if parent_needs_reindex?(file_set)
21
+ end
17
22
  end
18
23
 
19
24
  # If this file_set is the thumbnail for the parent work,
@@ -1,4 +1,6 @@
1
1
  class IngestFileJob < ActiveJob::Base
2
+ include CurationConcerns::Lockable
3
+
2
4
  queue_as CurationConcerns.config.ingest_queue_name
3
5
 
4
6
  # @param [FileSet] file_set
@@ -15,15 +17,17 @@ class IngestFileJob < ActiveJob::Base
15
17
  local_file.mime_type = opts.fetch(:mime_type, nil)
16
18
  local_file.original_name = opts.fetch(:filename, File.basename(filepath))
17
19
 
18
- # Tell AddFileToFileSet service to skip versioning because versions will be minted by
19
- # VersionCommitter when necessary during save_characterize_and_record_committer.
20
- Hydra::Works::AddFileToFileSet.call(file_set,
21
- local_file,
22
- relation,
23
- versioning: false)
24
-
25
- # Persist changes to the file_set
26
- file_set.save!
20
+ # Prevent other jobs from trying to modify the FileSet at the same time
21
+ acquire_lock_for(file_set.id) do
22
+ # Tell AddFileToFileSet service to skip versioning because versions will be minted by
23
+ # VersionCommitter when necessary during save_characterize_and_record_committer.
24
+ Hydra::Works::AddFileToFileSet.call(file_set,
25
+ local_file,
26
+ relation,
27
+ versioning: false)
28
+ # Persist changes to the file_set
29
+ file_set.save!
30
+ end
27
31
 
28
32
  repository_file = file_set.send(relation)
29
33
 
@@ -14,6 +14,7 @@ module CurationConcerns
14
14
 
15
15
  # user can version if they can edit
16
16
  alias_action :versions, to: :update
17
+ alias_action :file_manager, to: :update
17
18
 
18
19
  if admin?
19
20
  admin_permissions
@@ -50,7 +50,7 @@ module CurationConcerns
50
50
  # Field name to look up when locating the size of each file in Solr.
51
51
  # Override for your own installation if using something different
52
52
  def file_size_field
53
- Solrizer.solr_name(:file_size, CurationConcerns::FileSetIndexer::STORED_INTEGER)
53
+ Solrizer.solr_name(:file_size, CurationConcerns::FileSetIndexer::STORED_LONG)
54
54
  end
55
55
 
56
56
  # Solr field name collections and works use to index member ids
@@ -24,6 +24,12 @@ module CurationConcerns::WorkBehavior
24
24
  self.indexer = CurationConcerns::WorkIndexer
25
25
  end
26
26
 
27
+ # TODO: Move this into ActiveFedora
28
+ def etag
29
+ raise "Unable to produce an etag for a unsaved object" unless persisted?
30
+ ldp_source.head.etag
31
+ end
32
+
27
33
  module ClassMethods
28
34
  # This governs which partial to draw when you render this type of object
29
35
  def _to_partial_path #:nodoc:
@@ -16,6 +16,10 @@ module CurationConcerns
16
16
  @agent = agent
17
17
  end
18
18
 
19
+ def responsibilities_present?
20
+ @agent.workflow_responsibilities.any?
21
+ end
22
+
19
23
  def responsibilities
20
24
  @agent.workflow_responsibilities.each do |responsibility|
21
25
  yield ResponsibilityPresenter.new(responsibility)
@@ -0,0 +1,70 @@
1
+ module CurationConcerns
2
+ # Creates the presenters of the members (member works and file sets) of a specific object
3
+ class MemberPresenterFactory
4
+ class_attribute :file_presenter_class, :work_presenter_class
5
+ # modify this attribute to use an alternate presenter class for the files
6
+ self.file_presenter_class = FileSetPresenter
7
+
8
+ # modify this attribute to use an alternate presenter class for the child works
9
+ self.work_presenter_class = WorkShowPresenter
10
+
11
+ def initialize(work, ability, request = nil)
12
+ @work = work
13
+ @current_ability = ability
14
+ @request = request
15
+ end
16
+
17
+ delegate :id, to: :@work
18
+ attr_reader :current_ability, :request
19
+
20
+ # @param [Array<String>] ids a list of ids to build presenters for
21
+ # @param [Class] presenter_class the type of presenter to build
22
+ # @return [Array<presenter_class>] presenters for the ordered_members (not filtered by class)
23
+ def member_presenters(ids = ordered_ids, presenter_class = composite_presenter_class)
24
+ PresenterFactory.build_presenters(ids, presenter_class, *presenter_factory_arguments)
25
+ end
26
+
27
+ # @return [Array<FileSetPresenter>] presenters for the orderd_members that are FileSets
28
+ def file_set_presenters
29
+ @file_set_presenters ||= member_presenters(ordered_ids & file_set_ids)
30
+ end
31
+
32
+ # @return [Array<WorkShowPresenter>] presenters for the ordered_members that are not FileSets
33
+ def work_presenters
34
+ @work_presenters ||= member_presenters(ordered_ids - file_set_ids, work_presenter_class)
35
+ end
36
+
37
+ private
38
+
39
+ # TODO: Extract this to ActiveFedora::Aggregations::ListSource
40
+ def ordered_ids
41
+ @ordered_ids ||= begin
42
+ ActiveFedora::SolrService.query("proxy_in_ssi:#{id}",
43
+ rows: 10_000,
44
+ fl: "ordered_targets_ssim")
45
+ .flat_map { |x| x.fetch("ordered_targets_ssim", []) }
46
+ end
47
+ end
48
+
49
+ # These are the file sets that belong to this work, but not necessarily
50
+ # in order.
51
+ # Arbitrarily maxed at 10 thousand; had to specify rows due to solr's default of 10
52
+ def file_set_ids
53
+ @file_set_ids ||= begin
54
+ ActiveFedora::SolrService.query("{!field f=has_model_ssim}FileSet",
55
+ rows: 10_000,
56
+ fl: ActiveFedora.id_field,
57
+ fq: "{!join from=ordered_targets_ssim to=id}id:\"#{id}/list_source\"")
58
+ .flat_map { |x| x.fetch(ActiveFedora.id_field, []) }
59
+ end
60
+ end
61
+
62
+ def presenter_factory_arguments
63
+ [current_ability, request]
64
+ end
65
+
66
+ def composite_presenter_class
67
+ CompositePresenterFactory.new(file_presenter_class, work_presenter_class, ordered_ids & file_set_ids)
68
+ end
69
+ end
70
+ end
@@ -4,17 +4,11 @@ module CurationConcerns
4
4
  include PresentsAttributes
5
5
  attr_accessor :solr_document, :current_ability, :request
6
6
 
7
- class_attribute :collection_presenter_class, :file_presenter_class, :work_presenter_class
7
+ class_attribute :collection_presenter_class
8
8
 
9
9
  # modify this attribute to use an alternate presenter class for the collections
10
10
  self.collection_presenter_class = CollectionPresenter
11
11
 
12
- # modify this attribute to use an alternate presenter class for the files
13
- self.file_presenter_class = FileSetPresenter
14
-
15
- # modify this attribute to use an alternate presenter class for the child works
16
- self.work_presenter_class = self
17
-
18
12
  # Methods used by blacklight helpers
19
13
  delegate :has?, :first, :fetch, :export_formats, :export_as, to: :solr_document
20
14
 
@@ -41,11 +35,6 @@ module CurationConcerns
41
35
  :lease_expiration_date, :rights, :source, :thumbnail_id, :representative_id,
42
36
  :member_of_collection_ids, to: :solr_document
43
37
 
44
- # @return [Array<FileSetPresenter>] presenters for the orderd_members that are FileSets
45
- def file_set_presenters
46
- @file_set_presenters ||= member_presenters(ordered_ids & file_set_ids)
47
- end
48
-
49
38
  def workflow
50
39
  @workflow ||= WorkflowPresenter.new(solr_document, current_ability)
51
40
  end
@@ -68,22 +57,6 @@ module CurationConcerns
68
57
  end
69
58
  end
70
59
 
71
- # @return [Array<WorkShowPresenter>] presenters for the ordered_members that are not FileSets
72
- def work_presenters
73
- @work_presenters ||= member_presenters(ordered_ids - file_set_ids, work_presenter_class)
74
- end
75
-
76
- # @param [Array<String>] ids a list of ids to build presenters for
77
- # @param [Class] presenter_class the type of presenter to build
78
- # @return [Array<presenter_class>] presenters for the ordered_members (not filtered by class)
79
- def member_presenters(ids = ordered_ids, presenter_class = composite_presenter_class)
80
- PresenterFactory.build_presenters(ids, presenter_class, *presenter_factory_arguments)
81
- end
82
-
83
- def composite_presenter_class
84
- CompositePresenterFactory.new(file_presenter_class, work_presenter_class, ordered_ids & file_set_ids)
85
- end
86
-
87
60
  # Get presenters for the collections this work is a member of via the member_of_collections association.
88
61
  # @return [Array<CollectionPresenter>] presenters
89
62
  def member_of_collection_presenters
@@ -107,33 +80,20 @@ module CurationConcerns
107
80
  graph.dump(:ttl)
108
81
  end
109
82
 
110
- private
83
+ delegate :member_presenters, :file_set_presenters, :work_presenters, to: :member_presenter_factory
111
84
 
112
- def graph
113
- GraphExporter.new(solr_document, request).fetch
114
- end
85
+ private
115
86
 
116
87
  def presenter_factory_arguments
117
88
  [current_ability, request]
118
89
  end
119
90
 
120
- # TODO: Extract this to ActiveFedora::Aggregations::ListSource
121
- def ordered_ids
122
- @ordered_ids ||= begin
123
- ActiveFedora::SolrService.query("proxy_in_ssi:#{id}", fl: "ordered_targets_ssim")
124
- .flat_map { |x| x.fetch("ordered_targets_ssim", []) }
125
- end
91
+ def member_presenter_factory
92
+ MemberPresenterFactory.new(solr_document, current_ability, request)
126
93
  end
127
94
 
128
- # These are the file sets that belong to this work, but not necessarily
129
- # in order.
130
- def file_set_ids
131
- @file_set_ids ||= begin
132
- ActiveFedora::SolrService.query("{!field f=has_model_ssim}FileSet",
133
- fl: ActiveFedora.id_field,
134
- fq: "{!join from=ordered_targets_ssim to=id}id:\"#{id}/list_source\"")
135
- .flat_map { |x| x.fetch(ActiveFedora.id_field, []) }
136
- end
95
+ def graph
96
+ GraphExporter.new(solr_document, request).fetch
137
97
  end
138
98
  end
139
99
  end
@@ -8,7 +8,8 @@ module CurationConcerns
8
8
  end
9
9
 
10
10
  def self.stack_actors(curation_concern)
11
- [AddAsMemberOfCollectionsActor,
11
+ [OptimisticLockValidator,
12
+ AddAsMemberOfCollectionsActor,
12
13
  AddToWorkActor,
13
14
  AssignRepresentativeActor,
14
15
  AttachFilesActor,
@@ -4,7 +4,7 @@ module CurationConcerns
4
4
  # grants the creator the ability to alter it.
5
5
  class GrantEditToDepositor
6
6
  def self.call(target:, **)
7
- target.edit_users = [target.depositor]
7
+ target.edit_users += [target.depositor]
8
8
  end
9
9
  end
10
10
  end
@@ -257,7 +257,10 @@ module CurationConcerns
257
257
  .and(entity_responsibilities[:entity_id].eq(entity.id))
258
258
  )
259
259
 
260
- sub_query_for_user = agent_table.project(agent_table[:proxy_for_id]).where(
260
+ # PostgreSQL requires an explicit cast from string to integer
261
+ cast = Arel::Nodes::NamedFunction.new "CAST", [agent_table[:proxy_for_id].as("integer")]
262
+
263
+ sub_query_for_user = agent_table.project(cast).where(
261
264
  agent_table[:id].in(workflow_agent_id_subquery)
262
265
  .or(agent_table[:id].in(entity_agent_id_subquery))
263
266
  ).where(
@@ -72,6 +72,7 @@ module CurationConcerns
72
72
  workflow = Sipity::Workflow.find_or_initialize_by(name: configuration.fetch(:name)) do |wf|
73
73
  wf.label = configuration.fetch(:label, nil)
74
74
  wf.description = configuration.fetch(:description, nil)
75
+ wf.allows_access_grant = configuration.fetch(:allows_access_grant, nil)
75
76
  wf.save!
76
77
  end
77
78
 
@@ -34,6 +34,7 @@ module CurationConcerns
34
34
  required(:name).filled(:str?) # Sipity::Workflow#name
35
35
  optional(:label).filled(:str?) # Sipity::Workflow#label
36
36
  optional(:description).filled(:str?) # Sipity::Workflow#description
37
+ optional(:allows_access_grant).filled(:bool?) # Sipity::Workflow#allows_access_grant?
37
38
  required(:actions).each do
38
39
  required(:name).filled(:str?) # Sipity::WorkflowAction#name
39
40
  required(:from_states).each do
@@ -11,7 +11,7 @@
11
11
  <tr>
12
12
  <td><%= user.user_key %></td>
13
13
  <% agent_presenter = @presenter.presenter_for(user) %>
14
- <% if agent_presenter %>
14
+ <% if agent_presenter && agent_presenter.responsibilities_present? %>
15
15
  <td>
16
16
  <ul>
17
17
  <% agent_presenter.responsibilities do |responsibility_presenter| %>
@@ -42,4 +42,3 @@
42
42
  </div>
43
43
  </div>
44
44
  </div>
45
-
@@ -1,10 +1,10 @@
1
1
  <div class="form-group radio_buttons member_resource_options">
2
2
  <span class="radio">
3
- <%= radio_button_tag "thumbnail_id", node.id, @presenter.thumbnail_id == node.id, id: "thumbnail_id_#{node.id}", class: "radio_buttons" %>
3
+ <%= radio_button_tag "thumbnail_id", node.id, @form.thumbnail_id == node.id, id: "thumbnail_id_#{node.id}", class: "radio_buttons" %>
4
4
  <%= label_tag "thumbnail_id_#{node.id}", "Thumbnail" %>
5
5
  </span>
6
6
  <span class="radio">
7
- <%= radio_button_tag "representative_id", node.id, @presenter.representative_id == node.id, id: "representative_id_#{node.id}", class: "radio_buttons" %>
7
+ <%= radio_button_tag "representative_id", node.id, @form.representative_id == node.id, id: "representative_id_#{node.id}", class: "radio_buttons" %>
8
8
  <%= label_tag "representative_id_#{node.id}", "Representative Media" %>
9
9
  </span>
10
10
  </div>
@@ -1,5 +1,13 @@
1
- <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 clearfix">
2
- <% @presenter.member_presenters.each do |member| %>
3
- <%= render "file_manager_member", node: member %>
4
- <% end %>
5
- </ul>
1
+ <%= content_tag :ul,
2
+ id: "sortable",
3
+ class: "list-unstyled grid clearfix",
4
+ data: {
5
+ id: @form.id,
6
+ "class-name" => @form.model_name.plural,
7
+ "singular-class-name" => @form.model_name.singular,
8
+ version: @form.version
9
+ } do %>
10
+ <% @form.member_presenters.each do |member| %>
11
+ <%= render "file_manager_member", node: member %>
12
+ <% end %>
13
+ <% end %>
@@ -1,5 +1,5 @@
1
1
  <div class="resource-form-container">
2
- <%= simple_form_for [main_app, @presenter], remote: true, html: { id: 'resource-form', 'data-type': 'json' } do |f| %>
2
+ <%= simple_form_for [main_app, @form], remote: true, html: { id: 'resource-form', 'data-type': 'json' } do |f| %>
3
3
  <%= f.input :thumbnail_id, as: :hidden, input_html: { data: {member_link: 'thumbnail_id'}} %>
4
4
  <%= f.input :representative_id, as: :hidden, input_html: { data: {member_link: 'representative_id'}} %>
5
5
  <% end %>