mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-06 03:03:25 +02:00
Fix JS check, revise authentication check
This commit is contained in:
parent
996a6944a3
commit
fc52d98f21
3 changed files with 333 additions and 331 deletions
|
@ -912,180 +912,183 @@ function ScrollToElement(attributeName, attributeValue) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
let currentSortBy = 'id';
|
|
||||||
let currentOrder = 'asc';
|
|
||||||
let domainsWrapper = document.querySelector('.domains-wrapper');
|
let domainsWrapper = document.querySelector('.domains-wrapper');
|
||||||
let noDomainsWrapper = document.querySelector('.no-domains-wrapper');
|
|
||||||
let hasLoaded = false;
|
|
||||||
|
|
||||||
/**
|
if (domainsWrapper) {
|
||||||
* Loads rows in the domains list, as well as updates pagination around the domains list
|
let currentSortBy = 'id';
|
||||||
* based on the supplied attributes.
|
let currentOrder = 'asc';
|
||||||
* @param {*} page - the page number of the results (starts with 1)
|
let noDomainsWrapper = document.querySelector('.no-domains-wrapper');
|
||||||
* @param {*} sortBy - the sort column option
|
let hasLoaded = false;
|
||||||
* @param {*} order - the sort order {asc, desc}
|
|
||||||
* @param {*} loaded - control for the scrollToElement functionality
|
|
||||||
*/
|
|
||||||
function loadDomains(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) {
|
|
||||||
//fetch json of page of domains, given page # and sort
|
|
||||||
fetch(`/get-domains-json/?page=${page}&sort_by=${sortBy}&order=${order}`)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.error) {
|
|
||||||
console.log('Error in AJAX call: ' + data.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle the display of proper messaging in the event that no domains exist in the list
|
/**
|
||||||
if (data.domains.length) {
|
* Loads rows in the domains list, as well as updates pagination around the domains list
|
||||||
domainsWrapper.classList.remove('display-none');
|
* based on the supplied attributes.
|
||||||
noDomainsWrapper.classList.add('display-none');
|
* @param {*} page - the page number of the results (starts with 1)
|
||||||
} else {
|
* @param {*} sortBy - the sort column option
|
||||||
domainsWrapper.classList.add('display-none');
|
* @param {*} order - the sort order {asc, desc}
|
||||||
noDomainsWrapper.classList.remove('display-none');
|
* @param {*} loaded - control for the scrollToElement functionality
|
||||||
}
|
*/
|
||||||
|
function loadDomains(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) {
|
||||||
|
//fetch json of page of domains, given page # and sort
|
||||||
|
fetch(`/get-domains-json/?page=${page}&sort_by=${sortBy}&order=${order}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.error) {
|
||||||
|
console.log('Error in AJAX call: ' + data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// identify the DOM element where the domain list will be inserted into the DOM
|
// handle the display of proper messaging in the event that no domains exist in the list
|
||||||
const domainList = document.querySelector('.dotgov-table__registered-domains tbody');
|
if (data.domains.length) {
|
||||||
domainList.innerHTML = '';
|
domainsWrapper.classList.remove('display-none');
|
||||||
|
noDomainsWrapper.classList.add('display-none');
|
||||||
|
} else {
|
||||||
|
domainsWrapper.classList.add('display-none');
|
||||||
|
noDomainsWrapper.classList.remove('display-none');
|
||||||
|
}
|
||||||
|
|
||||||
data.domains.forEach(domain => {
|
// identify the DOM element where the domain list will be inserted into the DOM
|
||||||
const expirationDate = domain.expiration_date ? new Date(domain.expiration_date) : null;
|
const domainList = document.querySelector('.dotgov-table__registered-domains tbody');
|
||||||
const expirationDateSortValue = expirationDate ? expirationDate.getTime() : '';
|
domainList.innerHTML = '';
|
||||||
const actionUrl = domain.action_url;
|
|
||||||
|
data.domains.forEach(domain => {
|
||||||
const row = document.createElement('tr');
|
const expirationDate = domain.expiration_date ? new Date(domain.expiration_date) : null;
|
||||||
row.innerHTML = `
|
const expirationDateSortValue = expirationDate ? expirationDate.getTime() : '';
|
||||||
<th scope="row" role="rowheader" data-label="Domain name">
|
const actionUrl = domain.action_url;
|
||||||
${domain.name}
|
|
||||||
</th>
|
const row = document.createElement('tr');
|
||||||
<td data-sort-value="${expirationDateSortValue}" data-label="Expires">
|
row.innerHTML = `
|
||||||
${expirationDate ? expirationDate.toLocaleDateString() : ''}
|
<th scope="row" role="rowheader" data-label="Domain name">
|
||||||
</td>
|
${domain.name}
|
||||||
<td data-label="Status">
|
</th>
|
||||||
${domain.state_display}
|
<td data-sort-value="${expirationDateSortValue}" data-label="Expires">
|
||||||
<svg
|
${expirationDate ? expirationDate.toLocaleDateString() : ''}
|
||||||
class="usa-icon usa-tooltip usa-tooltip--registrar text-middle margin-bottom-05 text-accent-cool no-click-outline-and-cursor-help"
|
</td>
|
||||||
data-position="top"
|
<td data-label="Status">
|
||||||
title="${domain.get_state_help_text}"
|
${domain.state_display}
|
||||||
focusable="true"
|
<svg
|
||||||
aria-label="Status Information"
|
class="usa-icon usa-tooltip usa-tooltip--registrar text-middle margin-bottom-05 text-accent-cool no-click-outline-and-cursor-help"
|
||||||
role="tooltip"
|
data-position="top"
|
||||||
>
|
title="${domain.get_state_help_text}"
|
||||||
<use aria-hidden="true" xlink:href="/public/img/sprite.svg#info_outline"></use>
|
focusable="true"
|
||||||
</svg>
|
aria-label="Status Information"
|
||||||
</td>
|
role="tooltip"
|
||||||
<td>
|
>
|
||||||
<a href="${actionUrl}">
|
<use aria-hidden="true" xlink:href="/public/img/sprite.svg#info_outline"></use>
|
||||||
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24">
|
|
||||||
<use xlink:href="/public/img/sprite.svg#${domain.state === 'deleted' || domain.state === 'on hold' ? 'visibility' : 'settings'}"></use>
|
|
||||||
</svg>
|
</svg>
|
||||||
${domain.state === 'deleted' || domain.state === 'on hold' ? 'View' : 'Manage'} <span class="usa-sr-only">${domain.name}</span>
|
</td>
|
||||||
</a>
|
<td>
|
||||||
</td>
|
<a href="${actionUrl}">
|
||||||
`;
|
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24">
|
||||||
domainList.appendChild(row);
|
<use xlink:href="/public/img/sprite.svg#${domain.state === 'deleted' || domain.state === 'on hold' ? 'visibility' : 'settings'}"></use>
|
||||||
});
|
</svg>
|
||||||
// initialize tool tips immediately after the associated DOM elements are added
|
${domain.state === 'deleted' || domain.state === 'on hold' ? 'View' : 'Manage'} <span class="usa-sr-only">${domain.name}</span>
|
||||||
initializeTooltips();
|
</a>
|
||||||
if (loaded)
|
</td>
|
||||||
ScrollToElement('id', 'domains-header');
|
`;
|
||||||
|
domainList.appendChild(row);
|
||||||
|
});
|
||||||
|
// initialize tool tips immediately after the associated DOM elements are added
|
||||||
|
initializeTooltips();
|
||||||
|
if (loaded)
|
||||||
|
ScrollToElement('id', 'domains-header');
|
||||||
|
|
||||||
hasLoaded = true;
|
hasLoaded = true;
|
||||||
|
|
||||||
// update pagination
|
// update pagination
|
||||||
updateDomainsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total);
|
updateDomainsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total);
|
||||||
currentSortBy = sortBy;
|
currentSortBy = sortBy;
|
||||||
currentOrder = order;
|
currentOrder = order;
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error fetching domains:', error));
|
.catch(error => console.error('Error fetching domains:', error));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the pagination below the domains list.
|
|
||||||
* @param {*} currentPage - the current page number (starting with 1)
|
|
||||||
* @param {*} numPages - the number of pages indicated by the domains list response
|
|
||||||
* @param {*} hasPrevious - if there is a page of results prior to the current page
|
|
||||||
* @param {*} hasNext - if there is a page of results after the current page
|
|
||||||
*/
|
|
||||||
function updateDomainsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) {
|
|
||||||
// identify the DOM element where the pagination will be inserted
|
|
||||||
const paginationContainer = document.querySelector('#domains-pagination');
|
|
||||||
const paginationCounter = document.querySelector('#domains-pagination .usa-pagination__counter');
|
|
||||||
const paginationButtons = document.querySelector('#domains-pagination .usa-pagination__list');
|
|
||||||
paginationCounter.innerHTML = '';
|
|
||||||
paginationButtons.innerHTML = '';
|
|
||||||
|
|
||||||
// Buttons should only be displayed if there are more than one pages of results
|
|
||||||
paginationButtons.classList.toggle('display-none', numPages <= 1);
|
|
||||||
|
|
||||||
// Counter should only be displayed if there is more than 1 item
|
|
||||||
paginationContainer.classList.toggle('display-none', totalItems < 1);
|
|
||||||
|
|
||||||
paginationCounter.innerHTML = `${totalItems} domain${totalItems > 1 ? 's' : ''}`;
|
|
||||||
|
|
||||||
if (hasPrevious) {
|
|
||||||
const prevPageItem = document.createElement('li');
|
|
||||||
prevPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
|
||||||
prevPageItem.innerHTML = `
|
|
||||||
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__previous-page" aria-label="Domains previous page">
|
|
||||||
<svg class="usa-icon" aria-hidden="true" role="img">
|
|
||||||
<use xlink:href="/public/img/sprite.svg#navigate_before"></use>
|
|
||||||
</svg>
|
|
||||||
<span class="usa-pagination__link-text">Previous</span>
|
|
||||||
</a>
|
|
||||||
`;
|
|
||||||
prevPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage - 1));
|
|
||||||
paginationButtons.appendChild(prevPageItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= numPages; i++) {
|
/**
|
||||||
const pageItem = document.createElement('li');
|
* Update the pagination below the domains list.
|
||||||
pageItem.className = 'usa-pagination__item usa-pagination__page-no';
|
* @param {*} currentPage - the current page number (starting with 1)
|
||||||
pageItem.innerHTML = `
|
* @param {*} numPages - the number of pages indicated by the domains list response
|
||||||
<a href="javascript:void(0);" class="usa-pagination__button" aria-label="Domains page ${i}">${i}</a>
|
* @param {*} hasPrevious - if there is a page of results prior to the current page
|
||||||
`;
|
* @param {*} hasNext - if there is a page of results after the current page
|
||||||
if (i === currentPage) {
|
*/
|
||||||
pageItem.querySelector('a').classList.add('usa-current');
|
function updateDomainsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) {
|
||||||
pageItem.querySelector('a').setAttribute('aria-current', 'page');
|
// identify the DOM element where the pagination will be inserted
|
||||||
|
const paginationContainer = document.querySelector('#domains-pagination');
|
||||||
|
const paginationCounter = document.querySelector('#domains-pagination .usa-pagination__counter');
|
||||||
|
const paginationButtons = document.querySelector('#domains-pagination .usa-pagination__list');
|
||||||
|
paginationCounter.innerHTML = '';
|
||||||
|
paginationButtons.innerHTML = '';
|
||||||
|
|
||||||
|
// Buttons should only be displayed if there are more than one pages of results
|
||||||
|
paginationButtons.classList.toggle('display-none', numPages <= 1);
|
||||||
|
|
||||||
|
// Counter should only be displayed if there is more than 1 item
|
||||||
|
paginationContainer.classList.toggle('display-none', totalItems < 1);
|
||||||
|
|
||||||
|
paginationCounter.innerHTML = `${totalItems} domain${totalItems > 1 ? 's' : ''}`;
|
||||||
|
|
||||||
|
if (hasPrevious) {
|
||||||
|
const prevPageItem = document.createElement('li');
|
||||||
|
prevPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
||||||
|
prevPageItem.innerHTML = `
|
||||||
|
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__previous-page" aria-label="Domains previous page">
|
||||||
|
<svg class="usa-icon" aria-hidden="true" role="img">
|
||||||
|
<use xlink:href="/public/img/sprite.svg#navigate_before"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="usa-pagination__link-text">Previous</span>
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
prevPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage - 1));
|
||||||
|
paginationButtons.appendChild(prevPageItem);
|
||||||
}
|
}
|
||||||
pageItem.querySelector('a').addEventListener('click', () => loadDomains(i));
|
|
||||||
paginationButtons.appendChild(pageItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasNext) {
|
for (let i = 1; i <= numPages; i++) {
|
||||||
const nextPageItem = document.createElement('li');
|
const pageItem = document.createElement('li');
|
||||||
nextPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
pageItem.className = 'usa-pagination__item usa-pagination__page-no';
|
||||||
nextPageItem.innerHTML = `
|
pageItem.innerHTML = `
|
||||||
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__next-page" aria-label="Domains next page">
|
<a href="javascript:void(0);" class="usa-pagination__button" aria-label="Domains page ${i}">${i}</a>
|
||||||
<span class="usa-pagination__link-text">Next</span>
|
`;
|
||||||
<svg class="usa-icon" aria-hidden="true" role="img">
|
if (i === currentPage) {
|
||||||
<use xlink:href="/public/img/sprite.svg#navigate_next"></use>
|
pageItem.querySelector('a').classList.add('usa-current');
|
||||||
</svg>
|
pageItem.querySelector('a').setAttribute('aria-current', 'page');
|
||||||
</a>
|
}
|
||||||
`;
|
pageItem.querySelector('a').addEventListener('click', () => loadDomains(i));
|
||||||
nextPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage + 1));
|
paginationButtons.appendChild(pageItem);
|
||||||
paginationButtons.appendChild(nextPageItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add event listeners to table headers for sorting
|
|
||||||
document.querySelectorAll('.dotgov-table__registered-domains th[data-sortable]').forEach(header => {
|
|
||||||
header.addEventListener('click', function() {
|
|
||||||
const sortBy = this.getAttribute('data-sortable');
|
|
||||||
let order = 'asc';
|
|
||||||
// sort order will be ascending, unless the currently sorted column is ascending, and the user
|
|
||||||
// is selecting the same column to sort in descending order
|
|
||||||
if (sortBy === currentSortBy) {
|
|
||||||
order = currentOrder === 'asc' ? 'desc' : 'asc';
|
|
||||||
}
|
}
|
||||||
// load the results with the updated sort
|
|
||||||
loadDomains(1, sortBy, order);
|
if (hasNext) {
|
||||||
|
const nextPageItem = document.createElement('li');
|
||||||
|
nextPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
||||||
|
nextPageItem.innerHTML = `
|
||||||
|
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__next-page" aria-label="Domains next page">
|
||||||
|
<span class="usa-pagination__link-text">Next</span>
|
||||||
|
<svg class="usa-icon" aria-hidden="true" role="img">
|
||||||
|
<use xlink:href="/public/img/sprite.svg#navigate_next"></use>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
nextPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage + 1));
|
||||||
|
paginationButtons.appendChild(nextPageItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners to table headers for sorting
|
||||||
|
document.querySelectorAll('.dotgov-table__registered-domains th[data-sortable]').forEach(header => {
|
||||||
|
header.addEventListener('click', function() {
|
||||||
|
const sortBy = this.getAttribute('data-sortable');
|
||||||
|
let order = 'asc';
|
||||||
|
// sort order will be ascending, unless the currently sorted column is ascending, and the user
|
||||||
|
// is selecting the same column to sort in descending order
|
||||||
|
if (sortBy === currentSortBy) {
|
||||||
|
order = currentOrder === 'asc' ? 'desc' : 'asc';
|
||||||
|
}
|
||||||
|
// load the results with the updated sort
|
||||||
|
loadDomains(1, sortBy, order);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Load the first page initially
|
// Load the first page initially
|
||||||
loadDomains(1);
|
loadDomains(1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1094,185 +1097,188 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
let currentSortBy = 'id';
|
|
||||||
let currentOrder = 'asc';
|
|
||||||
let domainRequestsWrapper = document.querySelector('.domain-requests-wrapper');
|
let domainRequestsWrapper = document.querySelector('.domain-requests-wrapper');
|
||||||
let noDomainRequestsWrapper = document.querySelector('.no-domain-requests-wrapper');
|
|
||||||
let hasLoaded = false;
|
|
||||||
|
|
||||||
/**
|
if (domainRequestsWrapper) {
|
||||||
* Loads rows in the domain requests list, as well as updates pagination around the domain requests list
|
let currentSortBy = 'id';
|
||||||
* based on the supplied attributes.
|
let currentOrder = 'asc';
|
||||||
* @param {*} page - the page number of the results (starts with 1)
|
let noDomainRequestsWrapper = document.querySelector('.no-domain-requests-wrapper');
|
||||||
* @param {*} sortBy - the sort column option
|
let hasLoaded = false;
|
||||||
* @param {*} order - the sort order {asc, desc}
|
|
||||||
* @param {*} loaded - control for the scrollToElement functionality
|
|
||||||
*/
|
|
||||||
function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) {
|
|
||||||
//fetch json of page of domain requests, given page # and sort
|
|
||||||
fetch(`/get-domain-requests-json/?page=${page}&sort_by=${sortBy}&order=${order}`)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.error) {
|
|
||||||
console.log('Error in AJAX call: ' + data.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle the display of proper messaging in the event that no domain requests exist in the list
|
/**
|
||||||
if (data.domain_requests.length) {
|
* Loads rows in the domain requests list, as well as updates pagination around the domain requests list
|
||||||
domainRequestsWrapper.classList.remove('display-none');
|
* based on the supplied attributes.
|
||||||
noDomainRequestsWrapper.classList.add('display-none');
|
* @param {*} page - the page number of the results (starts with 1)
|
||||||
} else {
|
* @param {*} sortBy - the sort column option
|
||||||
domainRequestsWrapper.classList.add('display-none');
|
* @param {*} order - the sort order {asc, desc}
|
||||||
noDomainRequestsWrapper.classList.remove('display-none');
|
* @param {*} loaded - control for the scrollToElement functionality
|
||||||
}
|
*/
|
||||||
|
function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) {
|
||||||
|
//fetch json of page of domain requests, given page # and sort
|
||||||
|
fetch(`/get-domain-requests-json/?page=${page}&sort_by=${sortBy}&order=${order}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.error) {
|
||||||
|
console.log('Error in AJAX call: ' + data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// identify the DOM element where the domain request list will be inserted into the DOM
|
// handle the display of proper messaging in the event that no domain requests exist in the list
|
||||||
const tbody = document.querySelector('.dotgov-table__domain-requests tbody');
|
if (data.domain_requests.length) {
|
||||||
tbody.innerHTML = '';
|
domainRequestsWrapper.classList.remove('display-none');
|
||||||
|
noDomainRequestsWrapper.classList.add('display-none');
|
||||||
|
} else {
|
||||||
|
domainRequestsWrapper.classList.add('display-none');
|
||||||
|
noDomainRequestsWrapper.classList.remove('display-none');
|
||||||
|
}
|
||||||
|
|
||||||
// remove any existing modal elements from the DOM so they can be properly re-initialized
|
// identify the DOM element where the domain request list will be inserted into the DOM
|
||||||
// after the DOM content changes and there are new delete modal buttons added
|
const tbody = document.querySelector('.dotgov-table__domain-requests tbody');
|
||||||
unloadModals();
|
tbody.innerHTML = '';
|
||||||
data.domain_requests.forEach(request => {
|
|
||||||
const domainName = request.requested_domain ? request.requested_domain : `New domain request <span class="text-base font-body-xs">(${new Date(request.created_at).toLocaleString()} UTC)</span>`;
|
|
||||||
const submissionDate = request.submission_date ? new Date(request.submission_date).toLocaleDateString() : `<span class="text-base">Not submitted</span>`;
|
|
||||||
const actionUrl = request.action_url;
|
|
||||||
const actionLabel = request.action_label;
|
|
||||||
const deleteButton = request.is_deletable ? `
|
|
||||||
<a
|
|
||||||
role="button"
|
|
||||||
id="button-toggle-delete-domain-alert-${request.id}"
|
|
||||||
href="#toggle-delete-domain-alert-${request.id}"
|
|
||||||
class="usa-button--unstyled text-no-underline late-loading-modal-trigger"
|
|
||||||
aria-controls="toggle-delete-domain-alert-${request.id}"
|
|
||||||
data-open-modal
|
|
||||||
>
|
|
||||||
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24">
|
|
||||||
<use xlink:href="/public/img/sprite.svg#delete"></use>
|
|
||||||
</svg> Delete <span class="usa-sr-only">${domainName}</span>
|
|
||||||
</a>` : '';
|
|
||||||
|
|
||||||
const row = document.createElement('tr');
|
// remove any existing modal elements from the DOM so they can be properly re-initialized
|
||||||
row.innerHTML = `
|
// after the DOM content changes and there are new delete modal buttons added
|
||||||
<th scope="row" role="rowheader" data-label="Domain name">
|
unloadModals();
|
||||||
${domainName}
|
data.domain_requests.forEach(request => {
|
||||||
</th>
|
const domainName = request.requested_domain ? request.requested_domain : `New domain request <span class="text-base font-body-xs">(${new Date(request.created_at).toLocaleString()} UTC)</span>`;
|
||||||
<td data-sort-value="${new Date(request.submission_date).getTime()}" data-label="Date submitted">
|
const submissionDate = request.submission_date ? new Date(request.submission_date).toLocaleDateString() : `<span class="text-base">Not submitted</span>`;
|
||||||
${submissionDate}
|
const actionUrl = request.action_url;
|
||||||
</td>
|
const actionLabel = request.action_label;
|
||||||
<td data-label="Status">
|
const deleteButton = request.is_deletable ? `
|
||||||
${request.status}
|
<a
|
||||||
</td>
|
role="button"
|
||||||
<td>
|
id="button-toggle-delete-domain-alert-${request.id}"
|
||||||
<a href="${actionUrl}">
|
href="#toggle-delete-domain-alert-${request.id}"
|
||||||
|
class="usa-button--unstyled text-no-underline late-loading-modal-trigger"
|
||||||
|
aria-controls="toggle-delete-domain-alert-${request.id}"
|
||||||
|
data-open-modal
|
||||||
|
>
|
||||||
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24">
|
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24">
|
||||||
<use xlink:href="/public/img/sprite.svg#${request.state === 'deleted' || request.state === 'on hold' ? 'visibility' : 'settings'}"></use>
|
<use xlink:href="/public/img/sprite.svg#delete"></use>
|
||||||
</svg>
|
</svg> Delete <span class="usa-sr-only">${domainName}</span>
|
||||||
${actionLabel} <span class="usa-sr-only">${request.requested_domain ? request.requested_domain : 'New domain request'}</span>
|
</a>` : '';
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>${deleteButton}</td>
|
|
||||||
`;
|
|
||||||
tbody.appendChild(row);
|
|
||||||
});
|
|
||||||
// initialize modals immediately after the DOM content is updated
|
|
||||||
initializeModals();
|
|
||||||
if (loaded)
|
|
||||||
ScrollToElement('id', 'domain-requests-header');
|
|
||||||
|
|
||||||
hasLoaded = true;
|
const row = document.createElement('tr');
|
||||||
|
row.innerHTML = `
|
||||||
|
<th scope="row" role="rowheader" data-label="Domain name">
|
||||||
|
${domainName}
|
||||||
|
</th>
|
||||||
|
<td data-sort-value="${new Date(request.submission_date).getTime()}" data-label="Date submitted">
|
||||||
|
${submissionDate}
|
||||||
|
</td>
|
||||||
|
<td data-label="Status">
|
||||||
|
${request.status}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="${actionUrl}">
|
||||||
|
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24">
|
||||||
|
<use xlink:href="/public/img/sprite.svg#${request.state === 'deleted' || request.state === 'on hold' ? 'visibility' : 'settings'}"></use>
|
||||||
|
</svg>
|
||||||
|
${actionLabel} <span class="usa-sr-only">${request.requested_domain ? request.requested_domain : 'New domain request'}</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>${deleteButton}</td>
|
||||||
|
`;
|
||||||
|
tbody.appendChild(row);
|
||||||
|
});
|
||||||
|
// initialize modals immediately after the DOM content is updated
|
||||||
|
initializeModals();
|
||||||
|
if (loaded)
|
||||||
|
ScrollToElement('id', 'domain-requests-header');
|
||||||
|
|
||||||
// update the pagination after the domain requests list is updated
|
hasLoaded = true;
|
||||||
updateDomainRequestsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total);
|
|
||||||
currentSortBy = sortBy;
|
|
||||||
currentOrder = order;
|
|
||||||
})
|
|
||||||
.catch(error => console.error('Error fetching domain requests:', error));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// update the pagination after the domain requests list is updated
|
||||||
* Update the pagination below the domain requests list.
|
updateDomainRequestsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total);
|
||||||
* @param {*} currentPage - the current page number (starting with 1)
|
currentSortBy = sortBy;
|
||||||
* @param {*} numPages - the number of pages indicated by the domain request list response
|
currentOrder = order;
|
||||||
* @param {*} hasPrevious - if there is a page of results prior to the current page
|
})
|
||||||
* @param {*} hasNext - if there is a page of results after the current page
|
.catch(error => console.error('Error fetching domain requests:', error));
|
||||||
*/
|
|
||||||
function updateDomainRequestsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) {
|
|
||||||
// identify the DOM element where pagination is contained
|
|
||||||
const paginationContainer = document.querySelector('#domain-requests-pagination');
|
|
||||||
const paginationCounter = document.querySelector('#domain-requests-pagination .usa-pagination__counter');
|
|
||||||
const paginationButtons = document.querySelector('#domain-requests-pagination .usa-pagination__list');
|
|
||||||
paginationCounter.innerHTML = '';
|
|
||||||
paginationButtons.innerHTML = '';
|
|
||||||
|
|
||||||
// Buttons should only be displayed if there are more than one pages of results
|
|
||||||
paginationButtons.classList.toggle('display-none', numPages <= 1);
|
|
||||||
|
|
||||||
// Counter should only be displayed if there is more than 1 item
|
|
||||||
paginationContainer.classList.toggle('display-none', totalItems < 1);
|
|
||||||
|
|
||||||
paginationCounter.innerHTML = `${totalItems} domain request${totalItems > 1 ? 's' : ''}`;
|
|
||||||
|
|
||||||
if (hasPrevious) {
|
|
||||||
const prevPageItem = document.createElement('li');
|
|
||||||
prevPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
|
||||||
prevPageItem.innerHTML = `
|
|
||||||
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__previous-page" aria-label="Domain requests previous page">
|
|
||||||
<svg class="usa-icon" aria-hidden="true" role="img">
|
|
||||||
<use xlink:href="/public/img/sprite.svg#navigate_before"></use>
|
|
||||||
</svg>
|
|
||||||
<span class="usa-pagination__link-text">Previous</span>
|
|
||||||
</a>
|
|
||||||
`;
|
|
||||||
prevPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage - 1));
|
|
||||||
paginationButtons.appendChild(prevPageItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= numPages; i++) {
|
/**
|
||||||
const pageItem = document.createElement('li');
|
* Update the pagination below the domain requests list.
|
||||||
pageItem.className = 'usa-pagination__item usa-pagination__page-no';
|
* @param {*} currentPage - the current page number (starting with 1)
|
||||||
pageItem.innerHTML = `
|
* @param {*} numPages - the number of pages indicated by the domain request list response
|
||||||
<a href="javascript:void(0);" class="usa-pagination__button" aria-label="Domain requests page ${i}">${i}</a>
|
* @param {*} hasPrevious - if there is a page of results prior to the current page
|
||||||
`;
|
* @param {*} hasNext - if there is a page of results after the current page
|
||||||
if (i === currentPage) {
|
*/
|
||||||
pageItem.querySelector('a').classList.add('usa-current');
|
function updateDomainRequestsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) {
|
||||||
pageItem.querySelector('a').setAttribute('aria-current', 'page');
|
// identify the DOM element where pagination is contained
|
||||||
|
const paginationContainer = document.querySelector('#domain-requests-pagination');
|
||||||
|
const paginationCounter = document.querySelector('#domain-requests-pagination .usa-pagination__counter');
|
||||||
|
const paginationButtons = document.querySelector('#domain-requests-pagination .usa-pagination__list');
|
||||||
|
paginationCounter.innerHTML = '';
|
||||||
|
paginationButtons.innerHTML = '';
|
||||||
|
|
||||||
|
// Buttons should only be displayed if there are more than one pages of results
|
||||||
|
paginationButtons.classList.toggle('display-none', numPages <= 1);
|
||||||
|
|
||||||
|
// Counter should only be displayed if there is more than 1 item
|
||||||
|
paginationContainer.classList.toggle('display-none', totalItems < 1);
|
||||||
|
|
||||||
|
paginationCounter.innerHTML = `${totalItems} domain request${totalItems > 1 ? 's' : ''}`;
|
||||||
|
|
||||||
|
if (hasPrevious) {
|
||||||
|
const prevPageItem = document.createElement('li');
|
||||||
|
prevPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
||||||
|
prevPageItem.innerHTML = `
|
||||||
|
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__previous-page" aria-label="Domain requests previous page">
|
||||||
|
<svg class="usa-icon" aria-hidden="true" role="img">
|
||||||
|
<use xlink:href="/public/img/sprite.svg#navigate_before"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="usa-pagination__link-text">Previous</span>
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
prevPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage - 1));
|
||||||
|
paginationButtons.appendChild(prevPageItem);
|
||||||
}
|
}
|
||||||
pageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(i));
|
|
||||||
paginationButtons.appendChild(pageItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasNext) {
|
for (let i = 1; i <= numPages; i++) {
|
||||||
const nextPageItem = document.createElement('li');
|
const pageItem = document.createElement('li');
|
||||||
nextPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
pageItem.className = 'usa-pagination__item usa-pagination__page-no';
|
||||||
nextPageItem.innerHTML = `
|
pageItem.innerHTML = `
|
||||||
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__next-page" aria-label="Domain requests next page">
|
<a href="javascript:void(0);" class="usa-pagination__button" aria-label="Domain requests page ${i}">${i}</a>
|
||||||
<span class="usa-pagination__link-text">Next</span>
|
`;
|
||||||
<svg class="usa-icon" aria-hidden="true" role="img">
|
if (i === currentPage) {
|
||||||
<use xlink:href="/public/img/sprite.svg#navigate_next"></use>
|
pageItem.querySelector('a').classList.add('usa-current');
|
||||||
</svg>
|
pageItem.querySelector('a').setAttribute('aria-current', 'page');
|
||||||
</a>
|
}
|
||||||
`;
|
pageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(i));
|
||||||
nextPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage + 1));
|
paginationButtons.appendChild(pageItem);
|
||||||
paginationButtons.appendChild(nextPageItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add event listeners to table headers for sorting
|
|
||||||
document.querySelectorAll('.dotgov-table__domain-requests th[data-sortable]').forEach(header => {
|
|
||||||
header.addEventListener('click', function() {
|
|
||||||
const sortBy = this.getAttribute('data-sortable');
|
|
||||||
let order = 'asc';
|
|
||||||
// sort order will be ascending, unless the currently sorted column is ascending, and the user
|
|
||||||
// is selecting the same column to sort in descending order
|
|
||||||
if (sortBy === currentSortBy) {
|
|
||||||
order = currentOrder === 'asc' ? 'desc' : 'asc';
|
|
||||||
}
|
}
|
||||||
loadDomainRequests(1, sortBy, order);
|
|
||||||
|
if (hasNext) {
|
||||||
|
const nextPageItem = document.createElement('li');
|
||||||
|
nextPageItem.className = 'usa-pagination__item usa-pagination__arrow';
|
||||||
|
nextPageItem.innerHTML = `
|
||||||
|
<a href="javascript:void(0);" class="usa-pagination__link usa-pagination__next-page" aria-label="Domain requests next page">
|
||||||
|
<span class="usa-pagination__link-text">Next</span>
|
||||||
|
<svg class="usa-icon" aria-hidden="true" role="img">
|
||||||
|
<use xlink:href="/public/img/sprite.svg#navigate_next"></use>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
nextPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage + 1));
|
||||||
|
paginationButtons.appendChild(nextPageItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners to table headers for sorting
|
||||||
|
document.querySelectorAll('.dotgov-table__domain-requests th[data-sortable]').forEach(header => {
|
||||||
|
header.addEventListener('click', function() {
|
||||||
|
const sortBy = this.getAttribute('data-sortable');
|
||||||
|
let order = 'asc';
|
||||||
|
// sort order will be ascending, unless the currently sorted column is ascending, and the user
|
||||||
|
// is selecting the same column to sort in descending order
|
||||||
|
if (sortBy === currentSortBy) {
|
||||||
|
order = currentOrder === 'asc' ? 'desc' : 'asc';
|
||||||
|
}
|
||||||
|
loadDomainRequests(1, sortBy, order);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Load the first page initially
|
// Load the first page initially
|
||||||
loadDomainRequests(1);
|
loadDomainRequests(1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,15 +2,13 @@ from django.http import JsonResponse
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from registrar.models import DomainRequest
|
from registrar.models import DomainRequest
|
||||||
from django.utils.dateformat import format
|
from django.utils.dateformat import format
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
||||||
|
@login_required
|
||||||
def get_domain_requests_json(request):
|
def get_domain_requests_json(request):
|
||||||
"""Given the current request,
|
"""Given the current request,
|
||||||
get all domain requests that are associated with the request user and exclude the APPROVED ones"""
|
get all domain requests that are associated with the request user and exclude the APPROVED ones"""
|
||||||
|
|
||||||
if not request.user.is_authenticated:
|
|
||||||
return JsonResponse({"error": "User not authenticated"}, status=401)
|
|
||||||
|
|
||||||
domain_requests = DomainRequest.objects.filter(creator=request.user).exclude(
|
domain_requests = DomainRequest.objects.filter(creator=request.user).exclude(
|
||||||
status=DomainRequest.DomainRequestStatus.APPROVED
|
status=DomainRequest.DomainRequestStatus.APPROVED
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from registrar.models import UserDomainRole, Domain
|
from registrar.models import UserDomainRole, Domain
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
||||||
|
@login_required
|
||||||
def get_domains_json(request):
|
def get_domains_json(request):
|
||||||
"""Given the current request,
|
"""Given the current request,
|
||||||
get all domains that are associated with the UserDomainRole object"""
|
get all domains that are associated with the UserDomainRole object"""
|
||||||
|
|
||||||
if not request.user.is_authenticated:
|
|
||||||
return JsonResponse({"error": "User not authenticated"}, status=401)
|
|
||||||
|
|
||||||
user_domain_roles = UserDomainRole.objects.filter(user=request.user)
|
user_domain_roles = UserDomainRole.objects.filter(user=request.user)
|
||||||
domain_ids = user_domain_roles.values_list("domain_id", flat=True)
|
domain_ids = user_domain_roles.values_list("domain_id", flat=True)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue