Add reorder form fields [SCI-11343]

This commit is contained in:
Anton 2024-12-12 13:50:17 +01:00
parent 29f59293f4
commit 9d92679c58
6 changed files with 37 additions and 22 deletions

View file

@ -36,7 +36,7 @@ class FormFieldsController < ApplicationController
def destroy
ActiveRecord::Base.transaction do
if @form_field.discard
if @form_field.destroy
render json: {}
else
render json: { error: @form_field.errors.full_messages }, status: :unprocessable_entity

View file

@ -34,17 +34,29 @@
<div class="p-6 border-transparent border-r-sn-sleepy-grey border-solid border-r">
<h3 class="mb-3">{{ i18n.t('forms.show.build_form') }}</h3>
<div class="mb-3 flex flex-col gap-3">
<div v-for="(field) in fields"
@click="activeField = field"
:key="field.id"
class="font-bold p-3 rounded-lg flex items-center gap-2 border-sn-grey-100 cursor-pointer border"
:class="{ '!border-sn-blue bg-sn-super-light-blue': activeField.id === field.id }"
>
<i class="sn-icon rounded text-sn-blue bg-sn-super-light-blue p-1" :class="fieldIcon[field.attributes.data.type]"></i>
{{ field.attributes.name }}
</div>
<Draggable
v-model="fields"
class="flex flex-col gap-3"
handle=".element-grip"
item-key="id"
@end="saveOrder"
>
<template #item="{element, index}">
<div class="flex items-center relative group -ml-6 w-[calc(100%_+_24px)]">
<i class="sn-icon sn-icon-drag text-sn-grey element-grip cursor-grab opacity-0 group-hover:opacity-100"></i>
<div @click="activeField = element"
:key="element.id"
class="font-bold relative grow p-2 rounded-lg overflow-hidden flex items-center gap-2 border-sn-grey-100 cursor-pointer border"
:class="{ '!border-sn-blue bg-sn-super-light-blue': activeField.id === element.id }"
>
<i class="sn-icon rounded text-sn-blue bg-sn-super-light-blue p-1" :class="fieldIcon[element.attributes.data.type]"></i>
<span class="truncate">{{ element.attributes.name }}</span>
</div>
</div>
</template>
</Draggable>
</div>
<GeneralDropdown>
<GeneralDropdown ref="addFieldDropdown">
<template v-slot:field>
<button class="btn btn-secondary w-full">
<i class="sn-icon sn-icon-new-task"></i>
@ -76,6 +88,7 @@
<script>
import Draggable from 'vuedraggable';
import InlineEdit from '../shared/inline_edit.vue';
import axios from '../../packs/custom_axios.js';
import GeneralDropdown from '../shared/general_dropdown.vue';
@ -89,7 +102,8 @@ export default {
components: {
InlineEdit,
GeneralDropdown,
EditField
EditField,
Draggable
},
computed: {
canManage() {
@ -129,6 +143,7 @@ export default {
axios.get(this.formUrl).then((response) => {
this.form = response.data.data;
this.fields = response.data.included || [];
this.fields = this.fields.sort((a, b) => a.attributes.position - b.attributes.position);
if (this.fields.length > 0) {
[this.activeField] = this.fields;
}
@ -147,6 +162,7 @@ export default {
if (this.fields.length === 1) {
[this.activeField] = this.fields;
}
this.$refs.addFieldDropdown.isOpen = false;
});
},
updateName(name) {
@ -166,6 +182,11 @@ export default {
this.fields.splice(index, 1, response.data.data);
});
},
saveOrder() {
axios.post(this.form.attributes.urls.reorder_fields, {
form_field_positions: this.fields.map((f, i) => ({ id: f.id, position: i }))
});
},
deleteField(field) {
const index = this.fields.findIndex((f) => f.id === field.id);
axios.delete(field.attributes.urls.show).then(() => {

View file

@ -1,9 +1,6 @@
# frozen_string_literal: true
class FormField < ApplicationRecord
include Discard::Model
default_scope -> { kept }
belongs_to :form
belongs_to :created_by, class_name: 'User'
@ -13,6 +10,6 @@ class FormField < ApplicationRecord
validates :description, length: { maximum: Constants::NAME_MAX_LENGTH }
validates :position, presence: true, uniqueness: { scope: :form }
acts_as_list scope: [:form, discarded_at: nil], top_of_list: 0, sequential_updates: true
acts_as_list scope: :form, top_of_list: 0, sequential_updates: true
end

View file

@ -8,8 +8,7 @@ class FormSerializer < ActiveModel::Serializer
has_many :form_fields,
key: :form_fields,
serializer: FormFieldSerializer,
order: :position
serializer: FormFieldSerializer
def published_by
object.published_by&.full_name
@ -26,7 +25,8 @@ class FormSerializer < ActiveModel::Serializer
def urls
{
show: form_path(object),
create_field: form_form_fields_path(object)
create_field: form_form_fields_path(object),
reorder_fields: reorder_form_form_fields_path(object)
}
end
end

View file

@ -31,7 +31,6 @@ class CreateForms < ActiveRecord::Migration[7.0]
t.boolean :required, default: false, null: false
t.boolean :allow_not_applicable, default: false, null: false
t.string :uid
t.datetime :discarded_at, index: true
t.timestamps
end

View file

@ -235,11 +235,9 @@ ActiveRecord::Schema[7.0].define(version: 2024_12_09_074134) do
t.boolean "required", default: false, null: false
t.boolean "allow_not_applicable", default: false, null: false
t.string "uid"
t.datetime "discarded_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["created_by_id"], name: "index_form_fields_on_created_by_id"
t.index ["discarded_at"], name: "index_form_fields_on_discarded_at"
t.index ["form_id"], name: "index_form_fields_on_form_id"
t.index ["last_modified_by_id"], name: "index_form_fields_on_last_modified_by_id"
end