Merge branch 'main' into za/2332-display-action-needed-text

This commit is contained in:
zandercymatics 2024-06-21 13:35:26 -06:00
commit 38f6a1b87a
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
4 changed files with 118 additions and 39 deletions

View file

@ -1234,7 +1234,7 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin):
search_help_text = "Search by domain." search_help_text = "Search by domain."
fieldsets = [ fieldsets = [
(None, {"fields": ["creator", "submitter", "domain_request", "notes"]}), (None, {"fields": ["portfolio", "creator", "submitter", "domain_request", "notes"]}),
(".gov domain", {"fields": ["domain"]}), (".gov domain", {"fields": ["domain"]}),
("Contacts", {"fields": ["authorizing_official", "other_contacts", "no_other_contacts_rationale"]}), ("Contacts", {"fields": ["authorizing_official", "other_contacts", "no_other_contacts_rationale"]}),
("Background info", {"fields": ["anything_else"]}), ("Background info", {"fields": ["anything_else"]}),
@ -1320,6 +1320,32 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin):
change_form_template = "django/admin/domain_information_change_form.html" change_form_template = "django/admin/domain_information_change_form.html"
superuser_only_fields = [
"portfolio",
]
# DEVELOPER's NOTE:
# Normally, to exclude a field from an Admin form, we could simply utilize
# Django's "exclude" feature. However, it causes a "missing key" error if we
# go that route for this particular form. The error gets thrown by our
# custom fieldset.html code and is due to the fact that "exclude" removes
# fields from base_fields but not fieldsets. Rather than reworking our
# custom frontend, it seems more straightforward (and easier to read) to simply
# modify the fieldsets list so that it excludes any fields we want to remove
# based on permissions (eg. superuser_only_fields) or other conditions.
def get_fieldsets(self, request, obj=None):
fieldsets = self.fieldsets
# Create a modified version of fieldsets to exclude certain fields
if not request.user.has_perm("registrar.full_access_permission"):
modified_fieldsets = []
for name, data in fieldsets:
fields = data.get("fields", [])
fields = tuple(field for field in fields if field not in DomainInformationAdmin.superuser_only_fields)
modified_fieldsets.append((name, {"fields": fields}))
return modified_fieldsets
return fieldsets
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
"""Set the read-only state on form elements. """Set the read-only state on form elements.
We have 1 conditions that determine which fields are read-only: We have 1 conditions that determine which fields are read-only:
@ -1483,6 +1509,7 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
None, None,
{ {
"fields": [ "fields": [
"portfolio",
"status", "status",
"rejection_reason", "rejection_reason",
"action_needed_reason", "action_needed_reason",
@ -1593,6 +1620,32 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
] ]
filter_horizontal = ("current_websites", "alternative_domains", "other_contacts") filter_horizontal = ("current_websites", "alternative_domains", "other_contacts")
superuser_only_fields = [
"portfolio",
]
# DEVELOPER's NOTE:
# Normally, to exclude a field from an Admin form, we could simply utilize
# Django's "exclude" feature. However, it causes a "missing key" error if we
# go that route for this particular form. The error gets thrown by our
# custom fieldset.html code and is due to the fact that "exclude" removes
# fields from base_fields but not fieldsets. Rather than reworking our
# custom frontend, it seems more straightforward (and easier to read) to simply
# modify the fieldsets list so that it excludes any fields we want to remove
# based on permissions (eg. superuser_only_fields) or other conditions.
def get_fieldsets(self, request, obj=None):
fieldsets = super().get_fieldsets(request, obj)
# Create a modified version of fieldsets to exclude certain fields
if not request.user.has_perm("registrar.full_access_permission"):
modified_fieldsets = []
for name, data in fieldsets:
fields = data.get("fields", [])
fields = tuple(field for field in fields if field not in self.superuser_only_fields)
modified_fieldsets.append((name, {"fields": fields}))
return modified_fieldsets
return fieldsets
# Table ordering # Table ordering
# NOTE: This impacts the select2 dropdowns (combobox) # NOTE: This impacts the select2 dropdowns (combobox)
# Currentl, there's only one for requests on DomainInfo # Currentl, there's only one for requests on DomainInfo
@ -1980,13 +2033,7 @@ class DomainInformationInline(admin.StackedInline):
template = "django/admin/includes/domain_info_inline_stacked.html" template = "django/admin/includes/domain_info_inline_stacked.html"
model = models.DomainInformation model = models.DomainInformation
fieldsets = copy.deepcopy(DomainInformationAdmin.fieldsets) fieldsets = DomainInformationAdmin.fieldsets
# remove .gov domain from fieldset
for index, (title, f) in enumerate(fieldsets):
if title == ".gov domain":
del fieldsets[index]
break
readonly_fields = DomainInformationAdmin.readonly_fields readonly_fields = DomainInformationAdmin.readonly_fields
analyst_readonly_fields = DomainInformationAdmin.analyst_readonly_fields analyst_readonly_fields = DomainInformationAdmin.analyst_readonly_fields
@ -2033,6 +2080,23 @@ class DomainInformationInline(admin.StackedInline):
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
return DomainInformationAdmin.get_readonly_fields(self, request, obj=None) return DomainInformationAdmin.get_readonly_fields(self, request, obj=None)
# Re-route the get_fieldsets method to utilize DomainInformationAdmin.get_fieldsets
# since that has all the logic for excluding certain fields according to user permissions.
# Then modify the remaining fields to further trim out any we don't want for this inline
# form
def get_fieldsets(self, request, obj=None):
# Grab fieldsets from DomainInformationAdmin so that it handles all logic
# for permission-based field visibility.
modified_fieldsets = DomainInformationAdmin.get_fieldsets(self, request, obj=None)
# remove .gov domain from fieldset
for index, (title, f) in enumerate(modified_fieldsets):
if title == ".gov domain":
del modified_fieldsets[index]
break
return modified_fieldsets
class DomainResource(FsmModelResource): class DomainResource(FsmModelResource):
"""defines how each field in the referenced model should be mapped to the corresponding fields in the """defines how each field in the referenced model should be mapped to the corresponding fields in the

View file

@ -33,6 +33,33 @@ const showElement = (element) => {
element.classList.remove('display-none'); element.classList.remove('display-none');
}; };
/**
* Helper function that scrolls to an element
* @param {string} attributeName - The string "class" or "id"
* @param {string} attributeValue - The class or id name
*/
function ScrollToElement(attributeName, attributeValue) {
let targetEl = null;
if (attributeName === 'class') {
targetEl = document.getElementsByClassName(attributeValue)[0];
} else if (attributeName === 'id') {
targetEl = document.getElementById(attributeValue);
} else {
console.log('Error: unknown attribute name provided.');
return; // Exit the function if an invalid attributeName is provided
}
if (targetEl) {
const rect = targetEl.getBoundingClientRect();
const scrollTop = window.scrollY || document.documentElement.scrollTop;
window.scrollTo({
top: rect.top + scrollTop,
behavior: 'smooth' // Optional: for smooth scrolling
});
}
}
/** Makes an element invisible. */ /** Makes an element invisible. */
function makeHidden(el) { function makeHidden(el) {
el.style.position = "absolute"; el.style.position = "absolute";
@ -895,33 +922,6 @@ function unloadModals() {
window.modal.off(); window.modal.off();
} }
/**
* Helper function that scrolls to an element
* @param {string} attributeName - The string "class" or "id"
* @param {string} attributeValue - The class or id name
*/
function ScrollToElement(attributeName, attributeValue) {
let targetEl = null;
if (attributeName === 'class') {
targetEl = document.getElementsByClassName(attributeValue)[0];
} else if (attributeName === 'id') {
targetEl = document.getElementById(attributeValue);
} else {
console.log('Error: unknown attribute name provided.');
return; // Exit the function if an invalid attributeName is provided
}
if (targetEl) {
const rect = targetEl.getBoundingClientRect();
const scrollTop = window.scrollY || document.documentElement.scrollTop;
window.scrollTo({
top: rect.top + scrollTop,
behavior: 'smooth' // Optional: for smooth scrolling
});
}
}
/** /**
* Generalized function to update pagination for a list. * Generalized function to update pagination for a list.
* @param {string} itemName - The name displayed in the counter * @param {string} itemName - The name displayed in the counter
@ -1294,6 +1294,10 @@ document.addEventListener('DOMContentLoaded', function() {
* @param {*} pageToDisplay - If we're deleting the last item on a page that is not page 1, we'll need to display the previous page * @param {*} pageToDisplay - If we're deleting the last item on a page that is not page 1, we'll need to display the previous page
*/ */
function deleteDomainRequest(domainRequestPk,pageToDisplay) { function deleteDomainRequest(domainRequestPk,pageToDisplay) {
// Use to debug uswds modal issues
//console.log('deleteDomainRequest')
// Get csrf token // Get csrf token
const csrfToken = getCsrfToken(); const csrfToken = getCsrfToken();
// Create FormData object and append the CSRF token // Create FormData object and append the CSRF token
@ -1348,6 +1352,14 @@ document.addEventListener('DOMContentLoaded', function() {
const tbody = document.querySelector('.domain-requests__table tbody'); const tbody = document.querySelector('.domain-requests__table tbody');
tbody.innerHTML = ''; tbody.innerHTML = '';
// Unload modals will re-inject the DOM with the initial placeholders to allow for .on() in regular use cases
// We do NOT want that as it will cause multiple placeholders and therefore multiple inits on delete,
// which will cause bad delete requests to be sent.
const preExistingModalPlaceholders = document.querySelectorAll('[data-placeholder-for^="toggle-delete-domain-alert"]');
preExistingModalPlaceholders.forEach(element => {
element.remove();
});
// remove any existing modal elements from the DOM so they can be properly re-initialized // remove any existing modal elements from the DOM so they can be properly re-initialized
// after the DOM content changes and there are new delete modal buttons added // after the DOM content changes and there are new delete modal buttons added
unloadModals(); unloadModals();
@ -1469,7 +1481,7 @@ document.addEventListener('DOMContentLoaded', function() {
</svg> </svg>
</button> </button>
</div> </div>
` `
domainRequestsSectionWrapper.appendChild(modal); domainRequestsSectionWrapper.appendChild(modal);
} }

View file

@ -97,3 +97,6 @@ class Portfolio(TimeStampedModel):
verbose_name="security contact e-mail", verbose_name="security contact e-mail",
max_length=320, max_length=320,
) )
def __str__(self) -> str:
return f"{self.organization_name}"

View file

@ -16,7 +16,7 @@
</legend> </legend>
<!-- Toggle --> <!-- Toggle -->
<em>Select one (<abbr class="usa-hint usa-hint--required" title="required">*</abbr>).</em> <em>Select one. <abbr class="usa-hint usa-hint--required" title="required">*</abbr></em>
{% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %}
{% input_with_errors forms.0.has_cisa_representative %} {% input_with_errors forms.0.has_cisa_representative %}
{% endwith %} {% endwith %}
@ -36,7 +36,7 @@
</legend> </legend>
<!-- Toggle --> <!-- Toggle -->
<em>Select one (<abbr class="usa-hint usa-hint--required" title="required">*</abbr>).</em> <em>Select one. <abbr class="usa-hint usa-hint--required" title="required">*</abbr></em>
{% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %}
{% input_with_errors forms.2.has_anything_else_text %} {% input_with_errors forms.2.has_anything_else_text %}
{% endwith %} {% endwith %}
@ -44,7 +44,7 @@
</fieldset> </fieldset>
<div class="margin-top-3" id="anything-else"> <div class="margin-top-3" id="anything-else">
<p>Provide details below (<abbr class="usa-hint usa-hint--required" title="required">*</abbr>).</p> <p>Provide details below. <abbr class="usa-hint usa-hint--required" title="required">*</abbr></p>
{% with attr_maxlength=2000 add_label_class="usa-sr-only" %} {% with attr_maxlength=2000 add_label_class="usa-sr-only" %}
{% input_with_errors forms.3.anything_else %} {% input_with_errors forms.3.anything_else %}
{% endwith %} {% endwith %}