This commit is contained in:
Mira Weller
2026-03-27 18:57:22 +01:00
parent 583184af38
commit bdc720f5a2
5 changed files with 63 additions and 23 deletions

View File

@@ -541,6 +541,7 @@ class LegacyDependencyValueField(serializers.CharField):
class QuestionSerializer(I18nAwareModelSerializer): class QuestionSerializer(I18nAwareModelSerializer):
options = InlineQuestionOptionSerializer(many=True, required=False) options = InlineQuestionOptionSerializer(many=True, required=False)
identifier = serializers.CharField(allow_null=True) identifier = serializers.CharField(allow_null=True)
internal_name = serializers.CharField(allow_null=True, source='question', read_only=True)
dependency_value = LegacyDependencyValueField(source='dependency_values', required=False, allow_null=True) dependency_value = LegacyDependencyValueField(source='dependency_values', required=False, allow_null=True)
class Meta: class Meta:
@@ -549,7 +550,7 @@ class QuestionSerializer(I18nAwareModelSerializer):
'ask_during_checkin', 'show_during_checkin', 'identifier', 'dependency_question', 'dependency_values', 'ask_during_checkin', 'show_during_checkin', 'identifier', 'dependency_question', 'dependency_values',
'hidden', 'dependency_value', 'print_on_invoice', 'help_text', 'valid_number_min', 'hidden', 'dependency_value', 'print_on_invoice', 'help_text', 'valid_number_min',
'valid_number_max', 'valid_date_min', 'valid_date_max', 'valid_datetime_min', 'valid_datetime_max', 'valid_number_max', 'valid_date_min', 'valid_date_max', 'valid_datetime_min', 'valid_datetime_max',
'valid_string_length_max', 'valid_file_portrait') 'valid_string_length_max', 'valid_file_portrait', 'internal_name',)
def validate_identifier(self, value): def validate_identifier(self, value):
Question._clean_identifier(self.context['event'], value, self.instance) Question._clean_identifier(self.context['event'], value, self.instance)

View File

@@ -10,10 +10,12 @@
{% trans "Questionnaires" %} {% trans "Questionnaires" %}
{% endblock %} {% endblock %}
{% block inside %} {% block inside %}
<a href="{% url "control:event.items.questions" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default pull-right"> <h1>
{% icon "wrench" %} {% trans "Manage data fields" %} {% trans "Questionnaires" %}
</a> <a href="{% url "control:event.items.questions" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default pull-right">
<h1>{% trans "Questionnaires" %}</h1> {% icon "wrench" %} {% trans "Manage data fields" %}
</a>
</h1>
<p> <p>
{% blocktrans trimmed %} {% blocktrans trimmed %}
Questions allow your attendees to fill in additional data about their ticket. If you provide food, one Questions allow your attendees to fill in additional data about their ticket. If you provide food, one

View File

@@ -61,16 +61,6 @@ const editor = ref();
<I18nTextField :value="question.label"/> <I18nTextField :value="question.label"/>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">
Data field type
</label>
<div class="col-md-9">
<select v-model="df.type" class="form-control">
<option v-for="(label, type) in QUESTION_TYPE_LABEL" :value="QUESTION_TYPE[type]">{{ label }}</option>
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label"> <label class="col-md-3 control-label">
Help text Help text
@@ -80,6 +70,27 @@ const editor = ref();
<div class="help-block">Wenn diese Frage noch weitere Erklärung braucht, können Sie sie hier eintragen.</div> <div class="help-block">Wenn diese Frage noch weitere Erklärung braucht, können Sie sie hier eintragen.</div>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">
Data field
</label>
<div class="col-md-9">
<p class="form-control-static">
{{ question.question }}
<a href="" target="_blank">Manage data field details</a>
</p>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">
Data field type
</label>
<div class="col-md-9">
<select v-model="df.type" class="form-control" disabled>
<option v-for="(label, type) in QUESTION_TYPE_LABEL" :value="QUESTION_TYPE[type]">{{ label }}</option>
</select>
</div>
</div>
<button @click="editor.close()" class="btn btn-primary pull-right"><span class="fa fa-check"></span> Save and close</button> <button @click="editor.close()" class="btn btn-primary pull-right"><span class="fa fa-check"></span> Save and close</button>
<button @click="emit('removeSelf')" class="btn btn-default">Remove from questionnaire</button> <button @click="emit('removeSelf')" class="btn btn-default">Remove from questionnaire</button>
</NativeDialog> </NativeDialog>

View File

@@ -6,6 +6,7 @@ import I18nTextField from "./I18nTextField.vue";
import NativeDialog from "./NativeDialog.vue"; import NativeDialog from "./NativeDialog.vue";
const id = useId(); const id = useId();
const props = defineProps(['questionnaire', 'datafields', 'selected_product', 'items']) const props = defineProps(['questionnaire', 'datafields', 'selected_product', 'items'])
const gettext = (window as any).gettext
function toggleItem() { function toggleItem() {
const i = props.questionnaire.items.indexOf(props.selected_product); const i = props.questionnaire.items.indexOf(props.selected_product);
@@ -16,10 +17,23 @@ function toggleItem() {
} }
} }
function addExistingDatafield(field) {
props.questionnaire.children.push({
question: field.id,
required: false,
label: {},
help_text: {},
dependency_question: null,
dependency_values: [],
});
dlgAddExisting.value.close();
}
const isHidden = computed(() => props.selected_product && props.questionnaire.items.indexOf(props.selected_product) === -1); const isHidden = computed(() => props.selected_product && props.questionnaire.items.indexOf(props.selected_product) === -1);
const isEditable = computed(() => props.selected_product && props.questionnaire.items.indexOf(props.selected_product) !== -1); const isEditable = computed(() => props.selected_product && props.questionnaire.items.indexOf(props.selected_product) !== -1);
const editor = ref(); const dlgEditor = ref();
const dlgAddExisting = ref();
</script> </script>
@@ -27,7 +41,7 @@ const editor = ref();
<template> <template>
<div class="question-edit-buttons"><div> <div class="question-edit-buttons"><div>
<button class="btn btn-default"><i class="fa fa-arrows"></i></button> <button class="btn btn-default"><i class="fa fa-arrows"></i></button>
<button class="btn btn-default" @click="editor.show()"><i class="fa fa-edit"></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> <button class="btn btn-default" @click="toggleItem()" v-if="selected_product"><i :class="`fa fa-eye${isHidden ? '-slash':''}`"></i></button>
</div></div> </div></div>
@@ -48,7 +62,7 @@ const editor = ref();
</div> </div>
<p v-if="true"> <p v-if="true">
<button class="btn btn-default" @click="addExistingDatafield()"><i class="fa fa-plus"></i> Bestehendes Datenfeld hinzufügen</button> <button class="btn btn-default" @click="dlgAddExisting.show()"><i class="fa fa-plus"></i> Bestehendes Datenfeld hinzufügen</button>
<button class="btn btn-default" @click="newDatafield()"><i class="fa fa-plus"></i> Neues Datenfeld</button> <button class="btn btn-default" @click="newDatafield()"><i class="fa fa-plus"></i> Neues Datenfeld</button>
<button class="btn btn-default" @click="addSubtitle()"><i class="fa fa-plus"></i> Zwischenüberschrift</button> <button class="btn btn-default" @click="addSubtitle()"><i class="fa fa-plus"></i> Zwischenüberschrift</button>
<button class="btn btn-default" @click="addTextBlock()"><i class="fa fa-plus"></i> Text</button> <button class="btn btn-default" @click="addTextBlock()"><i class="fa fa-plus"></i> Text</button>
@@ -57,11 +71,11 @@ const editor = ref();
</details> </details>
<Teleport to="body"> <Teleport to="body">
<NativeDialog ref="editor" class="modal-card" <NativeDialog ref="dlgEditor" class="modal-card"
title="Edit questionnaire"> :title="gettext('Edit questionnaire')">
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label"> <label class="col-md-3 control-label">
Internal name {{ gettext('Internal name') }}
</label> </label>
<div class="col-md-9"> <div class="col-md-9">
<input type="text" class="form-control" v-model="questionnaire.internal_name"/> <input type="text" class="form-control" v-model="questionnaire.internal_name"/>
@@ -69,7 +83,7 @@ const editor = ref();
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label"> <label class="col-md-3 control-label">
Visible on products {{ gettext('Visible on products') }}
</label> </label>
<div class="col-md-9"> <div class="col-md-9">
<div class="checkbox" v-for="item in items"> <div class="checkbox" v-for="item in items">
@@ -79,8 +93,18 @@ const editor = ref();
</div> </div>
</div> </div>
</div> </div>
<button @click="editor.close()" class="btn btn-primary pull-right"><span class="fa fa-check"></span> Save and close</button> <button @click="dlgEditor.close()" class="btn btn-primary pull-right"><span class="fa fa-check"></span> {{ gettext('Save and close') }}</button>
<button class="btn btn-default">Delete</button> <button class="btn btn-default">Delete</button>
</NativeDialog> </NativeDialog>
<NativeDialog ref="dlgAddExisting" class="modal-card"
:title="gettext('Add existing data field')">
<div class="list-group">
<a href="javascript:" @click="addExistingDatafield(field)" v-for="field in datafields" class="list-group-item">{{ field.internal_name }}</a>
</div>
<button @click="dlgAddExisting.close()" class="btn btn-default pull-right">Cancel</button>
</NativeDialog>
</Teleport> </Teleport>
</template> </template>

View File

@@ -1,6 +1,8 @@
export function i18n_any(data) { export function i18n_any(data) {
if (!data) return null; if (!data) return null;
const preferred = document.body.getAttribute("data-pretixlocale");
if (data[preferred]) return data[preferred];
return Object.values(data)[0]; return Object.values(data)[0];
} }