From 1ebff9fc45560c27a98051a2e644b5b5d7f98f52 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 23 Aug 2024 10:45:32 -0400 Subject: [PATCH 01/23] some incremental changes --- src/registrar/admin.py | 47 ++++++++++++++++--- .../templates/admin/stacked_no_heading.html | 42 +++++++++++++++++ .../includes/domain_info_inline_stacked.html | 2 +- 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 src/registrar/templates/admin/stacked_no_heading.html diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 3ad5e3ea0..5b55eee12 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -2272,6 +2272,17 @@ class DomainInformationInline(admin.StackedInline): analyst_readonly_fields = DomainInformationAdmin.analyst_readonly_fields autocomplete_fields = DomainInformationAdmin.autocomplete_fields + # Removing specific fields from the first fieldset dynamically + fieldsets[0][1]["fields"] = [ + field for field in fieldsets[0][1]["fields"] if field not in ["creator", "submitter", "domain_request", "notes"] + ] + fieldsets[2][1]["fields"] = [ + field for field in fieldsets[2][1]["fields"] if field not in ["other_contacts", "no_other_contacts_rationale"] + ] + fieldsets[3][1]["fields"].extend(["other_contacts", "no_other_contacts_rationale"]) # type: ignore + fieldsets_to_move = fieldsets.pop(3) + fieldsets.append(fieldsets_to_move) + def has_change_permission(self, request, obj=None): """Custom has_change_permission override so that we can specify that analysts can edit this through this inline, but not through the model normally""" @@ -2382,14 +2393,11 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin): fieldsets = ( ( - None, - {"fields": ["name", "state", "expiration_date", "first_ready", "deleted"]}, + "Domain Information", + {"fields": ["state", "expiration_date", "first_ready", "deleted", "dnssecdata", "nameservers"]}, ), ) - # this ordering effects the ordering of results in autocomplete_fields for domain - ordering = ["name"] - def generic_org_type(self, obj): return obj.domain_info.get_generic_org_type_display() @@ -2410,6 +2418,25 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin): organization_name.admin_order_field = "domain_info__organization_name" # type: ignore + def dnssecdata(self, obj): + return "Yes" if obj.dnssecdata else "No" + + dnssecdata.short_description = "DNS Sec Enabled" # type: ignore + + # Custom method to display formatted nameservers + def nameservers(self, obj): + if not obj.nameservers: + return "No nameservers" + + formatted_nameservers = [] + for server, ip_list in obj.nameservers: + formatted_nameservers.append(f"{server} [{', '.join(ip_list)}]") + + # Join the formatted strings with line breaks + return "\n".join(formatted_nameservers) + + nameservers.short_description = "Nameservers" # type: ignore + def custom_election_board(self, obj): domain_info = getattr(obj, "domain_info", None) if domain_info: @@ -2436,7 +2463,15 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin): search_fields = ["name"] search_help_text = "Search by domain name." change_form_template = "django/admin/domain_change_form.html" - readonly_fields = ("state", "expiration_date", "first_ready", "deleted", "federal_agency") + readonly_fields = ( + "state", + "expiration_date", + "first_ready", + "deleted", + "federal_agency", + "dnssecdata", + "nameservers", + ) # Table ordering ordering = ["name"] diff --git a/src/registrar/templates/admin/stacked_no_heading.html b/src/registrar/templates/admin/stacked_no_heading.html new file mode 100644 index 000000000..60e37d757 --- /dev/null +++ b/src/registrar/templates/admin/stacked_no_heading.html @@ -0,0 +1,42 @@ +{% load i18n admin_urls %} +{% load i18n static %} + +{% comment %} +This is copied from Djangos implementation of this template, with added "blocks" +It is not inherently customizable on its own, so we can modify this instead. +https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/edit_inline/stacked.html +{% endcomment %} + +
+ +
+ {{ inline_admin_formset.formset.management_form }} + {{ inline_admin_formset.formset.non_form_errors }} + + {% for inline_admin_form in inline_admin_formset %}
+ {% if inline_admin_form.form.non_field_errors %} + {{ inline_admin_form.form.non_field_errors }} + {% endif %} + + {% for fieldset in inline_admin_form %} + {# .gov override #} + {% block fieldset %} + {% include "admin/includes/fieldset.html" %} + {% endblock fieldset%} + {# End of .gov override #} + {% endfor %} + + {% if inline_admin_form.needs_explicit_pk_field %} + {{ inline_admin_form.pk_field.field }} + {% endif %} + {% if inline_admin_form.fk_field %} + {{ inline_admin_form.fk_field.field }} + {% endif %} +
+ {% endfor %} +
+ +
diff --git a/src/registrar/templates/django/admin/includes/domain_info_inline_stacked.html b/src/registrar/templates/django/admin/includes/domain_info_inline_stacked.html index 414c485e5..9638bb7cb 100644 --- a/src/registrar/templates/django/admin/includes/domain_info_inline_stacked.html +++ b/src/registrar/templates/django/admin/includes/domain_info_inline_stacked.html @@ -1,4 +1,4 @@ -{% extends 'admin/stacked.html' %} +{% extends 'admin/stacked_no_heading.html' %} {% load i18n static %} {% block fieldset %} From 7265df122967b878557be77253d2e5d9990d3fe7 Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Fri, 30 Aug 2024 14:48:05 -0400 Subject: [PATCH 02/23] wip --- src/registrar/assets/js/get-gov-admin.js | 213 ++++++------------ .../admin/includes/detail_table_fieldset.html | 197 +++++++--------- 2 files changed, 152 insertions(+), 258 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 24f020b75..ffb65df27 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -506,72 +506,60 @@ function initializeWidgetOnList(list, parentId) { /** An IIFE that hooks to the show/hide button underneath action needed reason. * This shows the auto generated email on action needed reason. */ -(function () { - // Since this is an iife, these vars will be removed from memory afterwards - var actionNeededReasonDropdown = document.querySelector("#id_action_needed_reason"); - - // Placeholder text (for certain "action needed" reasons that do not involve e=mails) - var placeholderText = document.querySelector("#action-needed-reason-email-placeholder-text") - - // E-mail divs and textarea components - var actionNeededEmail = document.querySelector("#id_action_needed_reason_email") - var actionNeededEmailReadonly = document.querySelector("#action-needed-reason-email-readonly") - var actionNeededEmailReadonlyTextarea = document.querySelector("#action-needed-reason-email-readonly-textarea") - - // Edit e-mail modal (and its confirmation button) - var actionNeededEmailAlreadySentModal = document.querySelector("#email-already-sent-modal") - var confirmEditEmailButton = document.querySelector("#email-already-sent-modal_continue-editing-button") - - // Headers and footers (which change depending on if the e-mail was sent or not) - var actionNeededEmailHeader = document.querySelector("#action-needed-email-header") - var actionNeededEmailHeaderOnSave = document.querySelector("#action-needed-email-header-email-sent") - var actionNeededEmailFooter = document.querySelector("#action-needed-email-footer") - - let emailWasSent = document.getElementById("action-needed-email-sent"); - let lastSentEmailText = document.getElementById("action-needed-email-last-sent-text"); - - // Get the list of e-mails associated with each action-needed dropdown value - let emailData = document.getElementById('action-needed-emails-data'); - if (!emailData) { - return; - } - let actionNeededEmailData = emailData.textContent; - if(!actionNeededEmailData) { - return; - } - let actionNeededEmailsJson = JSON.parse(actionNeededEmailData); - +document.addEventListener('DOMContentLoaded', function() { + let actionNeededReasonDropdown = document.querySelector("#id_action_needed_reason"); + let textAreaActionNeededEmail = document.getElementById("id_action_needed_reason_email") const domainRequestId = actionNeededReasonDropdown ? document.querySelector("#domain_request_id").value : null - const emailSentSessionVariableName = `actionNeededEmailSent-${domainRequestId}`; - const oldDropdownValue = actionNeededReasonDropdown ? actionNeededReasonDropdown.value : null; - const oldEmailValue = actionNeededEmailData ? actionNeededEmailData.value : null; - if(actionNeededReasonDropdown && actionNeededEmail && domainRequestId) { - // Add a change listener to dom load - document.addEventListener('DOMContentLoaded', function() { - let reason = actionNeededReasonDropdown.value; + // Check we are on the right page and we have the right DOM elements + if(actionNeededReasonDropdown && textAreaActionNeededEmail && domainRequestId) { - // Handle the session boolean (to enable/disable editing) - if (emailWasSent && emailWasSent.value === "True") { - // An email was sent out - store that information in a session variable - addOrRemoveSessionBoolean(emailSentSessionVariableName, add=true); + var pleaseMakeASelection = document.getElementById("please-make-selection") + var noEmailWillBeSent = document.getElementById("no-email-will-be-sent") + var editEmailButton = document.getElementById('email-already-sent-modal_continue-editing-button'); + // Headers and footers (which change depending on if the email was sent or not) + // var actionNeededEmailHeader = document.querySelector("#action-needed-email-header") + // var actionNeededEmailHeaderOnSave = document.querySelector("#action-needed-email-header-email-sent") + let lastEmailSentInputStorer = document.getElementById("action-needed-email-sent"); + if (!lastEmailSentInputStorer) { + return; + } + let anEmailWasSent = lastEmailSentInputStorer.value == 'True'; + let lastEmailSentContent = document.getElementById("action-needed-email-sent-last-content"); + + // Get the list of emails associated with each action-needed dropdown value + let emailData = document.getElementById('action-needed-emails-data'); + if (!emailData) { + return; + } + let actionNeededEmailData = emailData.textContent; + if(!actionNeededEmailData) { + return; + } + let actionNeededEmailsJson = JSON.parse(actionNeededEmailData); + + const emailSentSessionVariableName = `actionNeededEmailSent-${domainRequestId}`; + const initialDropdownValue = actionNeededReasonDropdown ? actionNeededReasonDropdown.value : null; + const initialEmailValue = actionNeededEmailData ? actionNeededEmailData.value : null; + + function updateUserInterface(reason) { + if (!reason) { + showElement(pleaseMakeASelection); + hideElement(noEmailWillBeSent); + hideElement(textAreaActionNeededEmail); + } else if (reason == 'other') { + hideElement(pleaseMakeASelection); + showElement(noEmailWillBeSent); + hideElement(textAreaActionNeededEmail); + } else { + hideElement(pleaseMakeASelection); + hideElement(noEmailWillBeSent); + showElement(textAreaActionNeededEmail); } - - // Show an editable email field or a readonly one - updateActionNeededEmailDisplay(reason) - }); - - editEmailButton.addEventListener("click", function() { - if (!checkEmailAlreadySent()) { - showEmail(canEdit=true) - } - }); - - confirmEditEmailButton.addEventListener("click", function() { - // Show editable view - showEmail(canEdit=true) - }); + } + // Init the UI + updateUserInterface(actionNeededReasonDropdown.value); // Add a change listener to the action needed reason dropdown actionNeededReasonDropdown.addEventListener("change", function() { @@ -579,95 +567,34 @@ function initializeWidgetOnList(list, parentId) { let emailBody = reason in actionNeededEmailsJson ? actionNeededEmailsJson[reason] : null; if (reason && emailBody) { - // Reset the session object on change since change refreshes the email content. - if (oldDropdownValue !== actionNeededReasonDropdown.value || oldEmailValue !== actionNeededEmail.value) { + // If it's not the initial value + if (initialDropdownValue !== actionNeededReasonDropdown.value || initialEmailValue !== textAreaActionNeededEmail.value) { // Replace the email content - actionNeededEmail.value = emailBody; - actionNeededEmailReadonlyTextarea.value = emailBody; - hideEmailAlreadySentView(); + textAreaActionNeededEmail.value = emailBody; } } - // Show either a preview of the email or some text describing no email will be sent - updateActionNeededEmailDisplay(reason) + // Update the UI + updateUserInterface(reason); }); + + // Handle the session boolean (to enable/disable editing) + // An email was sent out - store that information in a session variable + if (anEmailWasSent) + addOrRemoveSessionBoolean(emailSentSessionVariableName, add=true); + + // editEmailButton.addEventListener("click", function() { + // if (!checkEmailAlreadySent()) { + // } + // } } - function checkEmailAlreadySent() - { - lastEmailSent = lastSentEmailText.value.replace(/\s+/g, '') - currentEmailInTextArea = actionNeededEmail.value.replace(/\s+/g, '') - return lastEmailSent === currentEmailInTextArea - } - - // Shows a readonly preview of the email with updated messaging to indicate this email was sent - function showEmailAlreadySentView() - { - hideElement(actionNeededEmailHeader) - showElement(actionNeededEmailHeaderOnSave) - actionNeededEmailFooter.innerHTML = "This email has been sent to the creator of this request"; - } - - // Shows a readonly preview of the email with updated messaging to indicate this email was sent - function hideEmailAlreadySentView() - { - showElement(actionNeededEmailHeader) - hideElement(actionNeededEmailHeaderOnSave) - actionNeededEmailFooter.innerHTML = "This email will be sent to the creator of this request after saving"; - } - - // Shows either a preview of the email or some text describing no email will be sent. - // If the email doesn't exist or if we're of reason "other", display that no email was sent. - function updateActionNeededEmailDisplay(reason) { - hideElement(actionNeededEmail.parentElement) - - if (reason) { - if (reason === "other") { - // Hide email preview and show this text instead - showPlaceholderText("No email will be sent"); - } - else { - // Always show readonly view of email to start - showEmail(canEdit=false) - if(checkEmailAlreadySent()) - { - showEmailAlreadySentView(); - } - } - } else { - // Hide email preview and show this text instead - showPlaceholderText("Select an action needed reason to see email"); - } - } - - // Shows either a readonly view (canEdit=false) or editable view (canEdit=true) of the action needed email - function showEmail(canEdit) - { - if(!canEdit) - { - showElement(actionNeededEmailReadonly) - hideElement(actionNeededEmail.parentElement) - } - else - { - hideElement(actionNeededEmailReadonly) - showElement(actionNeededEmail.parentElement) - } - showElement(actionNeededEmailFooter) // this is the same for both views, so it was separated out - hideElement(placeholderText) - } - - // Hides preview of action needed email and instead displays the given text (innerHTML) - function showPlaceholderText(innerHTML) - { - hideElement(actionNeededEmail.parentElement) - hideElement(actionNeededEmailReadonly) - hideElement(actionNeededEmailFooter) - - placeholderText.innerHTML = innerHTML; - showElement(placeholderText) - } -})(); + // function checkEmailAlreadySent() { + // lastEmailSent = lastEmailSentContent.value.replace(/\s+/g, '') + // currentEmailInTextArea = textAreaActionNeededEmail.value.replace(/\s+/g, '') + // return lastEmailSent === currentEmailInTextArea + // } +}); /** An IIFE for copy summary button (appears in DomainRegistry models) diff --git a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html index 3b4047d39..a7cf415e6 100644 --- a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html +++ b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html @@ -66,24 +66,6 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) No changelog to display. {% endif %} - {% elif field.field.name == "action_needed_reason_email" %} -
- - -
{% elif field.field.name == "other_contacts" %} {% if all_contacts.count > 2 %}
@@ -145,111 +127,89 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {% block field_other %} {% if field.field.name == "action_needed_reason_email" %} -
-
- - + + -
-