[UPDT] HORILLA: Merge fixes from v1
This commit is contained in:
@@ -9,11 +9,11 @@
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{%if message.tags == "oh-alert--success" %}
|
||||
<span class="oh-span__class" hx-trigger="load" hx-get="{%url 'asset-list' cat_id=instance.asset_category_id.id %}?{{pd}}"
|
||||
hx-target="#assetCategory{{instance.asset_category_id.id}}"></span>
|
||||
{% endif %}
|
||||
hx-target="#assetCategory{{instance.asset_category_id.id}}"></span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -175,4 +175,4 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
<div id="dis-container">
|
||||
<div id="dis-container">
|
||||
{% include "generic/horilla_list.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -33,6 +33,8 @@ class AutomationForm(ModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# --- Field: also_sent_to ---
|
||||
self.fields["also_sent_to"] = HorillaMultiSelectField(
|
||||
queryset=Employee.objects.all(),
|
||||
required=False,
|
||||
@@ -46,41 +48,57 @@ class AutomationForm(ModelForm):
|
||||
label="Also Sent to",
|
||||
help_text=_("The employees selected here will receive the email as Cc."),
|
||||
)
|
||||
if not self.data:
|
||||
mail_to = []
|
||||
|
||||
initial = []
|
||||
mail_details_choice = []
|
||||
if self.instance.pk:
|
||||
mail_to = generate_choices(self.instance.model)[0]
|
||||
mail_details_choice = generate_choices(self.instance.model)[1]
|
||||
self.fields["mail_to"] = forms.MultipleChoiceField(choices=mail_to)
|
||||
self.fields["mail_details"] = forms.ChoiceField(
|
||||
choices=mail_details_choice,
|
||||
help_text="Fill mail template details(reciever/instance, `self` will be the person who trigger the automation)",
|
||||
)
|
||||
self.fields["mail_to"].initial = initial
|
||||
attrs = self.fields["mail_to"].widget.attrs
|
||||
attrs["class"] = "oh-select oh-select-2 w-100"
|
||||
attrs = self.fields["model"].widget.attrs
|
||||
self.fields["model"].choices = [("", "Select model")] + list(set(MODEL_CHOICES))
|
||||
attrs["onchange"] = "getToMail($(this))"
|
||||
# --- Determine model for generate_choices ---
|
||||
model = getattr(self.instance, "model", None) or self.data.get("model")
|
||||
mail_to, mail_details_choice = [], []
|
||||
|
||||
if model:
|
||||
choices = generate_choices(model)
|
||||
mail_to, mail_details_choice = choices[0], choices[1]
|
||||
|
||||
# --- Field: mail_to ---
|
||||
self.fields["mail_to"] = forms.MultipleChoiceField(
|
||||
choices=mail_to,
|
||||
initial=self.data.get("mail_to"),
|
||||
widget=forms.SelectMultiple(attrs={"class": "oh-select oh-select-2 w-100"}),
|
||||
)
|
||||
|
||||
# --- Field: mail_details ---
|
||||
self.fields["mail_details"] = forms.ChoiceField(
|
||||
choices=mail_details_choice,
|
||||
help_text=_(
|
||||
"Fill mail template details (receiver/instance, `self` will be the person who triggers the automation)"
|
||||
),
|
||||
)
|
||||
self.fields["mail_details"].widget.attrs = {
|
||||
"class": "oh-select oh-select-2 w-100"
|
||||
}
|
||||
|
||||
# --- Field: model ---
|
||||
self.fields["model"].choices = [("", "Select model")] + sorted(
|
||||
set(MODEL_CHOICES)
|
||||
)
|
||||
self.fields["model"].widget.attrs["onchange"] = "getToMail($(this))"
|
||||
|
||||
# --- Field: mail_template ---
|
||||
self.fields["mail_template"].empty_label = "----------"
|
||||
attrs = attrs.copy()
|
||||
del attrs["onchange"]
|
||||
self.fields["mail_details"].widget.attrs = attrs
|
||||
|
||||
# --- Instance condition fields ---
|
||||
if self.instance.pk:
|
||||
self.fields["condition"].initial = self.instance.condition_html
|
||||
self.fields["condition_html"].initial = self.instance.condition_html
|
||||
self.fields["condition_querystring"].initial = (
|
||||
self.instance.condition_querystring
|
||||
)
|
||||
for _field_name, field in self.fields.items():
|
||||
|
||||
# --- Apply option template name for all select fields ---
|
||||
for field in self.fields.values():
|
||||
if isinstance(field.widget, forms.Select):
|
||||
field.widget.option_template_name = default_select_option_template
|
||||
|
||||
is_active_field = self.fields.pop("is_active")
|
||||
self.fields["is_active"] = is_active_field
|
||||
# --- Re-insert is_active field to ensure order ---
|
||||
self.fields["is_active"] = self.fields.pop("is_active")
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,7 +12,7 @@
|
||||
z-index: 100;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
.oh-modal__dialog {
|
||||
position: relative;
|
||||
margin: 1rem auto;
|
||||
@@ -22,29 +22,29 @@
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
|
||||
.oh-modal__dialog-header {
|
||||
position: relative;
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
|
||||
.oh-modal__dialog-body {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
|
||||
.oh-modal__dialog-footer {
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
|
||||
.oh-modal__close {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
/* Transition styles */
|
||||
[x-transition] {
|
||||
transition: all 0.3s ease;
|
||||
@@ -55,13 +55,13 @@
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="oh-card p-0" x-data="{showQuestions: true}">
|
||||
<div class="oh-card__header mb-0 p-4">
|
||||
<a href="#" class="px-4 py-2 bg-primary-600 text-white rounded-md text-xs flex w-28 justify-center items-center gap-2 hover:bg-primary-800 transition duration-300"
|
||||
<a href="#" class="px-4 py-2 bg-primary-600 text-white rounded-md text-xs flex w-28 justify-center items-center gap-2 hover:bg-primary-800 transition duration-300"
|
||||
x-show="showQuestions" @click="showQuestions = false"
|
||||
style="width: fit-content;">
|
||||
<ion-icon class="me-2" name="eye-off-outline"></ion-icon>
|
||||
{% trans "Hide Questions" %}
|
||||
</a>
|
||||
<a href="#" class="px-4 py-2 bg-primary-600 text-white rounded-md text-xs flex w-28 justify-center items-center gap-2 hover:bg-primary-800 transition duration-300"
|
||||
<a href="#" class="px-4 py-2 bg-primary-600 text-white rounded-md text-xs flex w-28 justify-center items-center gap-2 hover:bg-primary-800 transition duration-300"
|
||||
x-show="!showQuestions" @click="showQuestions = true"
|
||||
style="width: fit-content;">
|
||||
<ion-icon class="me-2" name="eye-outline"></ion-icon>
|
||||
@@ -86,11 +86,11 @@
|
||||
<td class="text-sm text-left p-3 text-[#666]">
|
||||
{{ form.instance.get_question_type_display }}
|
||||
</td>
|
||||
|
||||
|
||||
<!-- Question and Options -->
|
||||
<td class="text-sm text-left p-3 text-[#666]">
|
||||
<div class="font-medium mb-2">{{ form.instance.question }}</div>
|
||||
|
||||
|
||||
{% if form.instance.question_type == "4" %} <!-- Multiple choice -->
|
||||
<div x-data="{showOptions: false}">
|
||||
<a href="#" class="px-3 py-1 bg-[white] rounded-md text-xs flex items-center gap-2 border border-primary-500 hover:border-primary-600 transition duration-300 cursor-pointer w-fit"
|
||||
@@ -123,7 +123,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
|
||||
<!-- Actions -->
|
||||
<td class="stickyright text-sm text-center p-3 text-[#666]">
|
||||
<div class="flex justify-center gap-1">
|
||||
@@ -163,7 +163,7 @@
|
||||
class="oh-modal fixed inset-0 z-[100] overflow-y-auto"
|
||||
:class="{ 'flex items-center justify-center': open, 'hidden': !open }"
|
||||
x-transition>
|
||||
|
||||
|
||||
<div x-show="open"
|
||||
x-transition:enter="ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0"
|
||||
@@ -198,7 +198,7 @@
|
||||
<div class="oh-modal__dialog-body px-4 pb-4 sm:p-6 sm:pt-0" style="border: 1px solid #e5e7eb;padding: 18px;border-radius: 8px;">
|
||||
<form action="{% url 'question-update' temp_id=question_template.id q_id=form.instance.id %}" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="oh-label flex">
|
||||
{% trans "Question Type" %}
|
||||
@@ -274,7 +274,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function () {
|
||||
$(".oh-select--qa-change").select2();
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
@@ -283,11 +283,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('[id^="questionEditModal"]').forEach(modal => {
|
||||
const questionType = modal.querySelector('select[name="question_type"]');
|
||||
const optionsSection = modal.querySelector('#questionOptionsSection');
|
||||
|
||||
|
||||
if (questionType && optionsSection) {
|
||||
// Initial state
|
||||
optionsSection.style.display = questionType.value === '4' ? 'block' : 'none';
|
||||
|
||||
|
||||
// Change handler
|
||||
questionType.addEventListener('change', function() {
|
||||
optionsSection.style.display = this.value === '4' ? 'block' : 'none';
|
||||
@@ -295,4 +295,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1896,6 +1896,7 @@ class HorillaFormView(FormView):
|
||||
context["form_class_path"] = self.form_class_path
|
||||
context["view_id"] = self.view_id
|
||||
context["hx_confirm"] = self.hx_confirm
|
||||
context["hx_target"] = self.request.META.get("HTTP_HX_TARGET", "this")
|
||||
pk = None
|
||||
if self.form.instance:
|
||||
pk = self.form.instance.pk
|
||||
|
||||
@@ -1,80 +1,74 @@
|
||||
{% load generic_template_filters %}
|
||||
<div id="{{view_id}}">
|
||||
{% for field_tuple in dynamic_create_fields %}
|
||||
<div
|
||||
class="oh-modal"
|
||||
id="dynamicModal{{field_tuple.0}}"
|
||||
role="dialog"
|
||||
aria-labelledby="dynamicModal{{field_tuple.0}}"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div
|
||||
class="oh-modal__dialog"
|
||||
id="dynamicModal{{field_tuple.0}}Body"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<form id="{{view_id}}Form" hx-post="{{request.path}}?{{request.GET.urlencode}}" hx-encoding="multipart/form-data" hx-swap="outerHTML" {% if hx_confirm %} hx-confirm="{{hx_confirm}}" {% endif %}>{{form.structured}}</form>
|
||||
{% for field_tuple in dynamic_create_fields %}
|
||||
<div >
|
||||
<script class="dynamic_{{field_tuple.0}}_scripts">
|
||||
{{form.initial|get_item:field_tuple.0}}
|
||||
$("#{{view_id}}Form [name={{field_tuple.0}}]").val({{form.initial|get_item:field_tuple.0|safe}}).change()
|
||||
</script>
|
||||
|
||||
<form
|
||||
hidden
|
||||
id="modalButton{{field_tuple.0}}Form"
|
||||
hx-get="/dynamic-path-{{field_tuple.0}}-{{request.session.session_key}}?dynamic_field={{field_tuple.0}}"
|
||||
hx-target="#dynamicModal{{field_tuple.0}}Body"
|
||||
>
|
||||
<input type="text" name="dynamic_initial" data-dynamic-field="{{field_tuple.0}}">
|
||||
<input type="text" name="view_id" value="{{view_id}}">
|
||||
{% for field in field_tuple.2 %}
|
||||
<input type="text" name="{{field}}">
|
||||
<div id="{{ view_id }}">
|
||||
{% for field_tuple in dynamic_create_fields %}
|
||||
<div class="oh-modal" id="dynamicModal{{ field_tuple.0 }}" role="dialog"
|
||||
aria-labelledby="dynamicModal{{ field_tuple.0 }}" aria-hidden="true">
|
||||
<div class="oh-modal__dialog" id="dynamicModal{{ field_tuple.0 }}Body"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<button
|
||||
type="submit"
|
||||
id="modalButton{{field_tuple.0}}"
|
||||
onclick="$('#dynamicModal{{field_tuple.0}}').addClass('oh-modal--show');"
|
||||
>
|
||||
{{field_tuple.0}}
|
||||
</button>
|
||||
</form>
|
||||
<form hidden id="reload-field{{field_tuple.0}}{{view_id}}" hx-get="{% url "reload-field" %}?form_class_path={{form_class_path}}&dynamic_field={{field_tuple.0}}" hx-target="#dynamic_field_{{field_tuple.0}}">
|
||||
<input type="text" name="dynamic_initial" data-dynamic-field="{{field_tuple.0}}">
|
||||
<input type="text" name="view_id" value="{{view_id}}">
|
||||
<button class="reload-field" data-target="{{field_tuple.0}}">
|
||||
{{field_tuple.0}}
|
||||
</button>
|
||||
</form>
|
||||
<script class="dynamic_{{field_tuple.0}}_scripts">
|
||||
$("#{{view_id}}Form [name={{field_tuple.0}}]").change(function (e) {
|
||||
values = $(this).val();
|
||||
if (!values) {
|
||||
values = ""
|
||||
}
|
||||
if (values == "dynamic_create") {
|
||||
$("#modalButton{{field_tuple.0}}").click()
|
||||
$(this).val("")
|
||||
}else if (values.includes("dynamic_create")) {
|
||||
let index = values.indexOf("dynamic_create");
|
||||
values.splice(index, 1);
|
||||
$(this).val(values).change();
|
||||
$("#modalButton{{field_tuple.0}}").parent().find('input[name=dynamic_initial]').val(values)
|
||||
$("#reload-field{{field_tuple.0}}{{view_id}}").find('input[name=dynamic_initial]').val(values)
|
||||
$("#modalButton{{field_tuple.0}}").click()
|
||||
}else if(values) {
|
||||
$("#modalButton{{field_tuple.0}}").parent().find('input[name=dynamic_initial]').val(values)
|
||||
$("#reload-field{{field_tuple.0}}{{view_id}}").find('input[name=dynamic_initial]').val(values)
|
||||
}
|
||||
});
|
||||
$("#reload-field{{field_tuple.0}}{{view_id}}").submit(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).find("[name=dynamic_initial]").val();
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<form id="{{ view_id }}Form" hx-post="{{ request.path }}?{{ request.GET.urlencode }}" hx-target="#{{ hx_target }}"
|
||||
hx-swap="{% if hx_target == 'this' %}outerHTML{% else %}innerHTML{% endif %}" hx-encoding="multipart/form-data"
|
||||
{% if hx_confirm %} hx-confirm="{{ hx_confirm }}" {% endif %}>
|
||||
{{ form.structured }}
|
||||
</form>
|
||||
|
||||
{% for field_tuple in dynamic_create_fields %}
|
||||
<div>
|
||||
<script class="dynamic_{{ field_tuple.0 }}_scripts">
|
||||
{{ form.initial|get_item:field_tuple.0 }}
|
||||
$("#{{ view_id }}Form [name={{ field_tuple.0 }}]").val({{ form.initial|get_item:field_tuple.0|safe }}).change()
|
||||
</script>
|
||||
|
||||
<form hidden id="modalButton{{ field_tuple.0 }}Form"
|
||||
hx-get="/dynamic-path-{{ field_tuple.0 }}-{{ request.session.session_key }}?dynamic_field={{ field_tuple.0 }}"
|
||||
hx-target="#dynamicModal{{ field_tuple.0 }}Body">
|
||||
<input type="text" name="dynamic_initial" data-dynamic-field="{{ field_tuple.0 }}">
|
||||
<input type="text" name="view_id" value="{{ view_id }}">
|
||||
{% for field in field_tuple.2 %}
|
||||
<input type="text" name="{{ field }}">
|
||||
{% endfor %}
|
||||
<button type="submit" id="modalButton{{ field_tuple.0 }}"
|
||||
onclick="$('#dynamicModal{{ field_tuple.0 }}').addClass('oh-modal--show');">
|
||||
{{ field_tuple.0 }}
|
||||
</button>
|
||||
</form>
|
||||
<form hidden id="reload-field{{ field_tuple.0 }}{{ view_id }}"
|
||||
hx-get="{% url 'reload-field' %}?form_class_path={{ form_class_path }}&dynamic_field={{ field_tuple.0 }}"
|
||||
hx-target="#dynamic_field_{{ field_tuple.0 }}">
|
||||
<input type="text" name="dynamic_initial" data-dynamic-field="{{ field_tuple.0 }}">
|
||||
<input type="text" name="view_id" value="{{ view_id }}">
|
||||
<button class="reload-field" data-target="{{ field_tuple.0 }}">
|
||||
{{ field_tuple.0 }}
|
||||
</button>
|
||||
</form>
|
||||
<script class="dynamic_{{ field_tuple.0 }}_scripts">
|
||||
$("#{{ view_id }}Form [name={{ field_tuple.0 }}]").change(function (e) {
|
||||
values = $(this).val();
|
||||
if (!values) {
|
||||
values = ""
|
||||
}
|
||||
if (values == "dynamic_create") {
|
||||
$("#modalButton{{ field_tuple.0 }}").click()
|
||||
$(this).val("")
|
||||
} else if (values.includes("dynamic_create")) {
|
||||
let index = values.indexOf("dynamic_create");
|
||||
values.splice(index, 1);
|
||||
$(this).val(values).change();
|
||||
$("#modalButton{{ field_tuple.0 }}").parent().find('input[name=dynamic_initial]').val(values)
|
||||
$("#reload-field{{ field_tuple.0 }}{{ view_id }}").find('input[name=dynamic_initial]').val(values)
|
||||
$("#modalButton{{ field_tuple.0 }}").click()
|
||||
} else if (values) {
|
||||
$("#modalButton{{ field_tuple.0 }}").parent().find('input[name=dynamic_initial]').val(values)
|
||||
$("#reload-field{{ field_tuple.0 }}{{ view_id }}").find('input[name=dynamic_initial]').val(values)
|
||||
}
|
||||
});
|
||||
$("#reload-field{{ field_tuple.0 }}{{ view_id }}").submit(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).find("[name=dynamic_initial]").val();
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
<div id="questionTemplateList">
|
||||
{% include "generic/horilla_list.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -750,5 +750,3 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
document.body.addEventListener("htmx:afterSettle", function (event) {
|
||||
initCountryStateDropdowns();
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user