diff --git a/hyrax/Gemfile b/hyrax/Gemfile
index 7737500f7cf02bb8cf04d9d1556d146b1e377f2c..d40fc34a07af57e91daee2528db3bc0ebb5b59a5 100644
--- a/hyrax/Gemfile
+++ b/hyrax/Gemfile
@@ -83,7 +83,7 @@ gem 'hydra-role-management'
 gem 'omniauth'
 gem "omniauth-rails_csrf_protection"
 gem 'omniauth-orcid'
-gem 'omniauth-saml', '~> 2.1'
+gem 'omniauth-saml', '~> 2.2'
 
 # aws s3
 gem 'valkyrie-shrine'
diff --git a/hyrax/app/assets/javascripts/date_picker_options.js b/hyrax/app/assets/javascripts/date_picker_options.js
index c101bba22c9c9b939be7749a9e7d64b6dc7881d1..13a753bdc48b606637c36fdc90a0ef376358ea63 100644
--- a/hyrax/app/assets/javascripts/date_picker_options.js
+++ b/hyrax/app/assets/javascripts/date_picker_options.js
@@ -1,6 +1,6 @@
 Blacklight.onLoad(function() {
  // $.fn.datepicker.defaults.format = "dd/mm/yyyy";
- $("#complex_session_session_date_recorded").datepicker({
+ $('[data-provide="datepicker"]').datepicker({
   orientation: "bottom left"
 });
 });
diff --git a/hyrax/app/helpers/hyrax/listeners/lifecycle_listener_helper.rb b/hyrax/app/helpers/hyrax/listeners/lifecycle_listener_helper.rb
index 0611c960782a90ec8f326b3eef47487f1cb627dc..795bda0c42c3d5c5d7447917454a090528006589 100644
--- a/hyrax/app/helpers/hyrax/listeners/lifecycle_listener_helper.rb
+++ b/hyrax/app/helpers/hyrax/listeners/lifecycle_listener_helper.rb
@@ -26,6 +26,7 @@ module Hyrax
         end
 
         object = save_object!(object)
+        Hyrax.index_adapter.save(resource: object)
         object
       end
 
@@ -38,14 +39,13 @@ module Hyrax
           object.save_metadata_as_json_in_s3
         end
 
-        Hyrax.index_adapter.save(resource: object)
         object
       end
 
       def after_destroy_callbacks(object)
         case object.class.name
-        when 'Crc1280Experiment'
-          object.complex_subjects.destroy_all
+        when 'Crc1280Experiment', 'Dataset'
+          object.clear_s3_and_all_associated_objects
         when 'FileSet'
           destroy_set_meta_data(object)
         end
diff --git a/hyrax/app/helpers/hyrax/membership_helper.rb b/hyrax/app/helpers/hyrax/membership_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6b88925d84061adfff02ee171f92acfd17f56811
--- /dev/null
+++ b/hyrax/app/helpers/hyrax/membership_helper.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module Hyrax
+  module MembershipHelper
+    ##
+    # @param resource [#member_of_collection_ids, #member_of_collections_json]
+    #
+    # @return [String] JSON for `data-members`
+    #
+    # @todo optimize collection name lookup. the legacy `WorkForm`
+    #   implementation pulls all the collections already (though maybe with
+    #   instance-level caching?), but we should consider doing this more
+    #   efficiently.
+    #
+    # @see app/assets/javascripts/hyrax/relationships.js
+    def member_of_collections_json(resource)
+      # this is where we return for dassie
+      return resource.member_of_collections_json if
+        resource.respond_to?(:member_of_collections_json)
+
+      resource = resource.model if resource.respond_to?(:model)
+
+      existing_collections_array = resource.parent_collections + add_collection_from_params
+      existing_collections_array.map do |collection|
+        { id: collection.id.to_s,
+          label: collection.title.first,
+          path: url_for(collection) }
+      end.to_json
+    end
+
+    def add_collection_from_params
+      # avoid errors when creating Valkyrie resources from Dashboard >> Works
+      return [] if controller.params[:add_works_to_collection].blank?
+
+      # new valkyrie works need the collection from params when depositing directly into an existing collection
+      return [Hyrax.metadata_adapter.query_service.find_by(id: Valkyrie::ID.new(controller.params[:add_works_to_collection]))] if Hyrax.config.use_valkyrie?
+
+      [::Collection.find(@controller.params[:add_works_to_collection])]
+    end
+
+    ##
+    # @param resource [#work_members_json]
+    #
+    # @return [String] JSON for `data-members`
+    #
+    # @see app/assets/javascripts/hyrax/relationships.js
+    def work_members_json(resource)
+      return resource.work_members_json if
+        resource.respond_to?(:work_members_json)
+
+      resource = resource.model if resource.respond_to?(:model)
+
+      Hyrax.custom_queries.find_child_works(resource: resource).map do |member|
+        { id: member.id.to_s,
+          label: member.title.first,
+          path: main_app.url_for([member, { only_path: true }]) }
+      end.to_json
+    end
+  end
+end
\ No newline at end of file
diff --git a/hyrax/app/helpers/hyrax_helper.rb b/hyrax/app/helpers/hyrax_helper.rb
index 694ea73aca98bf492842e12c98d7336000de5dd7..850e896e26d4a60cd391df06e6473c69d69f0806 100644
--- a/hyrax/app/helpers/hyrax_helper.rb
+++ b/hyrax/app/helpers/hyrax_helper.rb
@@ -164,6 +164,6 @@ module HyraxHelper
     s3.init_client
 
     meta_object = s3.system_metadata_object(work_id)
-    meta_object.present? and (work.date_modified < DateTime.parse(meta_object.last_modified.to_s))
+    meta_object.present? and (work.date_modified.to_i <= DateTime.parse(meta_object.last_modified.to_s).to_i)
   end
 end
diff --git a/hyrax/app/listeners/hyrax_listener.rb b/hyrax/app/listeners/hyrax_listener.rb
index 57dcb10e925631d937f77c128638144b6ebb3fdf..d2dc4169396cdf68188728314b5c79a86832a9a5 100644
--- a/hyrax/app/listeners/hyrax_listener.rb
+++ b/hyrax/app/listeners/hyrax_listener.rb
@@ -91,7 +91,7 @@ class HyraxListener
 
   def on_object_metadata_updated(event)
     object = before_save_callbacks(event[:object])
-    object = after_save_callbacks(event[:object])
+    object = after_save_callbacks(object)
     ContentUpdateEventJob.perform_later(object, event[:user])
   end
 end
diff --git a/hyrax/app/models/concerns/common_works_query.rb b/hyrax/app/models/concerns/common_works_query.rb
index e94ad2b6f9d3fb4d4a68e60114e9d70ae871d5b9..8644d104c0f2f6009b6fec5d57014f4e55302ccf 100644
--- a/hyrax/app/models/concerns/common_works_query.rb
+++ b/hyrax/app/models/concerns/common_works_query.rb
@@ -2,6 +2,7 @@ module CommonWorksQuery
   extend ActiveSupport::Concern
 
   def parent_collections
+    return [] unless self.persisted?
     collection = Hyrax.query_service.custom_queries.find_parent_collections(resource: self)
   end
 end
\ No newline at end of file
diff --git a/hyrax/app/models/concerns/s3_file_handleable.rb b/hyrax/app/models/concerns/s3_file_handleable.rb
index c7cc1580d211fc573401b5621962a340b6b58373..73c40f99a6b097f11c263883a487971f9cede974 100644
--- a/hyrax/app/models/concerns/s3_file_handleable.rb
+++ b/hyrax/app/models/concerns/s3_file_handleable.rb
@@ -18,7 +18,8 @@ module S3FileHandleable
     if self.class.in?([Dataset, Crc1280Experiment])
       bucket_name = s3.sanitise_name(ENV.fetch("S3_FILE_UPLOAD_BUCKET"))
       user = ::User.find_by_user_key(self.depositor)
-      s3.delete_bucket(bucket_name)
+      all_objects, size = s3.list_all_objects(bucket_name, self.id.to_s)
+      s3.delete_objects(bucket_name, all_objects.map { |obj| obj[:key] }) if all_objects.present?
       if self.class == Crc1280Experiment
         self.complex_subjects.destroy_all
       end
@@ -27,7 +28,7 @@ module S3FileHandleable
       user = ::User.find_by_user_key(self.crc1280_experiment.depositor)
       objects_prefix = objects_prefix(self, s3_folder_name)
       all_objects, size = s3.list_all_objects(bucket_name, objects_prefix)
-      s3.delete_objects(bucket_name, all_objects.map{|obj| obj[:key]})
+      s3.delete_objects(bucket_name, all_objects.map{|obj| obj[:key]}) if all_objects.present?
     end
 
     self.file_sets.each do |file_set|
diff --git a/hyrax/app/models/dataset.rb b/hyrax/app/models/dataset.rb
index c7290ef6a2dd1f3652f291cc37344e51dd78063b..b12f4b88b3c1694b71e266c0869976f98f957a2d 100644
--- a/hyrax/app/models/dataset.rb
+++ b/hyrax/app/models/dataset.rb
@@ -13,6 +13,7 @@ class Dataset < Hyrax::Work
   include CommonWorksQuery
   include ::Hyrax::TombstoneBehavior
   include ExternalServices
+  include S3FileHandleable
 
   def default_admin_set
     AdminSetHelper.find_admin_set_by_property(title: [ENV.fetch('RUB_ADMIN_SET_TITLE', 'RUB publication workflow')])
diff --git a/hyrax/app/services/hyrax/valkyrie_upload.rb b/hyrax/app/services/hyrax/valkyrie_upload.rb
index 25fe4cde97f2f1e5af51cf06df5eb4c6809b714e..ef52eafac9f1ea1c759d45398e005d428dec6629 100644
--- a/hyrax/app/services/hyrax/valkyrie_upload.rb
+++ b/hyrax/app/services/hyrax/valkyrie_upload.rb
@@ -43,7 +43,7 @@ class Hyrax::ValkyrieUpload
     parent_object = file_set.parent_object
     siblings = parent_object.file_sets
 
-    duplicate_record = siblings.select {|fs| fs.title[0]&.downcase == filename && fs.id != file_set.id }
+    duplicate_record = siblings.select {|fs| fs.title[0]&.downcase == filename.downcase && fs.id != file_set.id }
     new_title = nil
 
     if duplicate_record.present?
@@ -55,13 +55,13 @@ class Hyrax::ValkyrieUpload
     file_size = io.size
     mime_type ||= file_set.get_mime_type
 
-    streamfile = storage_adapter.upload(file: io, original_filename: filename, resource: file_set)
+    streamfile = storage_adapter.upload(file: io, original_filename: new_title || filename, resource: file_set)
     file_metadata = Hyrax::FileMetadata(streamfile)
     file_metadata.file_set_id = file_set.id
     file_metadata.pcdm_use = Array(use)
     file_metadata.recorded_size = Array(io.size)
     file_metadata.mime_type = mime_type if mime_type
-    file_metadata.original_filename = File.basename(filename).to_s || File.basename(io)
+    file_metadata.original_filename = File.basename(new_title || filename).to_s || File.basename(io)
 
     if use == Hyrax::FileMetadata::Use::ORIGINAL_FILE
       # Set file set label.
@@ -155,7 +155,7 @@ class Hyrax::ValkyrieUpload
 
     suffix = 1
     new_title = file_name
-    while existing_titles.include?(new_title)
+    while existing_titles.include?(new_title.downcase)
       new_title = "#{base_name}_#{suffix}#{extension}"
       suffix += 1
     end
diff --git a/hyrax/app/services/hyrax/work_uploads_handler.rb b/hyrax/app/services/hyrax/work_uploads_handler.rb
index 59b402630511687a9f1eb5f53dd5b90411a75398..225d1c740e8b1b6717cd3ea872ddc26543be42eb 100644
--- a/hyrax/app/services/hyrax/work_uploads_handler.rb
+++ b/hyrax/app/services/hyrax/work_uploads_handler.rb
@@ -159,6 +159,7 @@ module Hyrax
 
     def work_attributes_for(file)
       return {} unless @file_set_params.present?
+      return @file_set_params.first if @file_set_params.length == 1
 
       @file_set_params.find { |hash| hash[:uploaded_file_id].to_s == file.id.to_s } || {}
     end
diff --git a/hyrax/config/metadata/crc1280_experiment.yaml b/hyrax/config/metadata/crc1280_experiment.yaml
index 96e373709b62087f1f5d9f69662165fc46e67aba..15488802eede1f3956d86666d5369884b8bc8dfa 100644
--- a/hyrax/config/metadata/crc1280_experiment.yaml
+++ b/hyrax/config/metadata/crc1280_experiment.yaml
@@ -49,6 +49,7 @@ attributes:
     predicate: http://www.example.com/vocabs/rdms/isTombstone
   format:
     type: string
+    multiple: true
     index_keys:
       - "format_ssim"
     predicate: http://www.example.com/vocabs/rdms/format
diff --git a/hyrax/config/metadata/dataset.yaml b/hyrax/config/metadata/dataset.yaml
index 13cd7a7e87d1a5393ebb4e0227678db462750edf..45b7129555a07b7f7d4cc513407268351664e549 100644
--- a/hyrax/config/metadata/dataset.yaml
+++ b/hyrax/config/metadata/dataset.yaml
@@ -49,6 +49,7 @@ attributes:
     predicate: http://www.example.com/vocabs/rdms/isTombstone
   format:
     type: string
+    multiple: true
     index_keys:
       - "format_ssim"
     predicate: http://www.example.com/vocabs/rdms/format