mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-30 06:26:34 +02:00
updatePortfolioFieldsDataDynamicDisplay cleanup
This commit is contained in:
parent
4887a47796
commit
4e12b1295b
4 changed files with 35 additions and 135 deletions
|
@ -1735,7 +1735,7 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
return obj.portfolio.senior_official if obj.portfolio and obj.portfolio.senior_official else None
|
return obj.portfolio.senior_official if obj.portfolio and obj.portfolio.senior_official else None
|
||||||
portfolio_senior_official.short_description = "Senior official"
|
portfolio_senior_official.short_description = "Senior official"
|
||||||
def portfolio_organization_type(self, obj):
|
def portfolio_organization_type(self, obj):
|
||||||
return obj.portfolio.organization_type if obj.portfolio else ""
|
return DomainRequest.OrganizationChoices.get_org_label(obj.portfolio.organization_type) if obj.portfolio and obj.portfolio.organization_type else "-"
|
||||||
portfolio_organization_type.short_description = "Organization type"
|
portfolio_organization_type.short_description = "Organization type"
|
||||||
def portfolio_federal_type(self, obj):
|
def portfolio_federal_type(self, obj):
|
||||||
return BranchChoices.get_branch_label(obj.portfolio.federal_type) if obj.portfolio and obj.portfolio.federal_type else "-"
|
return BranchChoices.get_branch_label(obj.portfolio.federal_type) if obj.portfolio and obj.portfolio.federal_type else "-"
|
||||||
|
|
|
@ -86,6 +86,10 @@ function handleSuborganizationFields(
|
||||||
portfolioDropdown.on("change", toggleSuborganizationFields);
|
portfolioDropdown.on("change", toggleSuborganizationFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMPORTANT NOTE: The logic in this method is paired dynamicPortfolioFields
|
||||||
|
*/
|
||||||
function handlePortfolioSelection() {
|
function handlePortfolioSelection() {
|
||||||
// These dropdown are select2 fields so they must be interacted with via jquery
|
// These dropdown are select2 fields so they must be interacted with via jquery
|
||||||
const portfolioDropdown = django.jQuery("#id_portfolio");
|
const portfolioDropdown = django.jQuery("#id_portfolio");
|
||||||
|
@ -121,6 +125,7 @@ function handlePortfolioSelection() {
|
||||||
const portfolioUrbanizationField = document.querySelector(".field-portfolio_urbanization");
|
const portfolioUrbanizationField = document.querySelector(".field-portfolio_urbanization");
|
||||||
const portfolioUrbanization = portfolioUrbanizationField.querySelector(".readonly");
|
const portfolioUrbanization = portfolioUrbanizationField.querySelector(".readonly");
|
||||||
const portfolioJsonUrl = document.getElementById("portfolio_json_url")?.value || null;
|
const portfolioJsonUrl = document.getElementById("portfolio_json_url")?.value || null;
|
||||||
|
const seniorOfficialAddress = portfolioSeniorOfficialField.querySelector(".dja-address-contact-list");
|
||||||
let isPageLoading = true;
|
let isPageLoading = true;
|
||||||
|
|
||||||
function getPortfolio(portfolio_id) {
|
function getPortfolio(portfolio_id) {
|
||||||
|
@ -174,19 +179,16 @@ function handlePortfolioSelection() {
|
||||||
function updatePortfolioSeniorOfficial(seniorOfficialField, senior_official) {
|
function updatePortfolioSeniorOfficial(seniorOfficialField, senior_official) {
|
||||||
|
|
||||||
let seniorOfficial = seniorOfficialField.querySelector(".readonly");
|
let seniorOfficial = seniorOfficialField.querySelector(".readonly");
|
||||||
let seniorOfficialAddress = seniorOfficialField.querySelector(".dja-address-contact-list");
|
|
||||||
let portfolioSeniorOfficialAddress = document.querySelector(".field-portfolio_senior_official .dja-address-contact-list");
|
|
||||||
|
|
||||||
|
|
||||||
if (senior_official) {
|
if (senior_official) {
|
||||||
let seniorOfficialName = [senior_official.first_name, senior_official.last_name].join(' ');
|
let seniorOfficialName = [senior_official.first_name, senior_official.last_name].join(' ');
|
||||||
let seniorOfficialLink = `<a href=/admin/registrar/seniorofficial/${senior_official.id}/change/ class='test'>${seniorOfficialName}</a>`
|
let seniorOfficialLink = `<a href=/admin/registrar/seniorofficial/${senior_official.id}/change/ class='test'>${seniorOfficialName}</a>`
|
||||||
seniorOfficial.innerHTML = seniorOfficialName ? seniorOfficialLink : "-";
|
seniorOfficial.innerHTML = seniorOfficialName ? seniorOfficialLink : "-";
|
||||||
updateSeniorOfficialContactInfo(seniorOfficialAddress, senior_official);
|
updateSeniorOfficialContactInfo(seniorOfficialAddress, senior_official);
|
||||||
showElement(portfolioSeniorOfficialAddress);
|
showElement(seniorOfficialAddress);
|
||||||
} else {
|
} else {
|
||||||
portfolioSeniorOfficial.innerText = "No senior official found.";
|
portfolioSeniorOfficial.innerText = "No senior official found.";
|
||||||
hideElement(portfolioSeniorOfficialAddress);
|
hideElement(seniorOfficialAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,20 +218,15 @@ function handlePortfolioSelection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePortfolioFieldsDataDynamicDisplay() {
|
function updatePortfolioFieldsDataDynamicDisplay() {
|
||||||
|
|
||||||
// the federal agency change listener fires on page load, which we don't want.
|
|
||||||
var isInitialPageLoad = true
|
|
||||||
|
|
||||||
// This is the additional information that exists beneath the SO element.
|
|
||||||
var contactList = document.querySelector(".field-portfolio_senior_official .dja-address-contact-list");
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
let federalAgencyValue = portfolioFederalAgency.innerText;
|
let federalAgencyValue = portfolioFederalAgency.innerText;
|
||||||
let portfolioOrgTypeValue = portfolioOrgType.innerText;
|
let portfolioOrgTypeValue = portfolioOrgType.innerText;
|
||||||
|
|
||||||
// if (federalAgencyValue && portfolioOrgTypeValue) {
|
if (federalAgencyValue && portfolioOrgTypeValue) {
|
||||||
// handleFederalAgencyChange(federalAgencyValue, portfolioOrgTypeValue, portfolioOrgNameField, portfolioFederalTypeField);
|
handleFederalAgencyChange(federalAgencyValue, portfolioOrgTypeValue);
|
||||||
// }
|
}
|
||||||
// Handle dynamically hiding the urbanization field
|
// Handle dynamically hiding the urbanization field
|
||||||
let portfolioStateTerritoryValue = portfolioStateTerritory.innerText;
|
let portfolioStateTerritoryValue = portfolioStateTerritory.innerText;
|
||||||
if (portfolioUrbanizationField && portfolioStateTerritoryValue) {
|
if (portfolioUrbanizationField && portfolioStateTerritoryValue) {
|
||||||
|
@ -237,8 +234,9 @@ function handlePortfolioSelection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle hiding the organization name field when the organization_type is federal.
|
// Handle hiding the organization name field when the organization_type is federal.
|
||||||
// Run this first one page load, then secondly on a change event.
|
|
||||||
handleOrganizationTypeChange(portfolioOrgTypeValue, portfolioOrgNameField, portfolioFederalTypeField);
|
handleOrganizationTypeChange(portfolioOrgTypeValue, portfolioOrgNameField, portfolioFederalTypeField);
|
||||||
|
|
||||||
|
handleNoSeniorOfficialData();
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleOrganizationTypeChange(portfolioOrgTypeValue, portfolioOrgNameField, portfolioFederalTypeField) {
|
function handleOrganizationTypeChange(portfolioOrgTypeValue, portfolioOrgNameField, portfolioFederalTypeField) {
|
||||||
|
@ -257,13 +255,7 @@ function handlePortfolioSelection() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFederalAgencyChange(federalAgencyValue, organizationTypeValue, portfolioOrgNameField, portfolioFederalTypeField) {
|
function handleFederalAgencyChange(federalAgencyValue, organizationTypeValue) {
|
||||||
// Don't do anything on page load
|
|
||||||
if (isInitialPageLoad) {
|
|
||||||
isInitialPageLoad = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There isn't a federal senior official associated with null records
|
// There isn't a federal senior official associated with null records
|
||||||
if (!federalAgencyValue) {
|
if (!federalAgencyValue) {
|
||||||
return;
|
return;
|
||||||
|
@ -273,70 +265,11 @@ function handlePortfolioSelection() {
|
||||||
if (organizationTypeValue !== "federal") {
|
if (organizationTypeValue !== "federal") {
|
||||||
portfolioOrgType.innerText = "Federal"
|
portfolioOrgType.innerText = "Federal"
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
if (organizationTypeValue === "federal") {
|
if (organizationTypeValue === "federal") {
|
||||||
portfolioOrgType.innerText = "-"
|
portfolioOrgType.innerText = "-"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOrganizationTypeChange(organizationTypeValue, portfolioOrgNameField, portfolioFederalTypeField);
|
|
||||||
|
|
||||||
// We are missing these hooks that exist on the portfolio template, so I hardcoded them for now:
|
|
||||||
// <input id="senior_official_from_agency_json_url" class="display-none" value="/admin/api/get-senior-official-from-federal-agency-json/" />
|
|
||||||
// <input id="federal_and_portfolio_types_from_agency_json_url" class="display-none" value="/admin/api/get-federal-and-portfolio-types-from-federal-agency-json/" />
|
|
||||||
// <input id="senior-official-add-url" class="display-none" value="/admin/registrar/seniorofficial/add/" />
|
|
||||||
|
|
||||||
let federalPortfolioApi = "/admin/api/get-federal-and-portfolio-types-from-federal-agency-json/";
|
|
||||||
fetch(`${federalPortfolioApi}?&agency_name=${selectedText}`)
|
|
||||||
.then(response => {
|
|
||||||
const statusCode = response.status;
|
|
||||||
return response.json().then(data => ({ statusCode, data }));
|
|
||||||
})
|
|
||||||
.then(({ statusCode, data }) => {
|
|
||||||
if (data.error) {
|
|
||||||
console.error("Error in AJAX call: " + data.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateReadOnly(data.federal_type, '.field-portfolio_federal_type');
|
|
||||||
})
|
|
||||||
.catch(error => console.error("Error fetching federal and portfolio types: ", error));
|
|
||||||
|
|
||||||
hideElement(contactList.parentElement);
|
|
||||||
|
|
||||||
let seniorOfficialAddUrl = "/admin/registrar/seniorofficial/add/";
|
|
||||||
let readonlySeniorOfficial = document.querySelector(".field-senior_official .readonly");
|
|
||||||
let seniorOfficialApi = "/admin/api/get-senior-official-from-federal-agency-json/";
|
|
||||||
fetch(`${seniorOfficialApi}?agency_name=${selectedText}`)
|
|
||||||
.then(response => {
|
|
||||||
const statusCode = response.status;
|
|
||||||
return response.json().then(data => ({ statusCode, data }));
|
|
||||||
})
|
|
||||||
.then(({ statusCode, data }) => {
|
|
||||||
if (data.error) {
|
|
||||||
if (statusCode === 404) {
|
|
||||||
readonlySeniorOfficial.innerHTML = `<a href="${seniorOfficialAddUrl}">No senior official found. Create one now.</a>`;
|
|
||||||
console.warn("Record not found: " + data.error);
|
|
||||||
}else {
|
|
||||||
console.error("Error in AJAX call: " + data.error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the "contact details" blurb beneath senior official
|
|
||||||
updateContactInfo(data);
|
|
||||||
showElement(contactList.parentElement);
|
|
||||||
|
|
||||||
// Get the associated senior official with this federal agency
|
|
||||||
let seniorOfficialId = data.id;
|
|
||||||
let seniorOfficialName = [data.first_name, data.last_name].join(" ");
|
|
||||||
|
|
||||||
if (readonlySeniorOfficial) {
|
|
||||||
let seniorOfficialLink = `<a href=/admin/registrar/seniorofficial/${seniorOfficialId}/change/ class='test'>${seniorOfficialName}</a>`
|
|
||||||
readonlySeniorOfficial.innerHTML = seniorOfficialName ? seniorOfficialLink : "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(error => console.error("Error fetching senior official: ", error));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,56 +281,11 @@ function handlePortfolioSelection() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function handleNoSeniorOfficialData() {
|
||||||
* Utility that selects a div from the DOM using selectorString,
|
if (portfolioSeniorOfficial.innerText.includes("No additional contact information found")) {
|
||||||
* and updates a div within that div which has class of 'readonly'
|
hideElement(seniorOfficialAddress);
|
||||||
* so that the text of the div is updated to updateText
|
|
||||||
* @param {*} updateText
|
|
||||||
* @param {*} selectorString
|
|
||||||
*/
|
|
||||||
function updateReadOnly(updateText, selectorString) {
|
|
||||||
// find the div by selectorString
|
|
||||||
const selectedDiv = document.querySelector(selectorString);
|
|
||||||
if (selectedDiv) {
|
|
||||||
// find the nested div with class 'readonly' inside the selectorString div
|
|
||||||
const readonlyDiv = selectedDiv.querySelector('.readonly');
|
|
||||||
if (readonlyDiv) {
|
|
||||||
// Update the text content of the readonly div
|
|
||||||
readonlyDiv.textContent = updateText !== null ? updateText : '-';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContactInfo(data) {
|
|
||||||
if (!contactList) return;
|
|
||||||
|
|
||||||
const titleSpan = contactList.querySelector(".contact_info_title");
|
|
||||||
const emailSpan = contactList.querySelector(".contact_info_email");
|
|
||||||
const phoneSpan = contactList.querySelector(".contact_info_phone");
|
|
||||||
|
|
||||||
if (titleSpan) {
|
|
||||||
titleSpan.textContent = data.title || "None";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update the email field and the content for the clipboard
|
|
||||||
if (emailSpan) {
|
|
||||||
let copyButton = contactList.querySelector(".admin-icon-group");
|
|
||||||
emailSpan.textContent = data.email || "None";
|
|
||||||
if (data.email) {
|
|
||||||
const clipboardInput = contactList.querySelector(".admin-icon-group input");
|
|
||||||
if (clipboardInput) {
|
|
||||||
clipboardInput.value = data.email;
|
|
||||||
};
|
|
||||||
showElement(copyButton);
|
|
||||||
}else {
|
|
||||||
hideElement(copyButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phoneSpan) {
|
|
||||||
phoneSpan.textContent = data.phone || "None";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updatePortfolioFields() {
|
async function updatePortfolioFields() {
|
||||||
|
@ -1426,6 +1314,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
|
||||||
/** An IIFE for dynamically changing some fields on the portfolio admin model
|
/** An IIFE for dynamically changing some fields on the portfolio admin model
|
||||||
|
* IMPORTANT NOTE: The logic in this IIFE is paired handlePortfolioSelection
|
||||||
*/
|
*/
|
||||||
(function dynamicPortfolioFields(){
|
(function dynamicPortfolioFields(){
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,9 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
||||||
{% elif field.field.name == "portfolio_senior_official" %}
|
{% elif field.field.name == "portfolio_senior_official" %}
|
||||||
<div class="readonly">
|
<div class="readonly">
|
||||||
{% if original_object.portfolio.senior_official %}
|
{% if original_object.portfolio.senior_official %}
|
||||||
<a href="{% url 'admin:registrar_seniorofficial_change' original_object.portfolio.senior_official.id %}">{{ field.contents }}</a></div>
|
<a href="{% url 'admin:registrar_seniorofficial_change' original_object.portfolio.senior_official.id %}">{{ field.contents }}</a>
|
||||||
|
{% else %}
|
||||||
|
No additional contact information found.<br>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% elif field.field.name == "other_contacts" %}
|
{% elif field.field.name == "other_contacts" %}
|
||||||
|
@ -341,6 +343,11 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
||||||
{% elif field.field.name == "portfolio_senior_official" %}
|
{% elif field.field.name == "portfolio_senior_official" %}
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<label aria-label="Senior official contact details"></label>
|
<label aria-label="Senior official contact details"></label>
|
||||||
|
{% comment %}fields_always_present=True will shortcut the contact_detail_list template when
|
||||||
|
1. Senior official field should be hidden on domain request because no portfoloio is selected, which is desirable
|
||||||
|
2. A portfolio is selected but there is no senior official on the portfolio, where the shortcut is not desirable
|
||||||
|
To solve 2, we use an else No additional contact information found on field.field.name == "portfolio_senior_official"
|
||||||
|
and we hide the placeholders from detail_table_fieldset in JS{% endcomment %}
|
||||||
{% include "django/admin/includes/contact_detail_list.html" with user=original_object.portfolio.senior_official no_title_top_padding=field.is_readonly fields_always_present=True %}
|
{% include "django/admin/includes/contact_detail_list.html" with user=original_object.portfolio.senior_official no_title_top_padding=field.is_readonly fields_always_present=True %}
|
||||||
</div>
|
</div>
|
||||||
{% elif field.field.name == "other_contacts" and original_object.other_contacts.all %}
|
{% elif field.field.name == "other_contacts" and original_object.other_contacts.all %}
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.contrib.admin.views.decorators import staff_member_required
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from registrar.utility.admin_helpers import get_action_needed_reason_default_email, get_rejection_reason_default_email
|
from registrar.utility.admin_helpers import get_action_needed_reason_default_email, get_rejection_reason_default_email
|
||||||
from registrar.models.portfolio import Portfolio
|
from registrar.models.portfolio import Portfolio
|
||||||
|
from registrar.models.domain_request import DomainRequest
|
||||||
from registrar.utility.constants import BranchChoices
|
from registrar.utility.constants import BranchChoices
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -61,6 +62,9 @@ def get_portfolio_json(request):
|
||||||
|
|
||||||
# map portfolio federal type
|
# map portfolio federal type
|
||||||
portfolio_dict["federal_type"] = BranchChoices.get_branch_label(portfolio.federal_type) if portfolio.federal_type else "-"
|
portfolio_dict["federal_type"] = BranchChoices.get_branch_label(portfolio.federal_type) if portfolio.federal_type else "-"
|
||||||
|
|
||||||
|
# map portfolio organization type
|
||||||
|
portfolio_dict["organization_type"] = DomainRequest.OrganizationChoices.get_org_label(portfolio.organization_type) if portfolio.organization_type else "-"
|
||||||
|
|
||||||
# Add senior official information if it exists
|
# Add senior official information if it exists
|
||||||
if portfolio.senior_official:
|
if portfolio.senior_official:
|
||||||
|
@ -84,7 +88,7 @@ def get_portfolio_json(request):
|
||||||
)
|
)
|
||||||
portfolio_dict["federal_agency"] = federal_agency["agency"]
|
portfolio_dict["federal_agency"] = federal_agency["agency"]
|
||||||
else:
|
else:
|
||||||
portfolio_dict["federal_agency"] = None
|
portfolio_dict["federal_agency"] = '-'
|
||||||
|
|
||||||
return JsonResponse(portfolio_dict)
|
return JsonResponse(portfolio_dict)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue