mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-25 01:03:18 +08:00
Implement protocol options dropdown [SCI-6750, SCI-6751] (#4066)
* Implement protocol options dropdown [SCI-6750, SCI-6751] * Implement simple API error handling for step status update [SCI-6354]
This commit is contained in:
parent
ccc668ce5c
commit
6352a4dd04
8 changed files with 176 additions and 48 deletions
|
@ -27,4 +27,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.protocol-options-dropdown {
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
cursor: default;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -263,14 +263,14 @@ class MyModulesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def protocol
|
def protocol
|
||||||
render json: @my_module.protocol
|
render json: @my_module.protocol, serializer: ProtocolSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_protocol
|
def update_protocol
|
||||||
protocol = @my_module.protocol
|
protocol = @my_module.protocol
|
||||||
protocol.update!(protocol_params)
|
protocol.update!(protocol_params)
|
||||||
|
|
||||||
render json: protocol
|
render json: protocol, serializer: ProtocolSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def results
|
def results
|
||||||
|
|
|
@ -9,6 +9,7 @@ Vue.prototype.i18n = window.I18n;
|
||||||
|
|
||||||
window.initProtocolComponent = () => {
|
window.initProtocolComponent = () => {
|
||||||
Vue.prototype.dateFormat = $('#protocolContainer').data('date-format');
|
Vue.prototype.dateFormat = $('#protocolContainer').data('date-format');
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#protocolContainer',
|
el: '#protocolContainer',
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<div class="task-section-title">
|
<div class="task-section-title">
|
||||||
<h2>{{ i18n.t('Protocol') }}</h2>
|
<h2>{{ i18n.t('Protocol') }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<span v-if="protocol.linked" class="status-label linked">
|
<span v-if="protocol.attributes.linked" class="status-label linked">
|
||||||
[{{ protocol.name }}]
|
[{{ protocol.attributes.name }}]
|
||||||
</span>
|
</span>
|
||||||
<span class="status-label" v-else>
|
<span class="status-label" v-else>
|
||||||
[{{ i18n.t('my_modules.protocols.protocol_status_bar.unlinked') }}]
|
[{{ i18n.t('my_modules.protocols.protocol_status_bar.unlinked') }}]
|
||||||
|
@ -16,52 +16,20 @@
|
||||||
<div class="sci-btn-group actions-block">
|
<div class="sci-btn-group actions-block">
|
||||||
<a class="btn btn-primary" @click="addStep(steps.length)">
|
<a class="btn btn-primary" @click="addStep(steps.length)">
|
||||||
<span class="fas fa-plus" aria-hidden="true"></span>
|
<span class="fas fa-plus" aria-hidden="true"></span>
|
||||||
<span>New step</span>
|
<span>{{ i18n.t("protocols.steps.new_step") }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-default" data-toggle="modal" data-target="#print-protocol-modal">
|
<a class="btn btn-default" data-toggle="modal" data-target="#print-protocol-modal">
|
||||||
<span class="fas fa-print" aria-hidden="true"></span>
|
<span class="fas fa-print" aria-hidden="true"></span>
|
||||||
<span>Print</span>
|
<span>{{ i18n.t("protocols.print.button") }}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown sci-dropdown">
|
<ProtocolOptions v-if="protocol.attributes && protocol.attributes.urls" :protocol="protocol" />
|
||||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownProtocolOptions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
|
||||||
<span class="fas fa-cog"></span>
|
|
||||||
<span>Protocol options</span>
|
|
||||||
<span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownProtocolOptions">
|
|
||||||
<li>
|
|
||||||
<a>
|
|
||||||
<span class="fas fa-edit"></span>
|
|
||||||
<span>Load from repository</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a>
|
|
||||||
<span class="fas fa-download"></span>
|
|
||||||
<span>Import protocol</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a>
|
|
||||||
<span class="fas fa-upload"></span>
|
|
||||||
<span>Export protocol</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a>
|
|
||||||
<span class="fas fa-save"></span>
|
|
||||||
<span>Save to repository</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="protocol.id" id="protocol-content" class="protocol-content collapse in" aria-expanded="true">
|
<div v-if="protocol.id" id="protocol-content" class="protocol-content collapse in" aria-expanded="true">
|
||||||
<div class="protocol-description">
|
<div class="protocol-description">
|
||||||
<div class="protocol-name">
|
<div class="protocol-name">
|
||||||
<InlineEdit
|
<InlineEdit
|
||||||
:value="protocol.name"
|
:value="protocol.attributes.name"
|
||||||
:characterLimit="255"
|
:characterLimit="255"
|
||||||
:placeholder="i18n.t('my_modules.protocols.protocol_status_bar.enter_name')"
|
:placeholder="i18n.t('my_modules.protocols.protocol_status_bar.enter_name')"
|
||||||
:allowBlank="true"
|
:allowBlank="true"
|
||||||
|
@ -95,6 +63,7 @@
|
||||||
<script>
|
<script>
|
||||||
import InlineEdit from 'vue/shared/inline_edit.vue'
|
import InlineEdit from 'vue/shared/inline_edit.vue'
|
||||||
import Step from 'vue/protocol/step'
|
import Step from 'vue/protocol/step'
|
||||||
|
import ProtocolOptions from 'vue/protocol/protocolOptions'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProtocolContainer',
|
name: 'ProtocolContainer',
|
||||||
|
@ -116,16 +85,18 @@
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: { Step, InlineEdit },
|
components: { Step, InlineEdit, ProtocolOptions },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
protocol: {},
|
protocol: {
|
||||||
|
attributes: {}
|
||||||
|
},
|
||||||
steps: {}
|
steps: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
$.get(this.protocolUrl, (data) => {
|
$.get(this.protocolUrl, (result) => {
|
||||||
this.protocol = data;
|
this.protocol = result.data;
|
||||||
});
|
});
|
||||||
$.get(this.stepsUrl, (result) => {
|
$.get(this.stepsUrl, (result) => {
|
||||||
this.steps = result.data
|
this.steps = result.data
|
||||||
|
@ -133,7 +104,7 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateName(newName) {
|
updateName(newName) {
|
||||||
this.protocol.name = newName;
|
this.protocol.attributes.name = newName;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'PATCH',
|
type: 'PATCH',
|
||||||
url: this.protocolUrl,
|
url: this.protocolUrl,
|
||||||
|
|
98
app/javascript/vue/protocol/protocolOptions.vue
Normal file
98
app/javascript/vue/protocol/protocolOptions.vue
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
<template>
|
||||||
|
<div class="dropdown sci-dropdown protocol-options-dropdown">
|
||||||
|
<button
|
||||||
|
class="btn btn-secondary dropdown-toggle"
|
||||||
|
type="button"
|
||||||
|
id="dropdownProtocolOptions"
|
||||||
|
data-toggle="dropdown"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="true"
|
||||||
|
>
|
||||||
|
<span class="fas fa-cog"></span>
|
||||||
|
<span>{{ i18n.t("my_modules.protocol.options_dropdown.title") }}</span>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul
|
||||||
|
class="dropdown-menu dropdown-menu-right"
|
||||||
|
aria-labelledby="dropdownProtocolOptions"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
ref="loadProtocol"
|
||||||
|
data-action="load-from-repository"
|
||||||
|
@click="loadProtocol"
|
||||||
|
:class="{ disabled: !protocol.attributes.urls.load_from_repo_url }"
|
||||||
|
>
|
||||||
|
<span class="fas fa-edit"></span>
|
||||||
|
<span>{{ i18n.t("my_modules.protocol.options_dropdown.load_from_repo") }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
ref="saveProtocol"
|
||||||
|
data-action="copy-to-repository"
|
||||||
|
@click="saveProtocol"
|
||||||
|
:class="{ disabled: !protocol.attributes.urls.save_to_repo_url }"
|
||||||
|
>
|
||||||
|
<span class="fas fa-check"></span>
|
||||||
|
<span>{{
|
||||||
|
i18n.t("my_modules.protocol.options_dropdown.save_to_repo")
|
||||||
|
}}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a data-action="load-from-file"
|
||||||
|
class="btn-open-file"
|
||||||
|
:class="{ disabled: !protocol.attributes.urls.import_url }">
|
||||||
|
<span class="fas fa-download"></span>
|
||||||
|
<span>{{ i18n.t("my_modules.protocol.options_dropdown.import") }}</span>
|
||||||
|
<input type="file" value="" accept=".eln" data-turbolinks="false">
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
data-turbolinks="false"
|
||||||
|
:href="protocol.attributes.urls.export_url"
|
||||||
|
:class="{ disabled: !protocol.attributes.urls.export_url }"
|
||||||
|
>
|
||||||
|
<span class="fas fa-upload"></span>
|
||||||
|
<span>{{
|
||||||
|
i18n.t("my_modules.protocol.options_dropdown.export")
|
||||||
|
}}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "ProtocolOptions",
|
||||||
|
props: {
|
||||||
|
protocol: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// Legacy global functions from app/assets/javascripts/my_modules/protocols.js
|
||||||
|
initLoadFromRepository();
|
||||||
|
initCopyToRepository();
|
||||||
|
initImport();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadProtocol() {
|
||||||
|
$.get(
|
||||||
|
this.protocol.attributes.urls.load_from_repo_url + "?type=recent"
|
||||||
|
).success((data) => {
|
||||||
|
$(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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -107,8 +107,12 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
changeState() {
|
changeState() {
|
||||||
$.post(this.step.attributes.urls.state_url, {completed: !this.step.attributes.completed}, (result) => {
|
this.step.attributes.completed = !this.step.attributes.completed;
|
||||||
this.$emit('step:update', result.data.attributes)
|
this.$emit('step:update', this.step)
|
||||||
|
$.post(this.step.attributes.urls.state_url, {completed: this.step.attributes.completed}).error(() => {
|
||||||
|
this.step.attributes.completed = !this.step.attributes.completed;
|
||||||
|
this.$emit('step:update', this.step)
|
||||||
|
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateName(newName) {
|
updateName(newName) {
|
||||||
|
|
43
app/serializers/protocol_serializer.rb
Normal file
43
app/serializers/protocol_serializer.rb
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ProtocolSerializer < ActiveModel::Serializer
|
||||||
|
include Canaid::Helpers::PermissionsHelper
|
||||||
|
include Rails.application.routes.url_helpers
|
||||||
|
|
||||||
|
attributes :name, :id, :urls
|
||||||
|
|
||||||
|
def urls
|
||||||
|
{
|
||||||
|
load_from_repo_url: load_from_repo_url,
|
||||||
|
save_to_repo_url: save_to_repo_url,
|
||||||
|
export_url: export_url,
|
||||||
|
import_url: import_url
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_from_repo_url
|
||||||
|
return unless can_manage_protocol_in_module?(object)
|
||||||
|
|
||||||
|
load_from_repository_modal_protocol_path(object, format: :json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_to_repo_url
|
||||||
|
return unless can_read_protocol_in_module?(object) && can_create_protocols_in_repository?(object.team)
|
||||||
|
|
||||||
|
copy_to_repository_modal_protocol_path(object, format: :json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def import_url
|
||||||
|
return unless can_manage_protocol_in_module?(object)
|
||||||
|
|
||||||
|
load_from_file_protocol_path(object, format: :json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def export_url
|
||||||
|
return unless can_read_protocol_in_module?(object)
|
||||||
|
|
||||||
|
export_protocols_path(protocol_ids: object.id, my_module_id: object.my_module.id)
|
||||||
|
end
|
||||||
|
end
|
|
@ -178,7 +178,8 @@ en:
|
||||||
attributes:
|
attributes:
|
||||||
output_id:
|
output_id:
|
||||||
creates_cycle: "mustn't create cycle"
|
creates_cycle: "mustn't create cycle"
|
||||||
|
errors:
|
||||||
|
general: "Something went wrong."
|
||||||
helpers:
|
helpers:
|
||||||
label:
|
label:
|
||||||
team:
|
team:
|
||||||
|
|
Loading…
Reference in a new issue