diff --git a/VERSION b/VERSION
index 450a687b2..6e66c4c20 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.28.1
+1.28.1.3
diff --git a/app/assets/images/icon_small/sequence-editor.svg b/app/assets/images/icon_small/sequence-editor.svg
new file mode 100644
index 000000000..b528c6c3f
--- /dev/null
+++ b/app/assets/images/icon_small/sequence-editor.svg
@@ -0,0 +1,10 @@
+
diff --git a/app/assets/javascripts/i18n_bundle.js b/app/assets/javascripts/i18n_bundle.js
new file mode 100644
index 000000000..04bbf3cf2
--- /dev/null
+++ b/app/assets/javascripts/i18n_bundle.js
@@ -0,0 +1,2 @@
+//= require i18n.js
+//= require i18n/translations
diff --git a/app/assets/javascripts/protocols/import_export/import.js b/app/assets/javascripts/protocols/import_export/import.js
index 000031aa4..d1e98c722 100644
--- a/app/assets/javascripts/protocols/import_export/import.js
+++ b/app/assets/javascripts/protocols/import_export/import.js
@@ -58,12 +58,41 @@ function importProtocolFromFile(
}
function getAssetBytes(folder, stepGuid, fileRef) {
- var stepPath = stepGuid ? stepGuid + '/' : '';
- var filePath = folder + stepPath + fileRef;
- var assetBytes = zipFiles.files[cleanFilePath(filePath)].asBinary();
+ const stepPath = stepGuid ? stepGuid + '/' : '';
+ const filePath = folder + stepPath + fileRef;
+ const assetBytes = zipFiles.files[cleanFilePath(filePath)].asBinary();
return window.btoa(assetBytes);
}
+ function getAssetPreview(folder, stepGuid, fileRef, fileName, fileType) {
+ if ($.inArray(fileType, ['image/png', 'image/jpeg', 'image/gif', 'image/bmp']) > 0) {
+ return {
+ fileName: fileName,
+ fileType: fileType,
+ bytes: getAssetBytes(folder, stepGuid, fileRef)
+ };
+ } else {
+ const stepPath = stepGuid ? folder + stepGuid + '/' : folder;
+ let baseName;
+ baseName = fileRef.split('.');
+ baseName.pop();
+ baseName.join('.');
+ let previewFileRef = zipFiles.file(new RegExp(stepPath + 'previews/' + baseName));
+ if (previewFileRef.length > 0) {
+ const previewFileExt = previewFileRef[0].name.split('.').at(-1);
+ let previewFileName = fileName.split('.');
+ previewFileName.splice(-1, 1, previewFileExt);
+ previewFileName.join('.');
+ return {
+ fileName: previewFileName,
+ fileType: `image/${previewFileExt}`,
+ bytes: window.btoa(previewFileRef[0].asBinary())
+ };
+ }
+ }
+ return null;
+ }
+
/* Template functions */
function newPreviewElement(name, values) {
@@ -82,14 +111,14 @@ function importProtocolFromFile(
}
function newAssetElement(folder, stepGuid, fileRef, fileName, fileType) {
- var html = '
';
- var assetBytes;
- if ($.inArray(fileType, ['image/png', 'image/jpeg', 'image/gif', 'image/bmp']) > 0) {
- assetBytes = getAssetBytes(folder, stepGuid, fileRef);
+ let html = '';
+ let assetPreview = getAssetPreview(folder, stepGuid, fileRef, fileName, fileType);
- html += '';
+ if (assetPreview) {
+ html += '';
html += '
';
}
+
html += '' + fileName + '';
html += '';
return $.parseHTML(html);
@@ -708,6 +737,7 @@ function importProtocolFromFile(
var assetId = $(this).attr('id');
var fileRef = $(this).attr('fileRef');
var fileName = $(this).children('fileName').text();
+
stepAssetJson.id = assetId;
stepAssetJson.fileName = fileName;
stepAssetJson.fileType = $(this).children('fileType').text();
@@ -723,6 +753,14 @@ function importProtocolFromFile(
fileRef
);
+ stepAssetJson.preview_image = getAssetPreview(
+ protocolFolders[index],
+ stepGuid,
+ fileRef,
+ fileName,
+ null
+ );
+
stepAssetsJson.push(stepAssetJson);
});
stepJson.assets = stepAssetsJson;
diff --git a/app/assets/javascripts/sitewide/active_storage_previews.js b/app/assets/javascripts/sitewide/active_storage_previews.js
index 32697ae23..7596bf168 100644
--- a/app/assets/javascripts/sitewide/active_storage_previews.js
+++ b/app/assets/javascripts/sitewide/active_storage_previews.js
@@ -17,6 +17,8 @@ var ActiveStoragePreviews = (function() {
if (img.retryCount >= RETRY_COUNT) return;
+ $(img).css('opacity', 0);
+
if (!$(img).parent().hasClass('processing')) $(img).parent().addClass('processing');
setTimeout(() => {
diff --git a/app/assets/javascripts/sitewide/iframe_modal.js b/app/assets/javascripts/sitewide/iframe_modal.js
new file mode 100644
index 000000000..d50df5ad9
--- /dev/null
+++ b/app/assets/javascripts/sitewide/iframe_modal.js
@@ -0,0 +1,31 @@
+/* global iFrameModal */
+// General-purpose iframe modal. For closing the modal, you need will to take care of triggering
+// the 'hide' event on the modal itself, example from inside the iframe:
+// parent.document.getElementById('iFrameModal').dispatchEvent(new Event('hide'));
+
+$(document).on('turbolinks:load', function() {
+ window.iFrameModal = document.getElementById('iFrameModal');
+ let iFrameModalFrame = document.getElementById('iFrameModalFrame');
+
+ window.showIFrameModal = (url) => {
+ iFrameModalFrame.setAttribute('src', url);
+ iFrameModal.classList.remove('hidden');
+ iFrameModal.dispatchEvent(new Event('shown'));
+ };
+
+ iFrameModal.addEventListener('hide', () => {
+ iFrameModal.classList.add('hidden');
+ iFrameModalFrame.removeAttribute('src');
+ iFrameModal.dispatchEvent(new Event('hidden'));
+ });
+
+ iFrameModal.addEventListener('shown', () => {
+ document.body.classList.add('overflow-hidden');
+ document.body.classList.remove('overflow-auto');
+ });
+
+ iFrameModal.addEventListener('hidden', () => {
+ document.body.classList.remove('overflow-hidden');
+ document.body.classList.add('overflow-auto');
+ });
+});
diff --git a/app/assets/javascripts/sitewide/marvinjs_editor.js b/app/assets/javascripts/sitewide/marvinjs_editor.js
index 60fa514d4..38021f77f 100644
--- a/app/assets/javascripts/sitewide/marvinjs_editor.js
+++ b/app/assets/javascripts/sitewide/marvinjs_editor.js
@@ -303,6 +303,12 @@ $(document).on('click', '.marvinjs-edit-button', function() {
});
});
+$(document).on('click', '.gene-sequence-edit-button', function() {
+ var editButton = $(this);
+ $('#filePreviewModal').modal('hide');
+ window.showIFrameModal(editButton.data('sequence-edit-url'));
+});
+
$(document).on('turbolinks:load', function() {
MarvinJsEditor = MarvinJsEditorApi();
if (MarvinJsEditor.enabled()) {
diff --git a/app/assets/stylesheets/shared/assets.scss b/app/assets/stylesheets/shared/assets.scss
index fc6a4a892..6336b2f14 100644
--- a/app/assets/stylesheets/shared/assets.scss
+++ b/app/assets/stylesheets/shared/assets.scss
@@ -477,3 +477,15 @@
padding: 4px 8px;
white-space: nowrap;
}
+
+.sn-file-ove {
+ height: 1.5rem;
+ width: 1.5rem;
+
+ &::before {
+ content: url("icon_small/sequence-editor.svg");
+ display: inline-block;
+ margin: auto;
+ width: 100%;
+ }
+}
diff --git a/app/assets/stylesheets/shared/file_preview.scss b/app/assets/stylesheets/shared/file_preview.scss
index 145147c91..dbf903698 100644
--- a/app/assets/stylesheets/shared/file_preview.scss
+++ b/app/assets/stylesheets/shared/file_preview.scss
@@ -26,11 +26,22 @@
.file-preview-container {
align-items: center;
+ background-color: var(--sn-color-white);
display: flex;
- height: 100%;
+ height: calc(100% - 4rem);
justify-content: center;
+ margin: 2rem;
text-align: center;
- width: 100%;
+ width: calc(100% - 4rem);
+
+ .asset-image {
+ background-color: var(--sn-white);
+ }
+
+ .gene-sequence-asset {
+ height: 500px;
+ width: 500px;
+ }
&.processing {
background-image: url("/images/medium/loading_white.svg");
diff --git a/app/assets/stylesheets/shared_styles/elements/input_fields.scss b/app/assets/stylesheets/shared_styles/elements/input_fields.scss
index 00c27c3ab..e081a9d2c 100644
--- a/app/assets/stylesheets/shared_styles/elements/input_fields.scss
+++ b/app/assets/stylesheets/shared_styles/elements/input_fields.scss
@@ -24,12 +24,18 @@
transition: .3s;
width: 100%;
+ &:hover {
+ border: 1px solid var(--sn-science-blue-hover);
+ }
+
&:focus {
border: $border-focus;
}
&:disabled {
- background: transparent;
+ background-color: var(--sn-super-light-grey);
+ color: var(--sn-light-grey);
+ border: 1px solid var(--sn-light-grey);
}
&::placeholder {
diff --git a/app/assets/stylesheets/sn_icon_font.css b/app/assets/stylesheets/sn_icon_font.css
new file mode 100644
index 000000000..3c023c6f9
--- /dev/null
+++ b/app/assets/stylesheets/sn_icon_font.css
@@ -0,0 +1,4 @@
+/*
+*= require sn-icon-font
+*= require sn-inter-font
+*/
diff --git a/app/assets/stylesheets/tailwind/inputs.css b/app/assets/stylesheets/tailwind/inputs.css
index 891c63fe6..c4acd18ab 100644
--- a/app/assets/stylesheets/tailwind/inputs.css
+++ b/app/assets/stylesheets/tailwind/inputs.css
@@ -32,6 +32,16 @@
@apply border-sn-science-blue shadow-none;
}
+ .sci-input-container-v2 input:hover {
+ border-color: var(--sn-science-blue-hover);
+ }
+
+ .sci-input-container-v2 input:disabled {
+ background-color: var(--sn-super-light-grey);
+ color: var(--sn-light-grey);
+ border: 1px solid var(--sn-light-grey);
+ }
+
.sci-input-container-v2 .sn-icon {
@apply m-2 text-sn-black;
}
diff --git a/app/controllers/access_permissions/projects_controller.rb b/app/controllers/access_permissions/projects_controller.rb
index 4d84406d2..5948429ef 100644
--- a/app/controllers/access_permissions/projects_controller.rb
+++ b/app/controllers/access_permissions/projects_controller.rb
@@ -99,21 +99,11 @@ module AccessPermissions
raise ActiveRecord::RecordInvalid
end
- if @project.visible?
- user_assignment.update!(
- user_role: @project.default_public_user_role,
- assigned: :automatically
- )
- else
- user_assignment.destroy!
- end
-
propagate_job(user_assignment, destroy: true)
log_activity(:unassign_user_from_project, { user_target: user_assignment.user.id,
role: user_assignment.user_role.name })
- render json: { flash: t('access_permissions.destroy.success', member_name: escape_input(user.full_name)) },
- status: :ok
+ render json: { flash: t('access_permissions.destroy.success', member_name: escape_input(user.full_name)) }
rescue ActiveRecord::RecordInvalid
render json: { flash: t('access_permissions.destroy.failure') },
status: :unprocessable_entity
diff --git a/app/controllers/at_who_controller.rb b/app/controllers/at_who_controller.rb
index 805d0bc7b..f6a801d11 100644
--- a/app/controllers/at_who_controller.rb
+++ b/app/controllers/at_who_controller.rb
@@ -29,13 +29,18 @@ class AtWhoController < ApplicationController
else
Repository.active.accessible_by_teams(@team).first
end
+
+ items = []
+ repository_id = nil
+
if repository && can_read_repository?(repository)
+ assignable_my_module =
+ if params[:assignable_my_module_id].present?
+ MyModule.viewable_by_user(current_user, @team).find_by(id: params[:assignable_my_module_id])
+ end
items = SmartAnnotation.new(current_user, current_team, @query)
- .repository_rows(repository, params[:assignable_my_module_id])
+ .repository_rows(repository, assignable_my_module&.id)
repository_id = repository.id
- else
- items = []
- repository_id = nil
end
render json: {
res: [
diff --git a/app/controllers/gene_sequence_assets_controller.rb b/app/controllers/gene_sequence_assets_controller.rb
new file mode 100644
index 000000000..7ce3e313f
--- /dev/null
+++ b/app/controllers/gene_sequence_assets_controller.rb
@@ -0,0 +1,176 @@
+# frozen_string_literal: true
+
+class GeneSequenceAssetsController < ApplicationController
+ include ActiveStorage::SetCurrent
+
+ skip_before_action :verify_authenticity_token
+
+ before_action :check_open_vector_service_enabled, except: %i(new edit)
+ before_action :load_vars, except: %i(new create)
+ before_action :load_create_vars, only: %i(new create)
+
+ before_action :check_read_permission
+ before_action :check_manage_permission, only: %i(new update create)
+
+ def new
+ render :edit, layout: false
+ end
+
+ def edit
+ @file_url = rails_representation_url(@asset.file)
+ @file_name = @asset.render_file_name
+ log_activity('sequence_asset_edit_started')
+ render :edit, layout: false
+ end
+
+ def create
+ save_asset!
+ log_activity('sequence_asset_added')
+ head :ok
+ end
+
+ def update
+ save_asset!
+ log_activity('sequence_asset_edit_finished')
+ head :ok
+ end
+
+ def destroy
+ log_activity('sequence_asset_deleted')
+ head :ok
+ end
+
+ private
+
+ def save_asset!
+ ActiveRecord::Base.transaction do
+ ensure_asset!
+
+ @asset.file.purge
+ @asset.preview_image.purge
+
+ @asset.file.attach(
+ io: StringIO.new(params[:sequence_data].to_json),
+ filename: "#{params[:sequence_name]}.json"
+ )
+
+ @asset.preview_image.attach(
+ io: StringIO.new(Base64.decode64(params[:base64_image].split(',').last)),
+ filename: "#{params[:sequence_name]}.png"
+ )
+
+ file = @asset.file
+
+ file.blob.metadata['asset_type'] = 'gene_sequence'
+ file.blob.metadata['name'] = params[:sequence_name]
+ file.save!
+
+ @asset.view_mode = @parent.assets_view_mode
+
+ @asset.save!
+ end
+ end
+
+ def ensure_asset!
+ return if @asset
+ return unless @parent
+
+ @asset = @parent.assets.create!(last_modified_by: current_user, team: current_team)
+ end
+
+ def load_vars
+ @ove_enabled = OpenVectorEditorService.enabled?
+ @asset = current_team.assets.find_by(id: params[:id])
+ return render_404 unless @asset
+
+ @parent ||= @asset.step
+ @parent ||= @asset.result
+
+ case @parent
+ when Step
+ @protocol = @parent.protocol
+ when Result
+ @my_module = @parent.my_module
+ end
+ end
+
+ def load_create_vars
+ @ove_enabled = OpenVectorEditorService.enabled?
+ @parent = case params[:parent_type]
+ when 'Step'
+ Step.find_by(id: params[:parent_id])
+ when 'Result'
+ Result.find_by(id: params[:parent_id])
+ end
+
+ case @parent
+ when Step
+ @protocol = @parent.protocol
+ when Result
+ @result = @parent
+ end
+ end
+
+ def check_read_permission
+ case @parent
+ when Step
+ return render_403 unless can_read_protocol_in_module?(@protocol) ||
+ can_read_protocol_in_repository?(@protocol)
+ when Result
+ return render_403 unless can_read_result?(@parent)
+ else
+ render_403
+ end
+ end
+
+ def check_manage_permission
+ render_403 unless asset_managable?
+ end
+
+ def check_open_vector_service_enabled
+ render_403 unless OpenVectorEditorService.enabled?
+ end
+
+ helper_method :asset_managable?
+ def asset_managable?
+ case @parent
+ when Step
+ can_manage_step?(@parent)
+ when Result
+ can_manage_result?(@parent)
+ else
+ false
+ end
+ end
+
+ def log_activity(type_of, project = nil, message_items = {})
+ return unless @parent.is_a?(Step)
+
+ my_module = @parent.my_module
+ default_items = {
+ protocol: @parent.protocol.id,
+ step: @parent.id,
+ asset_name: { id: @asset.id, value_for: 'file_name' },
+ step_position: { id: @parent.id, value_for: 'position_plus_one' }
+ }
+
+ if my_module
+ project = my_module.project
+ default_items[:my_module] = my_module.id
+ type_of = "task_#{type_of}".to_sym
+ else
+ type_of = "protocol_#{type_of}".to_sym
+ end
+
+ message_items = default_items.merge(message_items)
+
+ Activities::CreateActivityService.call(
+ activity_type: type_of,
+ owner: current_user,
+ team: @parent.protocol.team,
+ subject: @parent.protocol,
+ message_items: message_items,
+ project: project
+ )
+ end
+end
diff --git a/app/controllers/protocols_controller.rb b/app/controllers/protocols_controller.rb
index 8a84255e5..7a46b538f 100644
--- a/app/controllers/protocols_controller.rb
+++ b/app/controllers/protocols_controller.rb
@@ -697,6 +697,12 @@ class ProtocolsController < ApplicationController
asset_file_name = asset_guid.to_s + File.extname(asset.file_name).to_s
ostream.put_next_entry("#{step_dir}/#{asset_file_name}")
ostream.print(asset.file.download)
+
+ next unless asset.preview_image.attached?
+
+ asset_preview_image_name = asset_guid.to_s + File.extname(asset.preview_image_file_name).to_s
+ ostream.put_next_entry("#{step_dir}/previews/#{asset_preview_image_name}")
+ ostream.print(asset.preview_image.download)
end
end
ostream = step.tiny_mce_assets.save_to_eln(ostream, step_dir)
diff --git a/app/controllers/users/settings/account/connected_accounts_controller.rb b/app/controllers/users/settings/account/connected_accounts_controller.rb
index 8f3c981de..d30a2579d 100644
--- a/app/controllers/users/settings/account/connected_accounts_controller.rb
+++ b/app/controllers/users/settings/account/connected_accounts_controller.rb
@@ -9,20 +9,15 @@ module Users
end
def destroy
- settings = ApplicationSettings.instance
- if settings.values['azure_ad_apps']&.find { |v| v['provider_name'] == params[:provider] }
- provider = params[:provider]
- else
- flash[:error] = t('users.settings.account.connected_accounts.errors.not_found')
+ user_identity = current_user.user_identities.find_by(provider: params[:provider])
+ if user_identity.blank?
+ flash.now[:error] = t('users.settings.account.connected_accounts.errors.not_found')
return
end
- ActiveRecord::Base.transaction do
- __send__("#{provider}_pre_destroy".to_sym) if respond_to?("#{provider}_pre_destroy".to_sym, true)
- current_user.user_identities.where(provider: provider).take&.destroy!
- end
- flash[:success] = t('users.settings.account.connected_accounts.unlink_success')
+ user_identity.destroy!
+ flash.now[:success] = t('users.settings.account.connected_accounts.unlink_success')
rescue StandardError
- flash[:error] ||= t('users.settings.account.connected_accounts.errors.generic')
+ flash.now[:error] ||= t('users.settings.account.connected_accounts.errors.generic')
ensure
@linked_accounts = current_user.user_identities.pluck(:provider)
render :index
diff --git a/app/helpers/file_icons_helper.rb b/app/helpers/file_icons_helper.rb
index d5219e19d..adba2aab3 100644
--- a/app/helpers/file_icons_helper.rb
+++ b/app/helpers/file_icons_helper.rb
@@ -40,6 +40,8 @@ module FileIconsHelper
image_link = 'icon_small/pptx_file.svg'
elsif asset.file.attached? && asset.file.metadata['asset_type'] == 'marvinjs'
image_link = 'icon_small/marvinjs_file.svg'
+ elsif asset.file.attached? && asset.file.metadata['asset_type'] == 'gene_sequence'
+ image_link = 'icon_small/sequence-editor.svg'
end
# Now check for custom mappings or possible overrides
diff --git a/app/javascript/packs/open_vector_editor.js b/app/javascript/packs/open_vector_editor.js
new file mode 100644
index 000000000..af3675194
--- /dev/null
+++ b/app/javascript/packs/open_vector_editor.js
@@ -0,0 +1,2 @@
+import '@teselagen/ove';
+import '@teselagen/ove/style.css';
diff --git a/app/javascript/packs/vue/open_vector_editor.js b/app/javascript/packs/vue/open_vector_editor.js
new file mode 100644
index 000000000..c8ca74ac9
--- /dev/null
+++ b/app/javascript/packs/vue/open_vector_editor.js
@@ -0,0 +1,11 @@
+import TurbolinksAdapter from 'vue-turbolinks';
+import Vue from 'vue/dist/vue.esm';
+import OpenVectorEditor from '../../vue/ove/OpenVectorEditor.vue';
+
+Vue.use(TurbolinksAdapter);
+Vue.prototype.i18n = window.I18n;
+
+new Vue({
+ el: '#open-vector-editor',
+ components: { OpenVectorEditor }
+});
diff --git a/app/javascript/vue/ove/OpenVectorEditor.vue b/app/javascript/vue/ove/OpenVectorEditor.vue
new file mode 100644
index 000000000..ae52453ea
--- /dev/null
+++ b/app/javascript/vue/ove/OpenVectorEditor.vue
@@ -0,0 +1,154 @@
+
+
+
+
+
diff --git a/app/javascript/vue/protocol/step.vue b/app/javascript/vue/protocol/step.vue
index ecee1aaa6..3a04ff921 100644
--- a/app/javascript/vue/protocol/step.vue
+++ b/app/javascript/vue/protocol/step.vue
@@ -96,6 +96,9 @@
{{ i18n.t('assets.create_wopi_file.button_text') }}
+
+ {{ i18n.t('open_vector_editor.new_sequence_file') }}
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {{ i18n.t("protocols.steps.attachments.file_modal.drag_zone_title") }}
+
+
+ {{ i18n.t("protocols.steps.attachments.file_modal.drag_zone_description") }}
+
+
+
+
+ {{ i18n.t("protocols.steps.attachments.file_modal.drag_zone_notification", {position: step.attributes.position + 1}) }}
+
+
+
+ {{ i18n.t("protocols.steps.attachments.file_modal.or") }}
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/vue/protocol/step_attachments/thumbnail.vue b/app/javascript/vue/protocol/step_attachments/thumbnail.vue
new file mode 100644
index 000000000..0e85c05a5
--- /dev/null
+++ b/app/javascript/vue/protocol/step_attachments/thumbnail.vue
@@ -0,0 +1,64 @@
+
+
+
+
+
+
diff --git a/app/javascript/vue/protocol_import/file_import_modal.vue b/app/javascript/vue/protocol_import/file_import_modal.vue
index 02f761500..54f87c02f 100644
--- a/app/javascript/vue/protocol_import/file_import_modal.vue
+++ b/app/javascript/vue/protocol_import/file_import_modal.vue
@@ -9,10 +9,6 @@
diff --git a/app/views/projects/index/modals/_new_project.html.erb b/app/views/projects/index/modals/_new_project.html.erb
index 856afeb47..dabecdc67 100644
--- a/app/views/projects/index/modals/_new_project.html.erb
+++ b/app/views/projects/index/modals/_new_project.html.erb
@@ -40,7 +40,7 @@
diff --git a/app/views/protocols/index/_new_protocol_modal.html.erb b/app/views/protocols/index/_new_protocol_modal.html.erb
index cd7ad5ca7..2c7a9021f 100644
--- a/app/views/protocols/index/_new_protocol_modal.html.erb
+++ b/app/views/protocols/index/_new_protocol_modal.html.erb
@@ -41,7 +41,7 @@
diff --git a/app/views/result_assets/_edit.html.erb b/app/views/result_assets/_edit.html.erb
index 2c0d76d44..5328a80c0 100644
--- a/app/views/result_assets/_edit.html.erb
+++ b/app/views/result_assets/_edit.html.erb
@@ -17,8 +17,7 @@
- <%= f.button t("general.save"),
- class: 'btn btn-primary save-result' %>
+ <%= f.submit t("general.save"), class: 'btn btn-primary save-result' %>
<% end %>
diff --git a/app/views/result_tables/_edit.html.erb b/app/views/result_tables/_edit.html.erb
index 5c93ceac9..b2615ad88 100644
--- a/app/views/result_tables/_edit.html.erb
+++ b/app/views/result_tables/_edit.html.erb
@@ -18,8 +18,7 @@
- <%= f.button t("general.save"),
- class: 'btn btn-primary save-result' %>
+ <%= f.submit t("general.save"), class: 'btn btn-primary save-result' %>
<% end %>
diff --git a/app/views/result_tables/_new.html.erb b/app/views/result_tables/_new.html.erb
index 47a5ca52d..890dc734b 100644
--- a/app/views/result_tables/_new.html.erb
+++ b/app/views/result_tables/_new.html.erb
@@ -17,8 +17,7 @@
- <%= f.button t("result_tables.new.create"),
- class: 'btn btn-primary save-result' %>
+ <%= f.submit t("result_tables.new.create"), class: 'btn btn-primary save-result' %>
<% end %>
diff --git a/app/views/result_texts/_edit.html.erb b/app/views/result_texts/_edit.html.erb
index 1001e20ad..99f4efaa7 100644
--- a/app/views/result_texts/_edit.html.erb
+++ b/app/views/result_texts/_edit.html.erb
@@ -19,8 +19,7 @@
- <%= f.button t("general.save"),
- class: 'btn btn-primary save-result' %>
+ <%= f.submit t("general.save"), class: 'btn btn-primary save-result' %>
<% end %>
diff --git a/app/views/result_texts/_new.html.erb b/app/views/result_texts/_new.html.erb
index d80694d2a..fb2b42be4 100644
--- a/app/views/result_texts/_new.html.erb
+++ b/app/views/result_texts/_new.html.erb
@@ -18,8 +18,7 @@
- <%= f.button t("result_texts.new.create"),
- class: 'btn btn-primary save-result' %>
+ <%= f.submit t("result_texts.new.create"), class: 'btn btn-primary save-result' %>
<% end %>
diff --git a/app/views/search/results/_assets.html.erb b/app/views/search/results/_assets.html.erb
index 997e3ee81..6da353cd6 100644
--- a/app/views/search/results/_assets.html.erb
+++ b/app/views/search/results/_assets.html.erb
@@ -1,7 +1,9 @@
<% @asset_results.each do |asset| %>
-
+
<% if asset.blob.metadata["asset_type"] == 'marvinjs' %>
+ <% elsif asset.blob.metadata["asset_type"] == 'gene_sequence' %>
+
<% else %>
<% if wopi_file?(asset) %>
<%= file_extension_icon(asset) %>
diff --git a/app/views/shareable_links/my_modules/step_attachments/_file_preview.html.erb b/app/views/shareable_links/my_modules/step_attachments/_file_preview.html.erb
index 1c727a4d5..54018d17d 100644
--- a/app/views/shareable_links/my_modules/step_attachments/_file_preview.html.erb
+++ b/app/views/shareable_links/my_modules/step_attachments/_file_preview.html.erb
@@ -32,7 +32,7 @@
<% if asset.pdf_previewable? %>
<%= render partial: 'shared/pdf_viewer', locals: { asset: asset, report_document: false, shareable_document: true } %>
- <% elsif asset.previewable? && asset.large_preview.image.attached? %>
+ <% elsif asset.previewable? && asset.large_preview&.image&.attached? %>
<%= image_tag asset.large_preview.url(expires_in: Constants::URL_SHORT_EXPIRE_TIME.minutes),
class: 'asset-image',
style: 'opacity: 0' %>
@@ -50,7 +50,7 @@
class: "previous-asset shareable-gallery-switcher",
data: { id: previous_asset.id } do %>
- <% if previous_asset.previewable? && previous_asset.medium_preview.image.attached? %>
+ <% if previous_asset.previewable? && previous_asset.medium_preview&.image&.attached? %>
<%= image_tag previous_asset.medium_preview.url(expires_in: Constants::URL_SHORT_EXPIRE_TIME.minutes),
class: 'asset-image',
style: 'opacity: 0' %>
@@ -67,7 +67,7 @@
<%= link_to '#',
class: "next-asset shareable-gallery-switcher",
data: { id: next_asset.id } do %>
- <% if next_asset.previewable? && next_asset.medium_preview.image.attached? %>
+ <% if next_asset.previewable? && next_asset.medium_preview&.image&.attached? %>
<%= image_tag next_asset.medium_preview.url(expires_in: Constants::URL_SHORT_EXPIRE_TIME.minutes),
class: 'asset-image',
style: 'opacity: 0' %>
diff --git a/app/views/shareable_links/my_modules/step_attachments/_inline.html.erb b/app/views/shareable_links/my_modules/step_attachments/_inline.html.erb
index cd9bfab5b..7ff451b33 100644
--- a/app/views/shareable_links/my_modules/step_attachments/_inline.html.erb
+++ b/app/views/shareable_links/my_modules/step_attachments/_inline.html.erb
@@ -25,7 +25,7 @@
<% if asset.pdf_previewable? %>
<%= render partial: 'shared/pdf_viewer', locals: { asset: asset, report_document: false, shareable_document: true } %>
- <% elsif asset.previewable? && asset.large_preview.image.attached? %>
+ <% elsif asset.previewable? && asset.large_preview&.image&.attached? %>
<%= image_tag asset.large_preview.url(expires_in: Constants::URL_SHORT_EXPIRE_TIME.minutes),
class: 'asset-preview-image',
diff --git a/app/views/shareable_links/my_modules/step_attachments/_thumbnail.html.erb b/app/views/shareable_links/my_modules/step_attachments/_thumbnail.html.erb
index 2989ace52..1370e6d1a 100644
--- a/app/views/shareable_links/my_modules/step_attachments/_thumbnail.html.erb
+++ b/app/views/shareable_links/my_modules/step_attachments/_thumbnail.html.erb
@@ -7,7 +7,7 @@
id: asset.id
} do %>