From 4cd7a96b6332eb4aa57ba4bcf09efe19d9cf46ee Mon Sep 17 00:00:00 2001 From: Horilla Date: Wed, 13 Aug 2025 16:34:22 +0530 Subject: [PATCH] [UPDT] HORILLA AUTOMATIONS: Optimize form submit handler for #{{view_id}}Form: --- horilla_automations/apps.py | 80 ++-- horilla_automations/forms.py | 17 +- .../static/automation/automation.js | 398 +++++++++--------- .../horilla_automations/automation_form.html | 23 +- 4 files changed, 259 insertions(+), 259 deletions(-) diff --git a/horilla_automations/apps.py b/horilla_automations/apps.py index ab9130e81..ab760462b 100644 --- a/horilla_automations/apps.py +++ b/horilla_automations/apps.py @@ -1,56 +1,50 @@ -from django.apps import AppConfig +""" +App configuration for the Horilla Automations app. +Initializes model choices and starts automation when the server runs. +""" -from horilla_automations.signals import start_automation +import os +import sys + +from django.apps import AppConfig class HorillaAutomationConfig(AppConfig): + """Configuration class for the Horilla Automations Django app.""" + default_auto_field = "django.db.models.BigAutoField" name = "horilla_automations" - def ready(self) -> None: - ready = super().ready() - try: + def ready(self): + """Run initialization tasks when the app is ready.""" + from base.templatetags.horillafilters import app_installed + from employee.models import Employee + from horilla_automations.methods.methods import get_related_models + from horilla_automations.models import MODEL_CHOICES as model_choices - from base.templatetags.horillafilters import app_installed - from employee.models import Employee - from horilla_automations.methods.methods import get_related_models - from horilla_automations.models import MODEL_CHOICES + # Build MODEL_CHOICES + models = [Employee] + if app_installed("recruitment"): + from recruitment.models import Candidate - recruitment_installed = False - if app_installed("recruitment"): - recruitment_installed = True + models.append(Candidate) - models = [Employee] - if recruitment_installed: - from recruitment.models import Candidate + for main_model in models: + for model in get_related_models(main_model): + model_choices.append( + (f"{model.__module__}.{model.__name__}", model.__name__) + ) - models.append(Candidate) + model_choices.append(("employee.models.Employee", "Employee")) + model_choices.append(("pms.models.EmployeeKeyResult", "Employee Key Results")) + model_choices[:] = list(set(model_choices)) # Update in-place - main_models = models - for main_model in main_models: - related_models = get_related_models(main_model) + # Only start automation when running the server + if ( + len(sys.argv) >= 2 + and sys.argv[1] == "runserver" + and os.environ.get("RUN_MAIN") == "true" + ): + from horilla_automations.signals import start_automation - for model in related_models: - path = f"{model.__module__}.{model.__name__}" - MODEL_CHOICES.append((path, model.__name__)) - MODEL_CHOICES.append(("employee.models.Employee", "Employee")) - MODEL_CHOICES.append( - ("pms.models.EmployeeKeyResult", "Employee Key Results"), - ) - MODEL_CHOICES.append( - ("pms.models.Comment", "Key Result Comment"), - ) - - MODEL_CHOICES = list(set(MODEL_CHOICES)) - try: - start_automation() - except Exception as e: - print(e) - """ - Migrations are not affected yet - """ - except: - """ - Models not ready yet - """ - return ready + start_automation() diff --git a/horilla_automations/forms.py b/horilla_automations/forms.py index 60eb90476..f7ed7790c 100644 --- a/horilla_automations/forms.py +++ b/horilla_automations/forms.py @@ -84,13 +84,16 @@ class AutomationForm(ModelForm): # --- Field: mail_template --- self.fields["mail_template"].empty_label = "----------" - # --- 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 - ) + # --- Field: condition fields --- + self.fields["condition"].initial = getattr( + self.instance, "condition", None + ) or self.data.get("condition") + self.fields["condition_html"].initial = getattr( + self.instance, "condition_html", None + ) or self.data.get("condition_html") + self.fields["condition_querystring"].initial = getattr( + self.instance, "condition", None + ) or self.data.get("condition_html") # --- Apply option template name for all select fields --- for field in self.fields.values(): diff --git a/horilla_automations/static/automation/automation.js b/horilla_automations/static/automation/automation.js index 2ca862799..c122883d2 100644 --- a/horilla_automations/static/automation/automation.js +++ b/horilla_automations/static/automation/automation.js @@ -1,48 +1,48 @@ function getToMail(element) { - model = element.val(); - $.ajax({ - type: "get", - url: "/get-to-mail-field", - data: { - model: model, - }, - success: function (response) { - $(".dynamic-condition-row").remove(); - select = $("#id_mail_to"); - select.html(""); - detailSelect = $("#id_mail_details"); - detailSelect.html(""); - mailTo = response.choices; - mailDetail = response.mail_details_choice; + model = element.val(); + $.ajax({ + type: "get", + url: "/get-to-mail-field", + data: { + model: model, + }, + success: function (response) { + $(".dynamic-condition-row").remove(); + select = $("#id_mail_to"); + select.html(""); + detailSelect = $("#id_mail_details"); + detailSelect.html(""); + mailTo = response.choices; + mailDetail = response.mail_details_choice; - for (let option = 0; option < mailTo.length; option++) { - const element = mailTo[option]; + for (let option = 0; option < mailTo.length; option++) { + const element = mailTo[option]; - var selected = option === 0; // Set the first option as selected - var newOption = new Option(element[1], element[0], selected, selected); - select.append(newOption); - } - for (let option = 0; option < mailDetail.length; option++) { - const element = mailDetail[option]; + var selected = option === 0; // Set the first option as selected + var newOption = new Option(element[1], element[0], selected, selected); + select.append(newOption); + } + for (let option = 0; option < mailDetail.length; option++) { + const element = mailDetail[option]; - var selected = option === 0; // Set the first option as selected - var newOption = new Option(element[1], element[0], selected, selected); - detailSelect.append(newOption); - } - select.trigger("change"); - detailSelect.trigger("change"); + var selected = option === 0; // Set the first option as selected + var newOption = new Option(element[1], element[0], selected, selected); + detailSelect.append(newOption); + } + select.trigger("change"); + detailSelect.trigger("change"); - table = $("#multipleConditionTable"); - $("#multipleConditionTable select").select2("destroy"); + table = $("#multipleConditionTable"); + $("#multipleConditionTable select").select2("destroy"); - totalRows = "C" + (table.find(".dynamic-condition-row").length + 1); + totalRows = "C" + (table.find(".dynamic-condition-row").length + 1); - fieldsChoices = []; - $.each(response.serialized_form, function (indexInArray, valueOfElement) { - fieldsChoices.push([valueOfElement["name"], valueOfElement["label"]]); - }); - selectField = populateSelect(fieldsChoices, response); - tr = ` + fieldsChoices = []; + $.each(response.serialized_form, function (indexInArray, valueOfElement) { + fieldsChoices.push([valueOfElement["name"], valueOfElement["label"]]); + }); + selectField = populateSelect(fieldsChoices, response); + tr = ` ${totalRows} @@ -92,17 +92,17 @@ function getToMail(element) { `; - table.find("tr:last").after(tr); - $("#conditionalField").append(selectField); - $("#multipleConditionTable select").select2(); - selectField.trigger("change"); - selectField.attr("name", "automation_multiple_condition"); - }, - }); + table.find("tr:last").after(tr); + $("#conditionalField").append(selectField); + $("#multipleConditionTable select").select2(); + selectField.trigger("change"); + selectField.attr("name", "automation_multiple_condition"); + }, + }); } function getHtml() { - var htmlCode = ` + var htmlCode = `
@@ -124,193 +124,191 @@ function getHtml() { $("#multipleConditionTable").closest("[contenteditable=true]").removeAttr("contenteditable"); `; - return $(htmlCode); + return $(htmlCode); } function populateSelect(data, response) { - const selectElement = $( - `` - ); + const selectElement = $( + `` + ); - data.forEach((item) => { - const $option = $(""); - $option.val(item[0]); - $option.text(item[1]); - selectElement.append($option); - }); - return selectElement; + data.forEach((item) => { + const $option = $(""); + $option.val(item[0]); + $option.text(item[1]); + selectElement.append($option); + }); + return selectElement; } function updateValue(element) { - console.log(">>>>>>>>>>>>>>>>>>>>>>") - json = element.closest('table').find('#conditionalField div[hidden]').text() - console.log(json) + json = element.closest('table').find('#conditionalField div[hidden]').text() - field = element.val(); - // attr = json - // .replace(/[\u0000-\u001F\u007F-\u009F]/g, "") - // .replace(/\\n/g, "\\\\n") - // .replace(/\\t/g, "\\\\t"); + field = element.val(); + // attr = json + // .replace(/[\u0000-\u001F\u007F-\u009F]/g, "") + // .replace(/\\n/g, "\\\\n") + // .replace(/\\t/g, "\\\\t"); - response = JSON.parse(json); + response = JSON.parse(json); - valueElement = createElement(field, response); - element.closest("tr").find(".condition-value-th").html(""); - element.closest("tr").find(".condition-value-th").html(valueElement); - if (valueElement.is("select")) { - valueElement.select2(); - } + valueElement = createElement(field, response); + element.closest("tr").find(".condition-value-th").html(""); + element.closest("tr").find(".condition-value-th").html(valueElement); + if (valueElement.is("select")) { + valueElement.select2(); + } } function createElement(field, serialized_form) { - let element; - fieldItem = {}; + let element; + fieldItem = {}; - $.each(serialized_form, function (indexInArray, valueOfElement) { - if (valueOfElement.name == field) { - fieldItem = valueOfElement; - } - }); - - switch (fieldItem.type) { - case "CheckboxInput": - element = document.createElement("input"); - element.type = "checkbox"; - element.checked = true; - element.onchange = function () { - if (this.checked) { - $(this).attr("checked", true); - $(this).val("on"); - } else { - $(this).attr("checked", false); - $(this).val("off"); + $.each(serialized_form, function (indexInArray, valueOfElement) { + if (valueOfElement.name == field) { + fieldItem = valueOfElement; } - }; - element.name = "automation_multiple_condition"; - element.className = "oh-switch__checkbox oh-switch__checkbox"; - // Create the wrapping div - const wrapperDiv = document.createElement("div"); - wrapperDiv.className = "oh-switch"; - wrapperDiv.style.width = "30px"; - // Append the checkbox input to the div - wrapperDiv.appendChild(element); - $(element).change(); - element = wrapperDiv; - break; + }); - case "Select": - case "SelectMultiple": - element = document.createElement("select"); - if (fieldItem.type === "SelectMultiple") { - element.multiple = true; - } - element.onchange = function (event) { - addSelectedAttr(event); - }; - fieldItem.options.forEach((optionValue) => { - if (optionValue.value) { - const option = document.createElement("option"); - option.value = optionValue.value; - option.textContent = optionValue.label; - element.appendChild(option); - } - }); - break; + switch (fieldItem.type) { + case "CheckboxInput": + element = document.createElement("input"); + element.type = "checkbox"; + element.checked = true; + element.onchange = function () { + if (this.checked) { + $(this).attr("checked", true); + $(this).val("on"); + } else { + $(this).attr("checked", false); + $(this).val("off"); + } + }; + element.name = "automation_multiple_condition"; + element.className = "oh-switch__checkbox oh-switch__checkbox"; + // Create the wrapping div + const wrapperDiv = document.createElement("div"); + wrapperDiv.className = "oh-switch"; + wrapperDiv.style.width = "30px"; + // Append the checkbox input to the div + wrapperDiv.appendChild(element); + $(element).change(); + element = wrapperDiv; + break; - case "Textarea": - element = document.createElement("textarea"); - element.style = ` + case "Select": + case "SelectMultiple": + element = document.createElement("select"); + if (fieldItem.type === "SelectMultiple") { + element.multiple = true; + } + element.onchange = function (event) { + addSelectedAttr(event); + }; + fieldItem.options.forEach((optionValue) => { + if (optionValue.value) { + const option = document.createElement("option"); + option.value = optionValue.value; + option.textContent = optionValue.label; + element.appendChild(option); + } + }); + break; + + case "Textarea": + element = document.createElement("textarea"); + element.style = ` height: 29px !important; margin-top: 5px; `; - element.className = "oh-input w-100"; - if (fieldItem.max_length) { - element.maxLength = fieldItem.max_length; - } - element.onchange = function (event) { - $(this).html($(this).val()); - }; - break; - case "TextInput": - element = document.createElement("input"); - element.type = "text"; - element.style = ` + element.className = "oh-input w-100"; + if (fieldItem.max_length) { + element.maxLength = fieldItem.max_length; + } + element.onchange = function (event) { + $(this).html($(this).val()); + }; + break; + case "TextInput": + element = document.createElement("input"); + element.type = "text"; + element.style = ` height: 30px !important; `; - element.className = "oh-input w-100"; - if (fieldItem.max_length) { - element.maxLength = fieldItem.max_length; - } - element.onchange = function (event) { - $(this).attr("value", $(this).val()); - }; - break; - case "EmailInput": - element = document.createElement("input"); - element.type = "email"; - element.style = ` + element.className = "oh-input w-100"; + if (fieldItem.max_length) { + element.maxLength = fieldItem.max_length; + } + element.onchange = function (event) { + $(this).attr("value", $(this).val()); + }; + break; + case "EmailInput": + element = document.createElement("input"); + element.type = "email"; + element.style = ` height: 30px !important; `; - element.className = "oh-input w-100"; - if (fieldItem.max_length) { - element.maxLength = fieldItem.max_length; - } - element.onchange = function (event) { - $(this).attr("value", $(this).val()); - }; - break; - case "NumberInput": - element = document.createElement("input"); - element.type = "number"; - element.style = ` + element.className = "oh-input w-100"; + if (fieldItem.max_length) { + element.maxLength = fieldItem.max_length; + } + element.onchange = function (event) { + $(this).attr("value", $(this).val()); + }; + break; + case "NumberInput": + element = document.createElement("input"); + element.type = "number"; + element.style = ` height: 30px !important; `; - element.className = "oh-input w-100"; - if (fieldItem.max_length) { - element.maxLength = fieldItem.max_length; - } - element.onchange = function (event) { - $(this).attr("value", $(this).val()); - }; - break; - default: - element = document.createElement("input"); - element.type = "text"; - element.style = ` + element.className = "oh-input w-100"; + if (fieldItem.max_length) { + element.maxLength = fieldItem.max_length; + } + element.onchange = function (event) { + $(this).attr("value", $(this).val()); + }; + break; + default: + element = document.createElement("input"); + element.type = "text"; + element.style = ` height: 30px !important; `; - element.className = "oh-input w-100"; - if (fieldItem.max_length) { - element.maxLength = fieldItem.max_length; - } - element.onchange = function (event) { - $(this).attr("value", $(this).val()); - }; - break; - } - if (element) { - element.name = "automation_multiple_condition"; - if (fieldItem.required) { - element.required = true; + element.className = "oh-input w-100"; + if (fieldItem.max_length) { + element.maxLength = fieldItem.max_length; + } + element.onchange = function (event) { + $(this).attr("value", $(this).val()); + }; + break; } + if (element) { + element.name = "automation_multiple_condition"; + if (fieldItem.required) { + element.required = true; + } - // Create label - const label = document.createElement("label"); - label.textContent = fieldItem.label; - label.htmlFor = "automation_multiple_condition"; + // Create label + const label = document.createElement("label"); + label.textContent = fieldItem.label; + label.htmlFor = "automation_multiple_condition"; - return $(element); - } + return $(element); + } } function addSelectedAttr(event) { - const options = Array.from(event.target.options); - options.forEach((option) => { - if (option.selected) { - option.setAttribute("selected", "selected"); - } else { - option.removeAttribute("selected"); - } - }); + const options = Array.from(event.target.options); + options.forEach((option) => { + if (option.selected) { + option.setAttribute("selected", "selected"); + } else { + option.removeAttribute("selected"); + } + }); } diff --git a/horilla_automations/templates/horilla_automations/automation_form.html b/horilla_automations/templates/horilla_automations/automation_form.html index 1efc4d5b7..8be05270b 100644 --- a/horilla_automations/templates/horilla_automations/automation_form.html +++ b/horilla_automations/templates/horilla_automations/automation_form.html @@ -8,16 +8,21 @@ $(this).closest('.oh-accordion').toggleClass('oh-accordion--show'); }); - $("#{{view_id}} form button").click(function (e) { - const form = document.getElementById('multipleConditionForm'); - const elements = form.elements; - const queryString = Array.from(elements) - .filter(element => element.name && !element.disabled) - .map(element => encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value)) + $(document).on('click', '#{{view_id}}Form button[type="submit"]', function () { + const $mainForm = $('#{{view_id}}Form'); + const conditionFormEl = $('#multipleConditionForm')[0]; + + if (!conditionFormEl) return; + + const queryString = Array.from(conditionFormEl.elements) + .filter(el => el.name && !el.disabled) + .map(el => encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value)) .join('&'); - $("#{{view_id}} form [name=condition_querystring]").val(queryString); - html = $(".note-editable #multipleConditionForm").html() - $("#{{view_id}} form [name=condition_html]").val(html); + + $mainForm.find('[name="condition_querystring"]').val(queryString); + + const html = $(".note-editable #multipleConditionForm").html(); + $mainForm.find('[name="condition_html"]').val(html); }); $("#dynamic_field_condition").parent().removeClass("col-md-6");