mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-11 23:54:43 +08:00
Add new protocol modal [SCI-7810]
This commit is contained in:
parent
ae607839c1
commit
a95ca75362
13 changed files with 184 additions and 133 deletions
|
@ -35,63 +35,6 @@ function initEditProtocolDescription() {
|
|||
});
|
||||
}
|
||||
|
||||
function initCopyToRepository() {
|
||||
var link = "[data-action='copy-to-repository']";
|
||||
var modal = '#copy-to-repository-modal';
|
||||
var modalBody = '.modal-body';
|
||||
var submitBtn = ".modal-footer [data-action='submit']";
|
||||
$('.my-modules-protocols-index')
|
||||
.on('ajax:success', link, function(e, data) {
|
||||
$(modal).find(modalBody).html(data.html);
|
||||
$(modal).find(modalBody).find("[data-role='copy-to-repository']")
|
||||
.on('ajax:success', function(e2, data2) {
|
||||
if (data2.refresh !== null) {
|
||||
// Reload page
|
||||
location.reload();
|
||||
} else {
|
||||
// Simply hide the modal
|
||||
$(modal).modal('hide');
|
||||
}
|
||||
})
|
||||
.on('ajax:error', function(e2, data2) {
|
||||
// Display errors in form
|
||||
$(modal).find(submitBtn)[0].disabled = false;
|
||||
if (data2.status === 422) {
|
||||
$(this).renderFormErrors('protocol', data2.responseJSON);
|
||||
} else {
|
||||
// Simply display global error
|
||||
alert(data2.responseJSON.message);
|
||||
}
|
||||
});
|
||||
|
||||
$(modal).modal('show');
|
||||
$(modal).find(submitBtn)[0].disabled = false;
|
||||
})
|
||||
.on('ajax:error', function() {});
|
||||
|
||||
$(modal).on('click', submitBtn, function() {
|
||||
// Submit the embedded form
|
||||
$(modal).find(submitBtn)[0].disabled = true;
|
||||
$(modal).find('form').submit();
|
||||
});
|
||||
|
||||
$(modal).find(modalBody).on('click', "[data-role='link-check']", function() {
|
||||
var text = $(this).closest('.modal-body').find("[data-role='link-text']");
|
||||
if ($(this).prop('checked')) {
|
||||
text.show();
|
||||
} else {
|
||||
text.hide();
|
||||
}
|
||||
});
|
||||
|
||||
$(modal).on('hidden.bs.modal', function() {
|
||||
$(modal).find(modalBody).find("[data-role='copy-to-repository']")
|
||||
.off('ajax:success ajax:error');
|
||||
|
||||
$(modal).find(modalBody).html('');
|
||||
});
|
||||
}
|
||||
|
||||
function initLinkUpdate() {
|
||||
var modal = $('#confirm-link-update-modal');
|
||||
var modalTitle = modal.find('.modal-title');
|
||||
|
|
30
app/assets/javascripts/protocols/new_protocol.js
Normal file
30
app/assets/javascripts/protocols/new_protocol.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* global dropdownSelector HelperModule */
|
||||
(function() {
|
||||
$('#newProtocolModal').on('change', '#protocol_visibility', function() {
|
||||
$('#roleSelectWrapper').toggleClass('hidden', !$(this)[0].checked);
|
||||
});
|
||||
|
||||
let roleSelector = '#newProtocolModal #protocol_role_selector';
|
||||
dropdownSelector.init(roleSelector, {
|
||||
noEmptyOption: true,
|
||||
singleSelect: true,
|
||||
closeOnSelect: true,
|
||||
selectAppearance: 'simple',
|
||||
onChange: function() {
|
||||
$('#protocol_default_public_user_role_id').val(dropdownSelector.getValues(roleSelector));
|
||||
}
|
||||
});
|
||||
|
||||
$('#newProtocolModal')
|
||||
.on('ajax:error', 'form', function(e, error) {
|
||||
let msg = error.responseJSON.error;
|
||||
$('#newProtocolModal #protocol_name').parent().addClass('error').attr('data-error-text', msg);
|
||||
})
|
||||
.on('ajax:success', 'form', function(e, data) {
|
||||
if (data.message) {
|
||||
HelperModule.flashAlertMsg(data.message, 'success');
|
||||
}
|
||||
$('#newProtocolModal #protocol_name').parent().removeClass('error');
|
||||
$('#newProtocolModal').modal('hide');
|
||||
});
|
||||
}());
|
|
@ -233,3 +233,27 @@
|
|||
width: 90vw;
|
||||
}
|
||||
}
|
||||
|
||||
#newProtocolModal {
|
||||
.description {
|
||||
@include font-button;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.default-role-container {
|
||||
@include font-button;
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
margin: 1em 0;
|
||||
|
||||
.sci-checkbox-container {
|
||||
margin: 4px 8px 4px 0;
|
||||
}
|
||||
|
||||
small {
|
||||
@include font-small;
|
||||
display: block;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -256,29 +256,20 @@ class ProtocolsController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
@protocol = Protocol.new(
|
||||
team: @current_team,
|
||||
protocol_type: Protocol.protocol_types[:in_repository_draft],
|
||||
added_by: current_user,
|
||||
name: t('protocols.index.default_name')
|
||||
)
|
||||
|
||||
@protocol = Protocol.new(create_params)
|
||||
ts = Time.now
|
||||
@protocol.team = current_team
|
||||
@protocol.protocol_type = :in_repository_draft
|
||||
@protocol.added_by = current_user
|
||||
@protocol.record_timestamps = false
|
||||
@protocol.created_at = ts
|
||||
@protocol.updated_at = ts
|
||||
@protocol.published_on = ts if @type == :public
|
||||
|
||||
rename_record(@protocol, :name)
|
||||
if @protocol.save
|
||||
|
||||
log_activity(:create_protocol_in_repository, nil, protocol: @protocol.id)
|
||||
|
||||
TinyMceAsset.update_images(@protocol, params[:tiny_mce_images], current_user)
|
||||
redirect_to protocol_path(@protocol)
|
||||
else
|
||||
flash[:error] = @protocol.errors.full_messages.join(', ')
|
||||
redirect_to protocols_path
|
||||
render json: { error: @protocol.errors.full_messages.join(', ') }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -334,18 +325,10 @@ class ProtocolsController < ApplicationController
|
|||
end
|
||||
|
||||
def copy_to_repository
|
||||
link_protocols = params[:link] &&
|
||||
can_manage_protocol_in_module?(@protocol) &&
|
||||
can_create_protocols_in_repository?(@protocol.team)
|
||||
respond_to do |format|
|
||||
transaction_error = false
|
||||
Protocol.transaction do
|
||||
@new = @protocol.copy_to_repository(
|
||||
copy_to_repository_params[:name],
|
||||
copy_to_repository_params[:protocol_type],
|
||||
link_protocols,
|
||||
current_user
|
||||
)
|
||||
@new = @protocol.copy_to_repository(Protocol.new(create_params), current_user)
|
||||
rescue StandardError => e
|
||||
transaction_error = true
|
||||
Rails.logger.error(e.message)
|
||||
|
@ -353,23 +336,19 @@ class ProtocolsController < ApplicationController
|
|||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
format.json do
|
||||
if transaction_error
|
||||
# Bad request error
|
||||
format.json do
|
||||
render json: {
|
||||
message: t('my_modules.protocols.copy_to_repository_modal.error_400')
|
||||
},
|
||||
status: :bad_request
|
||||
end
|
||||
elsif @new.invalid?
|
||||
# Render errors
|
||||
format.json do
|
||||
render json: @new.errors,
|
||||
status: :unprocessable_entity
|
||||
end
|
||||
render json: { error: @new.errors.full_messages.join(', ') }, status: :unprocessable_entity
|
||||
else
|
||||
# Everything good, render 200
|
||||
format.json { render json: { refresh: link_protocols }, status: :ok }
|
||||
render json: { message: t('my_modules.protocols.copy_to_repository_modal.success_message') }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1241,7 +1220,7 @@ class ProtocolsController < ApplicationController
|
|||
end
|
||||
|
||||
def check_copy_to_repository_permissions
|
||||
@protocol = Protocol.find_by_id(params[:id])
|
||||
@protocol = Protocol.find_by(id: params[:id])
|
||||
@my_module = @protocol.my_module
|
||||
|
||||
render_403 unless @my_module.present? &&
|
||||
|
@ -1273,6 +1252,10 @@ class ProtocolsController < ApplicationController
|
|||
params.require(:protocol).permit(:name, :protocol_type)
|
||||
end
|
||||
|
||||
def create_params
|
||||
params.require(:protocol).permit(:name, :default_public_user_role_id, :visibility)
|
||||
end
|
||||
|
||||
def check_protocolsio_import_permissions
|
||||
render_403 unless can_create_protocols_in_repository?(current_team)
|
||||
end
|
||||
|
|
|
@ -31,9 +31,8 @@
|
|||
</li>
|
||||
<li>
|
||||
<a
|
||||
ref="saveProtocol"
|
||||
data-action="copy-to-repository"
|
||||
@click="saveProtocol"
|
||||
data-toggle="modal"
|
||||
data-target="#newProtocolModal"
|
||||
:class="{ disabled: !protocol.attributes.urls.save_to_repo_url }"
|
||||
>
|
||||
<span class="fas fa-save"></span>
|
||||
|
@ -132,7 +131,6 @@ export default {
|
|||
mounted() {
|
||||
// Legacy global functions from app/assets/javascripts/my_modules/protocols.js
|
||||
initLoadFromRepository();
|
||||
initCopyToRepository();
|
||||
initImport();
|
||||
initLinkUpdate();
|
||||
},
|
||||
|
@ -150,11 +148,6 @@ export default {
|
|||
$(this.$refs.loadProtocol).trigger("ajax:success", data);
|
||||
});
|
||||
},
|
||||
saveProtocol() {
|
||||
$.get(this.protocol.attributes.urls.save_to_repo_url).success((data) => {
|
||||
$(this.$refs.saveProtocol).trigger("ajax:success", data);
|
||||
});
|
||||
},
|
||||
unlinkProtocol() {
|
||||
$.get(this.protocol.attributes.urls.unlink_url).success((data) => {
|
||||
$(this.$refs.unlinkProtocol).trigger("ajax:success", data);
|
||||
|
|
28
app/jobs/user_assignments/protocol_group_assignment_job.rb
Normal file
28
app/jobs/user_assignments/protocol_group_assignment_job.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module UserAssignments
|
||||
class ProtocolGroupAssignmentJob < ApplicationJob
|
||||
queue_as :high_priority
|
||||
|
||||
def perform(team, protocols, assigned_by)
|
||||
@team = team
|
||||
@assigned_by = assigned_by
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
team.users.where.not(id: assigned_by).find_each do |user|
|
||||
user_assignment = UserAssignment.find_or_initialize_by(
|
||||
user: user,
|
||||
assignable: protocols
|
||||
)
|
||||
|
||||
next if user_assignment.manually_assigned?
|
||||
|
||||
user_assignment.update!(
|
||||
user_role: protocol.default_public_user_role || UserRole.find_predefined_viewer_role,
|
||||
assigned_by: @assigned_by
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,6 +19,7 @@ class Protocol < ApplicationRecord
|
|||
after_update :update_user_assignments, if: -> { saved_change_to_protocol_type? && in_repository? }
|
||||
after_destroy :decrement_linked_children
|
||||
after_save :update_linked_children
|
||||
after_create :auto_assign_protocol_members, if: :visible?
|
||||
skip_callback :create, :after, :create_users_assignments, if: -> { in_module? }
|
||||
|
||||
enum visibility: { hidden: 0, visible: 1 }
|
||||
|
@ -543,40 +544,16 @@ class Protocol < ApplicationRecord
|
|||
save!
|
||||
end
|
||||
|
||||
def copy_to_repository(new_name, new_protocol_type, link_protocols, current_user)
|
||||
clone = Protocol.new(
|
||||
name: new_name,
|
||||
description: description,
|
||||
protocol_type: new_protocol_type,
|
||||
added_by: current_user,
|
||||
team: team
|
||||
)
|
||||
clone.published_on = Time.now if clone.in_repository_public?
|
||||
|
||||
def copy_to_repository(clone, current_user)
|
||||
clone.team = team
|
||||
clone.protocol_type = :in_repository_draft
|
||||
clone.added_by = current_user
|
||||
# Don't proceed further if clone is invalid
|
||||
return clone if clone.invalid?
|
||||
|
||||
ActiveRecord::Base.no_touching do
|
||||
# Okay, clone seems to be valid: let's clone it
|
||||
clone = deep_clone(clone, current_user)
|
||||
|
||||
# If the above operation went well, update published_on
|
||||
# timestamp
|
||||
clone.update(published_on: Time.zone.now) if clone.in_repository_public?
|
||||
end
|
||||
|
||||
# Link protocols if neccesary
|
||||
if link_protocols
|
||||
reload
|
||||
self.name = clone.name
|
||||
self.record_timestamps = false
|
||||
self.added_by = current_user
|
||||
self.parent = clone
|
||||
ts = clone.updated_at
|
||||
self.parent_updated_at = ts
|
||||
self.updated_at = ts
|
||||
self.protocol_type = Protocol.protocol_types[:linked]
|
||||
save!
|
||||
end
|
||||
|
||||
clone
|
||||
|
@ -662,6 +639,14 @@ class Protocol < ApplicationRecord
|
|||
|
||||
private
|
||||
|
||||
def auto_assign_protocol_members
|
||||
UserAssignments::ProtocolGroupAssignmentJob.perform_now(
|
||||
team,
|
||||
self,
|
||||
last_modified_by || created_by
|
||||
)
|
||||
end
|
||||
|
||||
def update_user_assignments
|
||||
case visibility
|
||||
when 'visible'
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
<%= render partial: "my_modules/protocols/load_from_repository_modal.html.erb" %>
|
||||
|
||||
<!-- Copy to repository protocol modal -->
|
||||
<%= render partial: "my_modules/protocols/copy_to_repository_modal.html.erb" %>
|
||||
<%= render partial: "protocols/index/new_protocol_modal.html.erb", locals: {type: 'copy'} %>
|
||||
|
||||
<!-- Import protocol elements -->
|
||||
<%= render partial: "protocols/import_export/import_elements.html.erb" %>
|
||||
|
@ -182,6 +182,7 @@
|
|||
<%= javascript_include_tag("my_modules/pwa_mobile_app") %>
|
||||
<%= javascript_pack_tag 'pdfjs/pdf_js' %>
|
||||
<%= stylesheet_pack_tag 'pdfjs/pdf_js_styles' %>
|
||||
<%= javascript_include_tag "protocols/new_protocol" %>
|
||||
|
||||
<%= javascript_pack_tag 'vue/protocol' %>
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<%= render partial: "protocols/index/import_results_modal.html.erb" %>
|
||||
<%= render partial: "protocols/index/linked_children_modal.html.erb" %>
|
||||
<%= render partial: "protocols/index/protocolsio_modal.html.erb" %>
|
||||
<%= render partial: "protocols/index/new_protocol_modal.html.erb", locals: {type: 'new'} %>
|
||||
|
||||
<%= render partial: "protocols/import_export/import_elements.html.erb" %>
|
||||
|
||||
|
@ -54,5 +55,6 @@
|
|||
<%= stylesheet_link_tag 'datatables' %>
|
||||
<%= javascript_include_tag "assets/wopi/create_wopi_file" %>
|
||||
<%= javascript_include_tag "protocols/index" %>
|
||||
<%= javascript_include_tag "protocols/new_protocol" %>
|
||||
<%= javascript_pack_tag 'pdfjs/pdf_js' %>
|
||||
<%= stylesheet_pack_tag 'pdfjs/pdf_js_styles' %>
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
<template id="protocolGeneralToolbar">
|
||||
<div class="left-general-toolbar">
|
||||
<%= button_to protocols_path(type: @type), disabled: !can_create_protocols_in_repository?(@current_team), class: 'btn btn-primary only-active' do %>
|
||||
<button data-toggle="modal"
|
||||
data-target="#newProtocolModal"
|
||||
<%= 'disabled' if !can_create_protocols_in_repository?(@current_team) %>
|
||||
class="btn btn-primary only-active"
|
||||
>
|
||||
<span class="fas fa-plus"></span>
|
||||
<span class="hidden-xs"><%= t("protocols.index.create_new") %></span>
|
||||
<% end %>
|
||||
</button>
|
||||
|
||||
<div id="protocol-import-group" class="sci-btn-group only-active" role="group">
|
||||
<button class="btn btn-light btn-open-file <%= 'disabled' unless can_create_protocols_in_repository?(@current_team) %>"
|
||||
|
|
46
app/views/protocols/index/_new_protocol_modal.html.erb
Normal file
46
app/views/protocols/index/_new_protocol_modal.html.erb
Normal file
|
@ -0,0 +1,46 @@
|
|||
<div class="modal" id="newProtocolModal" tabindex="-1" role="dialog">
|
||||
<%= form_with model: @protocol || Protocol.new, url: type == 'new' ? protocols_path : copy_to_repository_protocol_path(@protocol), method: :post do |f| %>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<%= t('general.close') %>"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">
|
||||
<%= t("protocols.new_protocol_modal.title_#{type}") %>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="sci-input-container">
|
||||
<%= f.label :name, t("protocols.new_protocol_modal.name_label") %>
|
||||
<%= f.text_field :name, placeholder: t("protocols.new_protocol_modal.name_placeholder"), class: 'sci-input-field' %>
|
||||
</div>
|
||||
<% if type == 'copy' %>
|
||||
<p class="description">
|
||||
<%= t("protocols.new_protocol_modal.description") %>
|
||||
</p>
|
||||
<% end %>
|
||||
<div class="default-role-container">
|
||||
<div class="sci-checkbox-container">
|
||||
<%= f.check_box :visibility, { class: 'sci-checkbox'},:visible, :hidden %>
|
||||
<span class="sci-checkbox-label"></span>
|
||||
</div>
|
||||
<div class="default-role-description">
|
||||
<%= t("protocols.new_protocol_modal.access_label") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden" id="roleSelectWrapper">
|
||||
<div class="sci-input-container">
|
||||
<%= f.label :default_public_user_role_id, t("protocols.new_protocol_modal.role_label") %>
|
||||
<% default_role = UserRole.find_by(name: I18n.t('user_roles.predefined.viewer')).id %>
|
||||
<%= f.hidden_field :default_public_user_role_id, value: default_role %>
|
||||
<%= f.select :role_selector, options_for_select(user_roles_collection, default_role) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%= t('general.cancel') %></button>
|
||||
<%= f.button t("protocols.new_protocol_modal.create_#{type}") , class: "btn btn-primary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
|
@ -60,6 +60,7 @@ Rails.application.config.assets.precompile += %w(protocols/index.js)
|
|||
Rails.application.config.assets.precompile += %w(protocols/protocolsio.js)
|
||||
Rails.application.config.assets.precompile += %w(protocols/header.js)
|
||||
Rails.application.config.assets.precompile += %w(protocols/steps.js)
|
||||
Rails.application.config.assets.precompile += %w(protocols/new_protocol.js)
|
||||
Rails.application.config.assets.precompile += %w(protocols/edit.js)
|
||||
Rails.application.config.assets.precompile += %w(protocols/import_export/eln_table.js)
|
||||
Rails.application.config.assets.precompile += %w(protocols/import_export/import.js)
|
||||
|
|
|
@ -1127,6 +1127,7 @@ en:
|
|||
link_label: "Link task to this protocol in templates"
|
||||
link_text: "<strong>Warning!</strong> This will unlink the currently linked protocol."
|
||||
error_400: "Due to unknown error, protocol could not be copied to templates."
|
||||
success_message: "New protocol template was successfully saved. You can see it in protocol templates."
|
||||
confirm: "Save"
|
||||
load_from_file_flash: "Successfully loaded the protocol from the file."
|
||||
load_from_file_error: "Failed to load the protocol from file."
|
||||
|
@ -2655,6 +2656,16 @@ en:
|
|||
comment: "Revision comment"
|
||||
comment_placeholder: "What's new in this version?"
|
||||
publish: "Publish"
|
||||
new_protocol_modal:
|
||||
title_new: "Create new protocol template"
|
||||
title_copy: "Save as new protocol template"
|
||||
name_label: "Protocol template name"
|
||||
name_placeholder: "Enter a protocol template name…"
|
||||
description: "You will create a copy of a protocol and save it to Protocol templates."
|
||||
access_label: "Grant access to all team members"
|
||||
role_label: "Default user role"
|
||||
create_new: "Create"
|
||||
create_copy: "Save"
|
||||
header:
|
||||
details: 'Details'
|
||||
versions: 'Versions'
|
||||
|
|
Loading…
Add table
Reference in a new issue