use slicksort for reordering questionnaires and questions

This commit is contained in:
Mira Weller
2026-05-05 18:12:21 +02:00
parent 3a1a6b988e
commit 3cee5f524b
5 changed files with 37 additions and 27 deletions

22
package-lock.json generated
View File

@@ -9,7 +9,8 @@
"version": "1.0.0",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"vue": "^3.5.30"
"vue": "^3.5.30",
"vue-slicksort": "^2.0.5"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
@@ -1032,7 +1033,6 @@
"integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/types": "^8.56.0",
@@ -1103,7 +1103,6 @@
"integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.18.0"
}
@@ -1160,7 +1159,6 @@
"integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.57.0",
"@typescript-eslint/types": "8.57.0",
@@ -1568,7 +1566,6 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -1961,7 +1958,6 @@
"integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.2",
@@ -2018,7 +2014,6 @@
"integrity": "sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"natural-compare": "^1.4.0",
@@ -4269,7 +4264,6 @@
"integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@adobe/css-tools": "~4.3.3",
"debug": "^4.3.2",
@@ -4469,7 +4463,6 @@
"integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@oxc-project/runtime": "0.115.0",
"lightningcss": "^1.32.0",
@@ -4565,7 +4558,6 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz",
"integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.30",
"@vue/compiler-sfc": "3.5.30",
@@ -4588,7 +4580,6 @@
"integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"debug": "^4.4.0",
"eslint-scope": "^8.2.0 || ^9.0.0",
@@ -4620,6 +4611,15 @@
"vue-eslint-parser": "^10.0.0"
}
},
"node_modules/vue-slicksort": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/vue-slicksort/-/vue-slicksort-2.0.5.tgz",
"integrity": "sha512-fXz1YrNjhUbJK7o0tMk27mIr4pMAZYLSYvtmLazCtfpvz+zafPCn34ILDL8B7hT7WLVZKreYs6JVe5VWymqmzA==",
"license": "MIT",
"peerDependencies": {
"vue": ">=3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@@ -27,7 +27,8 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"vue": "^3.5.30"
"vue": "^3.5.30",
"vue-slicksort": "^2.0.5"
},
"devDependencies": {
"@eslint/js": "^10.0.1",

View File

@@ -3,6 +3,7 @@ import Questionnaire from './Questionnaire.vue';
import {get_datafields, get_items, get_questionnaires} from './api';
import { i18n_any, QUESTION_TYPE } from './helper';
import { ref } from 'vue';
import { SlickList, SlickItem } from 'vue-slicksort';
const datafields_response = await get_datafields();
const questionnaires_response = await get_questionnaires();
@@ -56,14 +57,16 @@ export default {
</select>
</p>
<div class="question-editor">
<SlickList axis="y" v-model:list="questionnaires" useDragHandle appendTo="#questionnaireListParent" id="questionnaireListParent">
<SlickItem v-for="(questionnaire, index) in questionnaires" :key="questionnaire.id" :index="index">
<Questionnaire
v-for="questionnaire in questionnaires"
:questionnaire="questionnaire"
:datafields="datafields"
:items="items"
:selected_product="selected_product" />
</SlickItem>
</SlickList>
</div>
<p>
<button class="btn btn-default" @click="addQuestionnaire()"><i class="fa fa-plus"></i> Neuen Fragebogen erstellen</button>
</p>

View File

@@ -3,6 +3,8 @@ import { i18n_any, QUESTION_TYPE, QUESTION_TYPE_LABEL, SYSTEM_DATAFIELDS } from
import NativeDialog from './NativeDialog.vue';
import I18nTextField from './I18nTextField.vue';
import { useId, ref } from 'vue'
import { DragHandle } from 'vue-slicksort';
const id = useId();
const props = defineProps(['question', 'datafields', 'editable'])
const emit = defineEmits(['removeSelf']);
@@ -23,7 +25,7 @@ const editor = ref();
<template>
<div class="form-group">
<div class="question-edit-buttons" v-if="editable"><div>
<button class="btn btn-default"><i class="fa fa-arrows"></i></button>
<DragHandle tag="button" class="btn btn-default"><i class="fa fa-arrows"></i></DragHandle>
<button class="btn btn-default" @click="editor.show()"><i class="fa fa-edit"></i></button>
</div></div>

View File

@@ -4,6 +4,7 @@ import Question from "./Question.vue";
import {i18n_any, QUESTION_TYPE, QUESTION_TYPE_LABEL} from "./helper";
import I18nTextField from "./I18nTextField.vue";
import NativeDialog from "./NativeDialog.vue";
import { SlickList, SlickItem, DragHandle } from 'vue-slicksort';
const dlgEditor = ref();
const dlgAddExisting = ref();
@@ -62,11 +63,11 @@ const isEditable = computed(() => props.selected_product && props.questionnaire.
<template>
<div class="question-edit-buttons"><div>
<button class="btn btn-default"><i class="fa fa-arrows"></i></button>
<button class="btn btn-default" @click="dlgEditor.show()"><i class="fa fa-edit"></i></button>
<button class="btn btn-default" @click="toggleItem()" v-if="selected_product"><i :class="`fa fa-eye${isHidden ? '-slash':''}`"></i></button>
</div></div>
<div class="question-edit-buttons"><div>
<DragHandle tag="button" class="btn btn-default"><i class="fa fa-arrows"></i></DragHandle>
<button class="btn btn-default" @click="dlgEditor.show()"><i class="fa fa-edit"></i></button>
<button class="btn btn-default" @click="toggleItem()" v-if="selected_product"><i :class="`fa fa-eye${isHidden ? '-slash':''}`"></i></button>
</div></div>
<details class="panel panel-default " :open="!!isEditable"
:class="{ 'hidden-question': isHidden }">
@@ -74,14 +75,17 @@ const isEditable = computed(() => props.selected_product && props.questionnaire.
{{ props.questionnaire.internal_name }}
</summary>
<div class="panel-body" v-if="!isHidden">
<div class="form-horizontal">
<div class="form-horizontal" :id="`questionListParent${props.questionnaire.id}`">
<Question
v-for="(child, index) in props.questionnaire.children" :key="index"
:datafields="props.datafields"
:question="child"
:editable="true"
@remove-self="questionnaire.children.splice(index, 1)" />
<SlickList axis="y" v-model:list="props.questionnaire.children" useDragHandle :appendTo="`#questionListParent${props.questionnaire.id}`">
<SlickItem v-for="(child, index) in props.questionnaire.children" :key="child.id" :index="index">
<Question
:datafields="props.datafields"
:question="child"
:editable="true"
@remove-self="questionnaire.children.splice(index, 1)" />
</SlickItem>
</SlickList>
</div>
<p v-if="true">