Add element movements between step [SCI-9024]

This commit is contained in:
Anton 2023-08-21 09:22:56 +02:00
parent 0780ed17b0
commit e9174ad158
30 changed files with 381 additions and 40 deletions

View file

@ -5,6 +5,10 @@ module ResultElements
before_action :load_result_and_my_module
before_action :check_manage_permissions
def move_targets
render json: { targets: @my_module.results.where.not(id: @result.id).map{ |i| [i.id, i.name] } }
end
private
def load_result_and_my_module

View file

@ -2,7 +2,7 @@
module ResultElements
class TablesController < BaseController
before_action :load_table, only: %i(update destroy duplicate)
before_action :load_table, only: %i(update destroy duplicate move)
def create
predefined_table_dimensions = create_table_params[:tableDimensions].map(&:to_i)
@ -57,6 +57,19 @@ module ResultElements
head :unprocessable_entity
end
def move
target = @my_module.results.find_by(id: params[:target_id])
result_table = @table.result_table
ActiveRecord::Base.transaction do
result_table.update!(result: target)
result_table.result_orderable_element.update!(result: target, position: target.result_orderable_elements.size)
@result.normalize_elements_position
render json: @table, serializer: ResultTableSerializer, user: current_user
rescue ActiveRecord::RecordInvalid
render json: result_table.errors, status: :unprocessable_entity
end
end
def destroy
if @table.destroy
#log_step_activity(:table_deleted, { table_name: @table.name })

View file

@ -7,7 +7,7 @@ module ResultElements
include InputSanitizeHelper
include Rails.application.routes.url_helpers
before_action :load_result_text, only: %i(update destroy duplicate)
before_action :load_result_text, only: %i(update destroy duplicate move)
def create
result_text = @result.result_texts.build
@ -36,6 +36,18 @@ module ResultElements
render json: @result_text.errors, status: :unprocessable_entity
end
def move
target = @my_module.results.find_by(id: params[:target_id])
ActiveRecord::Base.transaction do
@result_text.update!(result: target)
@result_text.result_orderable_element.update!(result: target, position: target.result_orderable_elements.size)
@result.normalize_elements_position
render json: @result_text, serializer: ResultTextSerializer, user: current_user
rescue ActiveRecord::RecordInvalid
render json: @result_text.errors, status: :unprocessable_entity
end
end
def destroy
if @result_text.destroy
log_step_activity(:text_deleted, { text_name: @result_text.name })

View file

@ -1,8 +1,6 @@
# frozen_string_literal: true
class ResultsController < ApplicationController
skip_before_action :verify_authenticity_token, only: %i(create update destroy)
before_action :load_my_module
before_action :load_vars, only: %i(destroy elements assets upload_attachment update_view_state update_asset_view_mode update)
before_action :check_destroy_permissions, only: :destroy

View file

@ -5,6 +5,11 @@ module StepElements
before_action :load_step_and_protocol
before_action :check_manage_permissions
def move_targets
render json: { targets: @protocol.steps.order(:position).where.not(id: @step.id).map{|i| [i.id, i.name] } }
end
private
def load_step_and_protocol

View file

@ -4,7 +4,7 @@ module StepElements
class ChecklistsController < BaseController
include ApplicationHelper
include StepsActions
before_action :load_checklist, only: %i(update destroy duplicate)
before_action :load_checklist, only: %i(update destroy duplicate move)
def create
checklist = @step.checklists.build(
name: t('protocols.steps.checklist.default_name', position: @step.checklists.length + 1)
@ -32,6 +32,18 @@ module StepElements
head :unprocessable_entity
end
def move
target = @protocol.steps.find_by(id: params[:target_id])
ActiveRecord::Base.transaction do
@checklist.update!(step: target)
@checklist.step_orderable_element.update!(step: target, position: target.step_orderable_elements.size)
@step.normalize_elements_position
render json: @checklist, serializer: ChecklistSerializer, user: current_user
rescue ActiveRecord::RecordInvalid
render json: @checklist.errors, status: :unprocessable_entity
end
end
def destroy
if @checklist.destroy
log_step_activity(:checklist_deleted, { checklist_name: @checklist.name })

View file

@ -2,7 +2,7 @@
module StepElements
class TablesController < BaseController
before_action :load_table, only: %i(update destroy duplicate)
before_action :load_table, only: %i(update destroy duplicate move)
def create
predefined_table_dimensions = create_table_params[:tableDimensions].map(&:to_i)
@ -57,6 +57,19 @@ module StepElements
head :unprocessable_entity
end
def move
target = @protocol.steps.find_by(id: params[:target_id])
step_table = @table.step_table
ActiveRecord::Base.transaction do
step_table.update!(step: target)
step_table.step_orderable_element.update!(step: target, position: target.step_orderable_elements.size)
@step.normalize_elements_position
render json: @table, serializer: TableSerializer, user: current_user
rescue ActiveRecord::RecordInvalid
render json: step_table.errors, status: :unprocessable_entity
end
end
def destroy
if @table.destroy
log_step_activity(:table_deleted, { table_name: @table.name })

View file

@ -5,7 +5,7 @@ module StepElements
include ApplicationHelper
include StepsActions
before_action :load_step_text, only: %i(update destroy duplicate)
before_action :load_step_text, only: %i(update destroy duplicate move)
def create
step_text = @step.step_texts.build
@ -34,6 +34,18 @@ module StepElements
render json: @step_text.errors, status: :unprocessable_entity
end
def move
target = @protocol.steps.find_by(id: params[:target_id])
ActiveRecord::Base.transaction do
@step_text.update!(step: target)
@step_text.step_orderable_element.update!(step: target, position: target.step_orderable_elements.size)
@step.normalize_elements_position
render json: @step_text, serializer: StepTextSerializer, user: current_user
rescue ActiveRecord::RecordInvalid
render json: @step_text.errors, status: :unprocessable_entity
end
end
def destroy
if @step_text.destroy
log_step_activity(:text_deleted, { text_name: @step_text.name })

View file

@ -0,0 +1,22 @@
import axios from "axios";
const instance = axios.create({
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
instance.interceptors.request.use(
function (config) {
const csrfToken = document.querySelector('[name=csrf-token]').content;
config.headers["X-CSRF-Token"] = csrfToken;
return config;
},
function (error) {
return Promise.reject(error);
}
);
export default instance;

View file

@ -3,7 +3,9 @@
import TurbolinksAdapter from 'vue-turbolinks';
import Vue from 'vue/dist/vue.esm';
import ProtocolContainer from '../../vue/protocol/container.vue';
import PerfectScrollbar from 'vue2-perfect-scrollbar';
Vue.use(PerfectScrollbar);
Vue.use(TurbolinksAdapter);
Vue.prototype.i18n = window.I18n;
Vue.prototype.inlineEditing = window.inlineEditing;

View file

@ -1,7 +1,9 @@
import TurbolinksAdapter from 'vue-turbolinks';
import Vue from 'vue/dist/vue.esm';
import Results from '../../vue/results/results.vue';
import PerfectScrollbar from 'vue2-perfect-scrollbar';
Vue.use(PerfectScrollbar);
Vue.use(TurbolinksAdapter);
Vue.prototype.i18n = window.I18n;
Vue.prototype.ActiveStoragePreviews = window.ActiveStoragePreviews;

View file

@ -129,10 +129,13 @@
:step.sync="steps[index]"
@reorder="startStepReorder"
:inRepository="inRepository"
:stepToReload="stepToReload"
@step:delete="updateStepsPosition"
@step:update="updateStep"
@stepUpdated="refreshProtocolStatus"
@step:insert="updateStepsPosition"
@step:elements:loaded="stepToReload = null"
@step:move_element="reloadStep"
:reorderStepUrl="steps.length > 1 ? urls.reorder_steps_url : null"
:assignableMyModuleId="protocol.attributes.assignable_my_module_id"
/>
@ -200,7 +203,8 @@
},
steps: [],
reordering: false,
publishing: false
publishing: false,
stepToReload: null,
}
},
created() {
@ -215,6 +219,9 @@
});
},
methods: {
reloadStep(step) {
this.stepToReload = step;
},
collapseSteps() {
$('.step-container .collapse').collapse('hide')
},

View file

@ -175,6 +175,7 @@
@update="updateElement"
@reorder="openReorderModal"
@component:insert="insertElement"
@moved="moveElement"
/>
</template>
<Attachments v-if="attachments.length"
@ -243,7 +244,11 @@
assignableMyModuleId: {
type: Number,
required: false
}
},
stepToReload: {
type: Number,
required: false
},
},
data() {
return {
@ -284,6 +289,13 @@
this.loadAttachments();
this.loadElements();
},
watch: {
stepToReload() {
if (this.stepToReload == this.step.id) {
this.loadElements();
}
}
},
mounted() {
$(this.$refs.comments).data('closeCallback', this.closeCommentsSidebar);
$(this.$refs.comments).data('openCallback', this.closeCommentsSidebar);
@ -335,6 +347,7 @@
loadElements() {
$.get(this.urls.elements_url, (result) => {
this.elements = result.data
this.$emit('step:elements:loaded');
});
},
showStorageUsage() {
@ -522,6 +535,17 @@
})
this.elements.push(element);
},
moveElement(position, target_id) {
this.elements.splice(position, 1)
let unorderedElements = this.elements.map( e => {
if (e.attributes.position >= position) {
e.attributes.position -= 1;
}
return e;
})
this.$emit('stepUpdated')
this.$emit('step:move_element', target_id)
},
duplicateStep() {
$.post(this.urls.duplicate_step_url, (result) => {
this.$emit('step:insert', result.data);

View file

@ -138,6 +138,7 @@
@update="updateElement"
@reorder="openReorderModal"
@component:insert="insertElement"
@moved="moveElement"
/>
</template>
<Attachments v-if="attachments.length"
@ -156,7 +157,7 @@
</template>
<script>
import axios from 'axios';
import axios from '../../packs/custom_axios.js';
import ReorderableItemsModal from '../shared/reorderable_items_modal.vue';
import ResultTable from '../shared/content/table.vue';
import ResultText from '../shared/content/text.vue';
@ -170,7 +171,8 @@
export default {
name: 'Results',
props: {
result: { type: Object, required: true }
result: { type: Object, required: true },
resultToReload: { type: Number, required: false }
},
data() {
return {
@ -198,6 +200,13 @@
Attachments,
InlineEdit
},
watch: {
resultToReload() {
if (this.resultToReload == this.result.id) {
this.loadElements();
}
}
},
computed: {
reorderableElements() {
return this.orderedElements.map((e) => { return { id: e.id, attributes: e.attributes.orderable } })
@ -294,6 +303,7 @@
loadElements() {
$.get(this.urls.elements_url, (result) => {
this.elements = result.data
this.$emit('result:elements:loaded');
});
},
loadAttachments() {
@ -340,6 +350,17 @@
},
duplicateResult() {
},
moveElement(position, target_id) {
this.elements.splice(position, 1)
let unorderedElements = this.elements.map( e => {
if (e.attributes.position >= position) {
e.attributes.position -= 1;
}
return e;
})
this.$emit('resultUpdated')
this.$emit('result:move_element', target_id)
},
updateName(name) {
axios.patch(this.urls.update_url, { result: { name: name } }, (_) => {

View file

@ -2,13 +2,18 @@
<div class="results-wrapper">
<ResultsToolbar :sort="sort" @setSort="setSort" @newResult="createResult" @expandAll="expandAll" @collapseAll="collapseAll" class="mb-3" />
<div class="results-list">
<Result v-for="result in results" :key="result.id" :result="result" />
<Result v-for="result in results" :key="result.id"
:result="result"
:resultToReload="resultToReload"
@result:elements:loaded="resultToReload = null"
@result:move_element="reloadResult"
/>
</div>
</div>
</template>
<script>
import axios from 'axios';
import axios from '../../packs/custom_axios.js';
import ResultsToolbar from './results_toolbar.vue';
import Result from './result.vue';
@ -21,13 +26,17 @@
data() {
return {
results: [],
sort: 'created_at_desc'
sort: 'created_at_desc',
resultToReload: null
}
},
created() {
this.loadResults();
},
methods: {
reloadResult(result) {
this.resultToReload = result;
},
loadResults() {
axios.get(
`${this.url}?sort=${this.sort}`,

View file

@ -29,6 +29,9 @@
<button v-if="element.attributes.orderable.urls.duplicate_url" class="btn icon-btn btn-light btn-sm" tabindex="0" @click="duplicateElement">
<i class="sn-icon sn-icon-duplicate"></i>
</button>
<button v-if="element.attributes.orderable.urls.move_targets_url" class="btn btn-light btn-sm" tabindex="0" @click="showMoveModal">
Move
</button>
<button v-if="element.attributes.orderable.urls.delete_url" class="btn icon-btn btn-light btn-sm" @click="showDeleteModal" tabindex="0">
<i class="sn-icon sn-icon-delete"></i>
</button>
@ -76,21 +79,27 @@
{{ i18n.t("protocols.steps.checklist.empty_checklist") }}
</div>
<deleteElementModal v-if="confirmingDelete" @confirm="deleteElement" @cancel="closeDeleteModal"/>
<moveElementModal v-if="movingElement"
:parent_type="element.attributes.orderable.parent_type"
:targets_url="element.attributes.orderable.urls.move_targets_url"
@confirm="moveElement($event)" @cancel="closeMoveModal"/>
</div>
</template>
<script>
import DeleteMixin from './mixins/delete.js'
import MoveMixin from './mixins/move.js'
import DuplicateMixin from './mixins/duplicate.js'
import deleteElementModal from './modal/delete.vue'
import InlineEdit from '../inline_edit.vue'
import ChecklistItem from './checklistItem.vue'
import Draggable from 'vuedraggable'
import moveElementModal from './modal/move.vue'
export default {
name: 'Checklist',
components: { deleteElementModal, InlineEdit, ChecklistItem, Draggable },
mixins: [DeleteMixin, DuplicateMixin],
components: { deleteElementModal, InlineEdit, ChecklistItem, Draggable, moveElementModal },
mixins: [DeleteMixin, DuplicateMixin, MoveMixin],
props: {
element: {
type: Object,

View file

@ -0,0 +1,25 @@
import axios from '../../../../packs/custom_axios.js';
export default {
data() {
return {
movingElement: false
};
},
methods: {
showMoveModal(event) {
event.stopPropagation();
this.movingElement = true;
},
closeMoveModal() {
this.movingElement = false;
},
moveElement(target_id) {
axios.post(this.element.attributes.orderable.urls.move_url, { target_id: target_id }).
then(() => {
this.movingElement = false;
this.$emit('moved', this.element.attributes.position, target_id);
});
}
}
};

View file

@ -0,0 +1,83 @@
<template>
<div ref="modal" @keydown.esc="cancel" class="modal" id="modalDestroyProtocolContent" 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" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
<h4 class="modal-title" id="modal-destroy-team-label">
{{ i18n.t(`protocols.steps.modals.move_element.${parent_type}.title`) }}
</h4>
</div>
<div class="modal-body">
<label>
{{ i18n.t(`protocols.steps.modals.move_element.${parent_type}.targets_label`) }}
</label>
<div class="w-full">
<Select
:value="target"
:options="targets"
v-bind:disabled="false"
@change="setTarget"
></Select>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" @click="cancel">{{ i18n.t('general.cancel') }}</button>
<button class="btn btn-primary" @click="confirm">{{ i18n.t('general.save')}}</button>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from '../../../../packs/custom_axios.js';
import Select from "../../select.vue";
export default {
name: 'moveElementModal',
props: {
parent_type: {
type: String,
required: true
},
targets_url: {
type: String,
required: true
}
},
data () {
return {
target: null,
targets: []
}
},
components: {
Select
},
mounted() {
$(this.$refs.modal).modal('show');
$(this.$refs.modal).on('hidden.bs.modal', () => {
this.$emit('cancel');
});
this.fetchTargets();
},
methods: {
setTarget(target) {
this.target = target;
},
fetchTargets() {
axios.get(this.targets_url)
.then(response => {
this.targets = response.data.targets;
})
},
confirm() {
$(this.$refs.modal).modal('hide');
this.$emit('confirm', this.target);
},
cancel() {
$(this.$refs.modal).modal('hide');
}
}
}
</script>

View file

@ -28,6 +28,9 @@
<button v-if="element.attributes.orderable.urls.duplicate_url" class="btn icon-btn btn-light" tabindex="0" @click="duplicateElement">
<i class="sn-icon sn-icon-duplicate"></i>
</button>
<button v-if="element.attributes.orderable.urls.move_targets_url" class="btn btn-light btn-sm" tabindex="0" @click="showMoveModal">
Move
</button>
<button v-if="element.attributes.orderable.urls.delete_url" class="btn icon-btn btn-light" @click="showDeleteModal" tabindex="0">
<i class="sn-icon sn-icon-delete"></i>
</button>
@ -59,20 +62,26 @@
</div>
<deleteElementModal v-if="confirmingDelete" @confirm="deleteElement" @cancel="closeDeleteModal"/>
<tableNameModal v-if="nameModalOpen" :element="element" @update="updateEmptyName" @cancel="nameModalOpen = false" />
<moveElementModal v-if="movingElement"
:parent_type="element.attributes.orderable.parent_type"
:targets_url="element.attributes.orderable.urls.move_targets_url"
@confirm="moveElement($event)" @cancel="closeMoveModal"/>
</div>
</template>
<script>
import DeleteMixin from './mixins/delete.js'
import MoveMixin from './mixins/move.js'
import DuplicateMixin from './mixins/duplicate.js'
import deleteElementModal from './modal/delete.vue'
import InlineEdit from '../inline_edit.vue'
import TableNameModal from './modal/table_name.vue'
import moveElementModal from './modal/move.vue'
export default {
name: 'ContentTable',
components: { deleteElementModal, InlineEdit, TableNameModal },
mixins: [DeleteMixin, DuplicateMixin],
components: { deleteElementModal, InlineEdit, TableNameModal, moveElementModal },
mixins: [DeleteMixin, DuplicateMixin, MoveMixin],
props: {
element: {
type: Object,

View file

@ -15,6 +15,9 @@
<button v-if="element.attributes.orderable.urls.duplicate_url" class="btn icon-btn btn-light btn-sm" tabindex="0" @click="duplicateElement">
<i class="sn-icon sn-icon-duplicate"></i>
</button>
<button v-if="element.attributes.orderable.urls.move_targets_url" class="btn btn-light btn-sm" tabindex="0" @click="showMoveModal">
Move
</button>
<button v-if="element.attributes.orderable.urls.delete_url" class="btn icon-btn btn-light btn-sm" @click="showDeleteModal" tabindex="0">
<i class="sn-icon sn-icon-delete"></i>
</button>
@ -41,19 +44,25 @@
{{ i18n.t("protocols.steps.text.empty_text") }}
</div>
<deleteElementModal v-if="confirmingDelete" @confirm="deleteElement($event)" @cancel="closeDeleteModal"/>
<moveElementModal v-if="movingElement"
:parent_type="element.attributes.orderable.parent_type"
:targets_url="element.attributes.orderable.urls.move_targets_url"
@confirm="moveElement($event)" @cancel="closeMoveModal"/>
</div>
</template>
<script>
import DeleteMixin from './mixins/delete.js'
import MoveMixin from './mixins/move.js'
import DuplicateMixin from './mixins/duplicate.js'
import deleteElementModal from './modal/delete.vue'
import moveElementModal from './modal/move.vue'
import Tinymce from '../tinymce.vue'
export default {
name: 'TextContent',
components: { deleteElementModal, Tinymce },
mixins: [DeleteMixin, DuplicateMixin],
components: { deleteElementModal, Tinymce, moveElementModal },
mixins: [DeleteMixin, DuplicateMixin, MoveMixin],
props: {
element: {
type: Object,

View file

@ -111,4 +111,10 @@ class Result < ApplicationRecord
def comments
result_comments
end
def normalize_elements_position
result_orderable_elements.order(:position).each_with_index do |element, index|
element.update!(position: index) unless element.position == index
end
end
end

View file

@ -180,6 +180,12 @@ class Step < ApplicationRecord
end
end
def normalize_elements_position
step_orderable_elements.order(:position).each_with_index do |element, index|
element.update!(position: index) unless element.position == index
end
end
private
def touch_protocol

View file

@ -23,13 +23,7 @@ class StepOrderableElement < ApplicationRecord
def decrement_following_elements_positions
step.with_lock do
yield
step.step_orderable_elements
.where('position > ?', position)
.order(position: :asc).each do |step_orderable_element|
# find_each ignore any ordering
step_orderable_element.position -= 1
step_orderable_element.save!
end
step.normalize_elements_position
end
end
end

View file

@ -6,12 +6,16 @@ class ChecklistSerializer < ActiveModel::Serializer
include ApplicationHelper
include ActionView::Helpers::TextHelper
attributes :id, :name, :urls, :icon, :sa_name, :checklist_items
attributes :id, :name, :urls, :icon, :sa_name, :checklist_items, :parent_type
def icon
'fa-list-ul'
end
def parent_type
:step
end
def checklist_items
object.checklist_items.map do |item|
ChecklistItemSerializer.new(item, scope: { user: scope[:user] || @instance_options[:user] }).as_json
@ -34,7 +38,9 @@ class ChecklistSerializer < ActiveModel::Serializer
delete_url: step_checklist_path(object.step, object),
update_url: step_checklist_path(object.step, object),
reorder_url: reorder_step_checklist_checklist_items_path(object.step, object),
create_item_url: step_checklist_checklist_items_path(object.step, object)
create_item_url: step_checklist_checklist_items_path(object.step, object),
move_targets_url: move_targets_step_checklist_path(object.step, object),
move_url: move_step_checklist_path(object.step, object)
}
end
end

View file

@ -4,7 +4,7 @@ class ResultTableSerializer < ActiveModel::Serializer
include Canaid::Helpers::PermissionsHelper
include Rails.application.routes.url_helpers
attributes :name, :contents, :urls, :icon, :metadata
attributes :name, :contents, :urls, :icon, :metadata, :parent_type
def contents
object.contents_utf_8
@ -14,20 +14,23 @@ class ResultTableSerializer < ActiveModel::Serializer
'fa-table'
end
def parent_type
:result
end
def urls
return if object.destroyed?
object.reload unless object.result
p object.result
p scope[:user] || @instance_options[:user]
p can_manage_result?(scope[:user] || @instance_options[:user], object.result)
return {} unless can_manage_result?(scope[:user] || @instance_options[:user], object.result)
{
duplicate_url: duplicate_my_module_result_table_path(object.result.my_module, object.result, object),
delete_url: my_module_result_table_path(object.result.my_module, object.result, object),
update_url: my_module_result_table_path(object.result.my_module, object.result, object)
update_url: my_module_result_table_path(object.result.my_module, object.result, object),
move_targets_url: move_targets_my_module_result_table_path(object.result.my_module, object.result, object),
move_url: move_my_module_result_table_path(object.result.my_module, object.result, object)
}
end
end

View file

@ -6,7 +6,7 @@ class ResultTextSerializer < ActiveModel::Serializer
include ApplicationHelper
include ActionView::Helpers::TextHelper
attributes :id, :text, :urls, :text_view, :icon, :placeholder, :name
attributes :id, :text, :urls, :text_view, :icon, :placeholder, :name, :parent_type
def updated_at
object.updated_at.to_i
@ -16,6 +16,10 @@ class ResultTextSerializer < ActiveModel::Serializer
I18n.t('protocols.steps.text.placeholder')
end
def parent_type
:result
end
def text_view
@user = scope[:user]
custom_auto_link(object.tinymce_render('text'),
@ -40,7 +44,9 @@ class ResultTextSerializer < ActiveModel::Serializer
{
duplicate_url: duplicate_my_module_result_text_path(result.my_module, result, object),
delete_url: my_module_result_text_path(result.my_module, result, object),
update_url: my_module_result_text_path(result.my_module, result, object)
update_url: my_module_result_text_path(result.my_module, result, object),
move_targets_url: move_targets_my_module_result_text_path(result.my_module, result, object),
move_url: move_my_module_result_text_path(result.my_module, result, object)
}
end
end

View file

@ -6,12 +6,16 @@ class StepTextSerializer < ActiveModel::Serializer
include ApplicationHelper
include ActionView::Helpers::TextHelper
attributes :id, :text, :urls, :text_view, :updated_at, :icon, :name, :placeholder
attributes :id, :text, :urls, :text_view, :updated_at, :icon, :name, :placeholder, :parent_type
def updated_at
object.updated_at.to_i
end
def parent_type
:step
end
def placeholder
I18n.t('protocols.steps.text.placeholder')
end
@ -38,7 +42,9 @@ class StepTextSerializer < ActiveModel::Serializer
{
duplicate_url: duplicate_step_text_path(object.step, object),
delete_url: step_text_path(object.step, object),
update_url: step_text_path(object.step, object)
update_url: step_text_path(object.step, object),
move_url: move_step_text_path(object.step, object),
move_targets_url: move_targets_step_text_path(object.step, object)
}
end
end

View file

@ -4,7 +4,7 @@ class TableSerializer < ActiveModel::Serializer
include Canaid::Helpers::PermissionsHelper
include Rails.application.routes.url_helpers
attributes :name, :contents, :urls, :icon, :metadata
attributes :name, :contents, :urls, :icon, :metadata, :parent_type
def contents
object.contents_utf_8
@ -14,6 +14,10 @@ class TableSerializer < ActiveModel::Serializer
'fa-table'
end
def parent_type
:step
end
def urls
return if object.destroyed?
@ -24,7 +28,9 @@ class TableSerializer < ActiveModel::Serializer
{
duplicate_url: duplicate_step_table_path(object.step, object),
delete_url: step_table_path(object.step, object),
update_url: step_table_path(object.step, object)
update_url: step_table_path(object.step, object),
move_targets_url: move_targets_step_table_path(object.step, object),
move_url: move_step_table_path(object.step, object)
}
end
end

View file

@ -3099,6 +3099,13 @@ en:
description_1: 'Youre about to delete a content block from your protocol. It might contain data you dont want to lose. You wont be able to get it back.'
description_2: 'Are you sure you want to delete it?'
confirm: 'Delete forever'
move_element:
step:
title: Move to different step
targets_label: Select step
result:
title: Move to different result
targets_label: Select result
delete_step:
title: 'Delete step'
description_1: 'Youre about to delete a whole step from your protocol. It might contain data you dont want to lose. You wont be able to get it back.'

View file

@ -542,11 +542,15 @@ Rails.application.routes.draw do
resources :tables, controller: 'result_elements/tables', only: %i(create destroy update) do
member do
get :move_targets
post :move
post :duplicate
end
end
resources :texts, controller: 'result_elements/texts', only: %i(create destroy update) do
member do
get :move_targets
post :move
post :duplicate
end
end
@ -562,16 +566,22 @@ Rails.application.routes.draw do
only: %i(create index update destroy)
resources :tables, controller: 'step_elements/tables', only: %i(create destroy update) do
member do
get :move_targets
post :move
post :duplicate
end
end
resources :texts, controller: 'step_elements/texts', only: %i(create destroy update) do
member do
get :move_targets
post :move
post :duplicate
end
end
resources :checklists, controller: 'step_elements/checklists', only: %i(create destroy update) do
member do
get :move_targets
post :move
post :duplicate
end
resources :checklist_items, controller: 'step_elements/checklist_items', only: %i(create update destroy) do