mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-24 08:43:13 +08:00
Initial implementation of protocol processing modal [SCI-8661] (#5683)
* Initial implementation of protocol processing modal [SCI-8661] * Prepare placeholder jobs and integrate notifications [SCI-8661]
This commit is contained in:
parent
940ca1f096
commit
4a8582ebc8
11 changed files with 231 additions and 48 deletions
|
@ -667,28 +667,33 @@ var ProtocolsIndex = (function() {
|
|||
var importUrl = fileInput.attr('data-import-url');
|
||||
var teamId = fileInput.attr('data-team-id');
|
||||
var type = fileInput.attr('data-type');
|
||||
importProtocolFromFile(
|
||||
ev.target.files[0],
|
||||
importUrl,
|
||||
{ team_id: teamId, type: type },
|
||||
false,
|
||||
function(datas) {
|
||||
var nrSuccessful = 0;
|
||||
_.each(datas, function(data) {
|
||||
if (data.status === 'ok') {
|
||||
nrSuccessful += 1;
|
||||
}
|
||||
});
|
||||
animateSpinner(null, false);
|
||||
|
||||
if (nrSuccessful) {
|
||||
HelperModule.flashAlertMsg(I18n.t('protocols.index.import_results.message_ok_html', { count: nrSuccessful }), 'success');
|
||||
reloadTable();
|
||||
} else {
|
||||
HelperModule.flashAlertMsg(I18n.t('protocols.index.import_results.message_failed'), 'danger');
|
||||
if(ev.target.files[0].name.split('.').pop() === 'eln') {
|
||||
importProtocolFromFile(
|
||||
ev.target.files[0],
|
||||
importUrl,
|
||||
{ team_id: teamId, type: type },
|
||||
false,
|
||||
function(datas) {
|
||||
var nrSuccessful = 0;
|
||||
_.each(datas, function(data) {
|
||||
if (data.status === 'ok') {
|
||||
nrSuccessful += 1;
|
||||
}
|
||||
});
|
||||
animateSpinner(null, false);
|
||||
|
||||
if (nrSuccessful) {
|
||||
HelperModule.flashAlertMsg(I18n.t('protocols.index.import_results.message_ok_html', { count: nrSuccessful }), 'success');
|
||||
reloadTable();
|
||||
} else {
|
||||
HelperModule.flashAlertMsg(I18n.t('protocols.index.import_results.message_failed'), 'danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
} else {
|
||||
protocolFileImportModal.init(ev.target.files, reloadTable);
|
||||
}
|
||||
$(this).val('');
|
||||
});
|
||||
}
|
||||
|
|
|
@ -591,7 +591,6 @@ class ProtocolsController < ApplicationController
|
|||
message_items: {
|
||||
protocol: protocol.id
|
||||
})
|
||||
generate_import_protocol_notification(current_user, protocol)
|
||||
format.json do
|
||||
render json: { status: :ok }, status: :ok
|
||||
end
|
||||
|
@ -918,6 +917,11 @@ class ProtocolsController < ApplicationController
|
|||
}
|
||||
end
|
||||
|
||||
def import_docx
|
||||
@job = Protocols::DocxImportJob.perform_later(params[:files], current_user)
|
||||
render json: { job_id: @job.job_id }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_importer
|
||||
|
@ -929,30 +933,6 @@ class ProtocolsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def generate_import_protocol_notification(user, protocol)
|
||||
protocol_download_link = "<a data-id='#{protocol.id}' " \
|
||||
"data-turbolinks='false' " \
|
||||
"href='#{Rails.application
|
||||
.routes
|
||||
.url_helpers
|
||||
.export_protocols_path(protocol_ids: [protocol.id])}'>" \
|
||||
"#{export_protocol_file_name([protocol])}</a>"
|
||||
|
||||
notification = Notification.create(
|
||||
type_of: :deliver,
|
||||
title: I18n.t('protocols.import_export.import_protocol_notification.title', link: protocol_download_link),
|
||||
message: "#{I18n.t('protocols.import_export.import_protocol_notification.message')} <a data-id='#{protocol.id}' " \
|
||||
"data-turbolinks='false' " \
|
||||
"href='#{Rails.application
|
||||
.routes
|
||||
.url_helpers
|
||||
.protocol_path(protocol)}'>" \
|
||||
"#{protocol.name}</a>"
|
||||
)
|
||||
|
||||
UserNotification.create(notification: notification, user: user)
|
||||
end
|
||||
|
||||
def export_protocol_file_name(protocols)
|
||||
protocol_name = get_protocol_name(protocols[0])
|
||||
|
||||
|
|
18
app/javascript/packs/vue/protocol_file_import_modal.js
Normal file
18
app/javascript/packs/vue/protocol_file_import_modal.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import TurbolinksAdapter from 'vue-turbolinks';
|
||||
import Vue from 'vue/dist/vue.esm';
|
||||
import ProtocolFileImportModal from '../../vue/protocol_import/file_import_modal.vue';
|
||||
|
||||
|
||||
Vue.use(TurbolinksAdapter);
|
||||
Vue.prototype.i18n = window.I18n;
|
||||
|
||||
window.initProtocolFileImportModalComponent = () => {
|
||||
new Vue({
|
||||
el: '#protocolFileImportModal',
|
||||
components: {
|
||||
'protocol-file-import-modal': ProtocolFileImportModal
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
initProtocolFileImportModalComponent();
|
105
app/javascript/vue/protocol_import/file_import_modal.vue
Normal file
105
app/javascript/vue/protocol_import/file_import_modal.vue
Normal file
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<div ref="modal" class="modal fade" id="protcolFileImportModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">{{ i18n.t(`protocols.import_modal.${state}.title`) }}</h4>
|
||||
</div>
|
||||
<div class="modal-body text-xs" v-html="i18n.t(`protocols.import_modal.${state}.body_html`, { url: protocolUrl })">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="modal">{{ i18n.t('protocols.import_modal.cancel') }}</button>
|
||||
|
||||
<button v-if="state === 'confirm'" type="button"
|
||||
class="btn btn-primary"
|
||||
@click.stop.prevent="confirm">{{ i18n.t('protocols.import_modal.import') }}</button>
|
||||
<button v-else type="button"
|
||||
class="btn btn-primary"
|
||||
:disabled="state === 'in_progress'"
|
||||
@click.stop.prevent="close">{{ i18n.t('protocols.import_modal.close') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ProtocolFileImportModal',
|
||||
props: {
|
||||
importUrl: { type: String, required: true}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
state: "confirm",
|
||||
files: null,
|
||||
jobPollInterval: null,
|
||||
pollCount: 0,
|
||||
jobId: null,
|
||||
protocolUrl: null,
|
||||
refreshCallback: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
window.protocolFileImportModal = this;
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
$(this.$refs.modal).modal('show');
|
||||
},
|
||||
close() {
|
||||
if (this.state === "done" && this.refreshCallback) {
|
||||
this.refreshCallback();
|
||||
}
|
||||
$(this.$refs.modal).modal('hide');
|
||||
},
|
||||
init(files, refreshCallback) {
|
||||
this.refreshCallback = refreshCallback;
|
||||
this.pollCount = 0;
|
||||
this.jobId = null;
|
||||
this.files = files;
|
||||
this.state = "confirm";
|
||||
this.open();
|
||||
},
|
||||
confirm() {
|
||||
$.post(this.importUrl, (data) => {
|
||||
this.state = 'in_progress';
|
||||
this.jobId = data.job_id
|
||||
this.jobPollInterval = setInterval(this.fetchJobStatus, 1000);
|
||||
});
|
||||
},
|
||||
fetchJobStatus() {
|
||||
this.pollCount += 1;
|
||||
|
||||
if (this.pollCount > 4) {
|
||||
this.state = 'not_yet_done';
|
||||
clearInterval(this.jobPollInterval);
|
||||
return;
|
||||
}
|
||||
|
||||
$.get(`/jobs/${this.jobId}/status`, (data) => {
|
||||
let status = data.status;
|
||||
|
||||
console.log(data)
|
||||
|
||||
switch (status) {
|
||||
case 'pending':
|
||||
break;
|
||||
case 'running':
|
||||
break;
|
||||
case 'done':
|
||||
this.state = 'done';
|
||||
clearInterval(this.jobPollInterval);
|
||||
break;
|
||||
case 'failed':
|
||||
clearInterval(this.jobPollInterval);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
9
app/jobs/protocols/docx_import_job.rb
Normal file
9
app/jobs/protocols/docx_import_job.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Protocols
|
||||
class DocxImportJob < ApplicationJob
|
||||
def perform(files, user)
|
||||
ProtocolImporters::DocxService.new(files, user).import!
|
||||
end
|
||||
end
|
||||
end
|
43
app/services/protocol_importers/docx_service.rb
Normal file
43
app/services/protocol_importers/docx_service.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtocolImporters
|
||||
class DocxService
|
||||
def initialize(files, user)
|
||||
@files = files
|
||||
@user = user
|
||||
end
|
||||
|
||||
def import!
|
||||
# TODO: Implement actual logic
|
||||
ActiveRecord::Base.transaction do
|
||||
@protocol = @user.current_team
|
||||
.protocols
|
||||
.create!(
|
||||
name: "PARSED PROTOCOL #{rand * 10000}",
|
||||
protocol_type: :in_repository_draft,
|
||||
added_by: @user
|
||||
)
|
||||
create_notification!
|
||||
end
|
||||
end
|
||||
|
||||
def create_notification!
|
||||
# TODO: Add proper protocol original file link
|
||||
protocol_download_link = "<a data-id='#{@protocol.id}' " \
|
||||
"data-turbolinks='false' " \
|
||||
"href='#'>" \
|
||||
"#{@protocol.name}</a>"
|
||||
|
||||
notification = Notification.create(
|
||||
type_of: :deliver,
|
||||
title: I18n.t('protocols.import_export.import_protocol_notification.title', link: protocol_download_link),
|
||||
message: "#{I18n.t('protocols.import_export.import_protocol_notification.message')} " \
|
||||
"<a data-id='#{@protocol.id}' data-turbolinks='false' " \
|
||||
"href='#{Rails.application.routes.url_helpers.protocol_path(@protocol)}'>" \
|
||||
"#{@protocol.name}</a>"
|
||||
)
|
||||
|
||||
UserNotification.create(notification: notification, user: @user)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,6 +34,11 @@
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<div id="protocolFileImportModal">
|
||||
<protocol-file-import-modal import-url="<%= import_docx_protocols_path %>" />
|
||||
</div>
|
||||
<%= javascript_include_tag 'vue_protocol_file_import_modal' %>
|
||||
|
||||
<div id="protocolsio-preview-modal-target"></div>
|
||||
<%= render partial: "protocols/index/general_toolbar.html.erb" %>
|
||||
<%= render partial: "protocols/index/protocol_filters.html.erb" %>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<li>
|
||||
<a class="btn-link-alt btn-secondary-link btn-open-file" <%= can_create_protocols_in_repository?(@current_team) ? 'data-action="import"' : 'disabled="disabled"' %>>
|
||||
<span><%= t("protocols.index.import_alt") %></span>
|
||||
<input type="file" value="" accept=".eln" data-role="import-file-input"
|
||||
<input type="file" value="" accept=".eln,.docx" data-role="import-file-input"
|
||||
data-team-id="<%= @current_team.id %>" data-import-url="<%= import_protocols_path %>">
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -2684,6 +2684,22 @@ en:
|
|||
button: "Rearrange steps"
|
||||
modal:
|
||||
title: "Rearrange protocol steps"
|
||||
import_modal:
|
||||
confirm:
|
||||
title: "Import protocol"
|
||||
body_html: "You will start importing selected .docx file into SciNote. The import time may vary according to the size of a file and internet connection."
|
||||
in_progress:
|
||||
title: "Importing in progress"
|
||||
body_html: "The process of importing has started. Please wait..."
|
||||
not_yet_done:
|
||||
title: "Importing in progress"
|
||||
body_html: "The import is taking longer than expected. You'll get a notice in <i class=\"sn-icon sn-icon-notifications\"></i> Notifications when your protocol template is ready. You can close the window and continue with your work."
|
||||
done:
|
||||
title: "Importing completed"
|
||||
body_html: 'The protocol has been successfully imported. You can access the draft of protocol template <a href="%{url}">here.</a>'
|
||||
import: "Import"
|
||||
cancel: "Cancel"
|
||||
close: "Close"
|
||||
print:
|
||||
title: "Print protocol"
|
||||
button: "Print"
|
||||
|
@ -2866,7 +2882,7 @@ en:
|
|||
edit: "Edit"
|
||||
clone_btn: "Copy"
|
||||
import: "Import"
|
||||
import_alt: "From local file"
|
||||
import_alt: "From file (.docx, .eln)"
|
||||
import_protocols_io: "From Protocols.io"
|
||||
modal_import_json_upload: "Upload"
|
||||
modal_import_json_title: "Import protocols.io file"
|
||||
|
|
|
@ -654,6 +654,7 @@ Rails.application.routes.draw do
|
|||
post 'restore', to: 'protocols#restore'
|
||||
post 'clone', to: 'protocols#clone'
|
||||
post 'import', to: 'protocols#import'
|
||||
post 'import_docx', to: 'protocols#import_docx'
|
||||
post 'protocolsio_import_create',
|
||||
to: 'protocols#protocolsio_import_create'
|
||||
post 'protocolsio_import_save', to: 'protocols#protocolsio_import_save'
|
||||
|
|
|
@ -34,7 +34,8 @@ const entryList = {
|
|||
vue_repository_assign_items_to_task_modal: './app/javascript/packs/vue/assign_items_to_task_modal.js',
|
||||
vue_navigation_top_menu: './app/javascript/packs/vue/navigation/top_menu.js',
|
||||
vue_navigation_navigator: './app/javascript/packs/vue/navigation/navigator.js',
|
||||
vue_components_action_toolbar: './app/javascript/packs/vue/action_toolbar.js'
|
||||
vue_components_action_toolbar: './app/javascript/packs/vue/action_toolbar.js',
|
||||
vue_protocol_file_import_modal: './app/javascript/packs/vue/protocol_file_import_modal.js'
|
||||
}
|
||||
|
||||
// Engine pack loading based on https://github.com/rails/webpacker/issues/348#issuecomment-635480949
|
||||
|
|
Loading…
Reference in a new issue