mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-17 10:07:04 +02:00
Merge branch 'main' into za/2332-display-action-needed-text
This commit is contained in:
commit
38f6a1b87a
4 changed files with 118 additions and 39 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue