mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-25 09:13:05 +08:00
Add step creation/deletion functionality [SCI-6754]
This commit is contained in:
parent
6ef190f353
commit
ba3c73439a
10 changed files with 174 additions and 24 deletions
|
@ -6,15 +6,19 @@ class StepsController < ApplicationController
|
|||
|
||||
before_action :load_vars, only: %i(edit update destroy show toggle_step_state checklistitem_state update_view_state
|
||||
move_up move_down update_asset_view_mode)
|
||||
before_action :load_vars_nested, only: %i(new create)
|
||||
before_action :load_vars_nested, only: %i(new create index)
|
||||
before_action :convert_table_contents_to_utf8, only: %i(create update)
|
||||
|
||||
before_action :check_view_permissions, only: :show
|
||||
before_action :check_view_permissions, only: %i(show index)
|
||||
before_action :check_create_permissions, only: %i(new create)
|
||||
before_action :check_manage_permissions, only: %i(edit update destroy move_up move_down
|
||||
update_view_state update_asset_view_mode)
|
||||
before_action :check_complete_and_checkbox_permissions, only: %i(toggle_step_state checklistitem_state)
|
||||
|
||||
def index
|
||||
render json: @protocol.steps.in_order, each_serializer: StepSerializer
|
||||
end
|
||||
|
||||
def new
|
||||
@step = Step.new
|
||||
|
||||
|
@ -28,6 +32,16 @@ class StepsController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
new_step = Step.new(
|
||||
name: t('protocols.steps.default_name'),
|
||||
completed: false,
|
||||
user: current_user,
|
||||
last_modified_by: current_user
|
||||
)
|
||||
render json: @protocol.insert_step(new_step, params[:position]), serializer: StepSerializer
|
||||
end
|
||||
|
||||
def create_old
|
||||
@step = Step.new
|
||||
@step.transaction do
|
||||
new_step_params = step_params
|
||||
|
@ -264,23 +278,9 @@ class StepsController < ApplicationController
|
|||
# Release space taken by the step
|
||||
team.release_space(previous_size)
|
||||
team.save
|
||||
|
||||
flash[:success] = t(
|
||||
'protocols.steps.destroy.success_flash',
|
||||
step: (@step.position_plus_one).to_s
|
||||
)
|
||||
else
|
||||
flash[:error] = t(
|
||||
'protocols.steps.destroy.error_flash',
|
||||
step: (@step.position_plus_one).to_s
|
||||
)
|
||||
end
|
||||
|
||||
if @protocol.in_module?
|
||||
redirect_to protocols_my_module_path(@step.my_module)
|
||||
else
|
||||
redirect_to edit_protocol_path(@protocol)
|
||||
end
|
||||
render json: @step, serializer: StepSerializer
|
||||
end
|
||||
|
||||
# Responds to checkbox toggling in steps view
|
||||
|
|
|
@ -9,7 +9,6 @@ Vue.prototype.i18n = window.I18n;
|
|||
|
||||
window.initProtocolComponent = () => {
|
||||
Vue.prototype.dateFormat = $('#protocolContainer').data('date-format');
|
||||
|
||||
new Vue({
|
||||
el: '#protocolContainer',
|
||||
components: {
|
||||
|
@ -17,7 +16,9 @@ window.initProtocolComponent = () => {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
protocolUrl: $('#protocolContainer').data('protocol-url')
|
||||
protocolUrl: $('#protocolContainer').data('protocol-url'),
|
||||
stepsUrl: $('#protocolContainer').data('steps-url'),
|
||||
addStepUrl: $('#protocolContainer').data('add-step-url')
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
@ -13,28 +13,91 @@
|
|||
<input type="text" class="inline" :model="protocol.name" :placeholder="i18n.t('my_modules.protocols.protocol_status_bar.enter_name')">
|
||||
</div>
|
||||
<div class="protocol-steps">
|
||||
Steps go here
|
||||
<template v-for="(step, index) in steps">
|
||||
<div class="step-block" :key="step.id">
|
||||
<button v-if="index > 0" class="btn btn-primary" @click="addStep(index)">
|
||||
<i class="fas fa-plus"></i>
|
||||
{{ i18n.t("protocols.steps.new_step") }}
|
||||
</button>
|
||||
<Step
|
||||
:step.sync="steps[index]"
|
||||
@step:delete="updateStepsPosition"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<button class="btn btn-primary" @click="addStep(steps.length)">
|
||||
<i class="fas fa-plus"></i>
|
||||
{{ i18n.t("protocols.steps.new_step") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Step from 'vue/protocol/step'
|
||||
|
||||
export default {
|
||||
name: 'ProtocolContainer',
|
||||
props: {
|
||||
protocolUrl: String, required: true
|
||||
protocolUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
stepsUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
addStepUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
components: { Step },
|
||||
data() {
|
||||
return {
|
||||
protocol: {}
|
||||
protocol: {},
|
||||
steps: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
$.get(this.protocolUrl, (data) => {
|
||||
this.protocol = data;
|
||||
});
|
||||
$.get(this.stepsUrl, (result) => {
|
||||
this.steps = result.data
|
||||
})
|
||||
},
|
||||
methods: {}
|
||||
methods: {
|
||||
addStep(position) {
|
||||
$.post(this.addStepUrl, {position: position}, (result) => {
|
||||
this.updateStepsPosition(result.data)
|
||||
})
|
||||
},
|
||||
updateStepsPosition(step, action = 'add') {
|
||||
let position = step.attributes.position;
|
||||
if (action === 'delete') {
|
||||
this.steps.splice(position, 1)
|
||||
}
|
||||
let unordered_steps = this.steps.map( s => {
|
||||
if (s.attributes.position >= position) {
|
||||
if (action === 'add') {
|
||||
s.attributes.position += 1;
|
||||
} else {
|
||||
s.attributes.position -= 1;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
})
|
||||
if (action === 'add') {
|
||||
unordered_steps.push(step);
|
||||
}
|
||||
this.reorderSteps(unordered_steps)
|
||||
|
||||
},
|
||||
reorderSteps(steps) {
|
||||
this.steps = steps.sort((a, b) => a.attributes.position - b.attributes.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
37
app/javascript/vue/protocol/step.vue
Normal file
37
app/javascript/vue/protocol/step.vue
Normal file
|
@ -0,0 +1,37 @@
|
|||
<template>
|
||||
<div class="step-container">
|
||||
{{ step.attributes.position + 1 }}
|
||||
{{ step.attributes.name }}
|
||||
<button class="btn btn-danger" @click="deleteStep">
|
||||
<i class="fas fa-trash"></i>
|
||||
{{ i18n.t("protocols.steps.options.delete_title") }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'StepContainer',
|
||||
props: {
|
||||
step: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteStep() {
|
||||
$.ajax({
|
||||
url: this.step.attributes.urls.delete_url,
|
||||
type: 'DELETE',
|
||||
success: (result) => {
|
||||
this.$emit(
|
||||
'step:delete',
|
||||
result.data,
|
||||
'delete'
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -202,6 +202,36 @@ class Protocol < ApplicationRecord
|
|||
user_id: user.id))
|
||||
end
|
||||
|
||||
def insert_step(step, position)
|
||||
ActiveRecord::Base.transaction do
|
||||
steps.where('position >= ?', position).desc_order.each do |s|
|
||||
s.update!(position: s.position + 1)
|
||||
end
|
||||
step.position = position
|
||||
step.protocol = self
|
||||
step.save!
|
||||
end
|
||||
step
|
||||
end
|
||||
|
||||
def move_step(step, new_position)
|
||||
ActiveRecord::Base.transaction do
|
||||
old_position = step.position
|
||||
step.update!(posistion: -1)
|
||||
if old_position > new_position
|
||||
steps.where('position > ? AND position <= ?', old_position, new_position).desc_order.each do |s|
|
||||
s.update!(position: s.position + 1)
|
||||
end
|
||||
else
|
||||
steps.where('position >= ? AND position < ?', old_position, new_position).at_order.each do |s|
|
||||
s.update!(position: s.position - 1)
|
||||
end
|
||||
end
|
||||
step.update!(posistion: new_position)
|
||||
end
|
||||
step
|
||||
end
|
||||
|
||||
def linked_modules
|
||||
MyModule.joins(:protocols).where('protocols.parent_id = ?', id)
|
||||
end
|
||||
|
|
|
@ -45,6 +45,9 @@ class Step < ApplicationRecord
|
|||
},
|
||||
allow_destroy: true
|
||||
|
||||
scope :in_order, -> { order(position: :asc) }
|
||||
scope :desc_order, -> { order(position: :desc) }
|
||||
|
||||
def self.search(user,
|
||||
include_archived,
|
||||
query = nil,
|
||||
|
|
11
app/serializers/step_serializer.rb
Normal file
11
app/serializers/step_serializer.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
class StepSerializer < ActiveModel::Serializer
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
attributes :name, :position, :completed, :urls
|
||||
|
||||
def urls
|
||||
{
|
||||
delete_url: step_path(object)
|
||||
}
|
||||
end
|
||||
end
|
|
@ -121,11 +121,15 @@
|
|||
<div
|
||||
id="protocolContainer"
|
||||
data-protocol-url="<%= protocol_my_module_path(@my_module, @protocol) %>"
|
||||
data-add-step-url="<%= protocol_steps_path(protocol_id: @protocol.id) %>"
|
||||
data-steps-url="<%= steps_path(protocol_id: @protocol) %>"
|
||||
data-date-format="<%= datetime_picker_format_date_only %>"
|
||||
data-user-utc-offset="<%= ActiveSupport::TimeZone.find_tzinfo(current_user.time_zone).utc_offset %>"
|
||||
>
|
||||
<protocol-container
|
||||
:protocol-url="protocolUrl"
|
||||
:steps-url="stepsUrl"
|
||||
:add-step-url="addStepUrl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2491,6 +2491,7 @@ en:
|
|||
success_flash: 'Protocol <strong>%{name}</strong> successfully imported to %{type}.'
|
||||
|
||||
steps:
|
||||
default_name: 'Untitled step'
|
||||
completed: 'Completed'
|
||||
uncompleted: 'Uncompleted'
|
||||
expand_label: "Expand All"
|
||||
|
|
|
@ -443,7 +443,7 @@ Rails.application.routes.draw do
|
|||
get 'users/edit', to: 'user_my_modules#index_edit'
|
||||
end
|
||||
|
||||
resources :steps, only: [:edit, :update, :destroy, :show] do
|
||||
resources :steps, only: %i(index edit update destroy show) do
|
||||
resources :step_comments,
|
||||
path: '/comments',
|
||||
only: %i(create index update destroy)
|
||||
|
|
Loading…
Reference in a new issue