Add step creation/deletion functionality [SCI-6754]

This commit is contained in:
Anton 2022-04-22 13:07:51 +02:00
parent 6ef190f353
commit ba3c73439a
10 changed files with 174 additions and 24 deletions

View file

@ -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

View file

@ -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')
};
}
});

View file

@ -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>

View 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>

View file

@ -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

View file

@ -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,

View 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

View file

@ -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>

View file

@ -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"

View file

@ -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)