From 5e6f405b95f38d4be26011c41d7ba8a88f481397 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Wed, 5 Jun 2024 01:19:47 -0400
Subject: [PATCH] implement seach on domains and requests
---
src/registrar/assets/js/get-gov.js | 134 +++++++++++++-----
src/registrar/assets/js/uswds-edited.js | 8 +-
src/registrar/assets/sass/_theme/_tables.scss | 4 +-
src/registrar/templates/home.html | 80 +++++++++--
src/registrar/views/domain_requests_json.py | 11 ++
src/registrar/views/domains_json.py | 9 ++
6 files changed, 197 insertions(+), 49 deletions(-)
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index 0d594b315..cc24f7df7 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -918,8 +918,9 @@ function ScrollToElement(attributeName, attributeValue) {
* @param {boolean} hasPrevious - Whether there is a page before the current page.
* @param {boolean} hasNext - Whether there is a page after the current page.
* @param {number} totalItems - The total number of items.
+ * @param {string} searchTerm - The search term
*/
-function updatePagination(itemName, paginationSelector, counterSelector, headerAnchor, loadPageFunction, currentPage, numPages, hasPrevious, hasNext, totalItems) {
+function updatePagination(itemName, paginationSelector, counterSelector, headerAnchor, loadPageFunction, currentPage, numPages, hasPrevious, hasNext, totalItems, searchTerm) {
const paginationContainer = document.querySelector(paginationSelector);
const paginationCounter = document.querySelector(counterSelector);
const paginationButtons = document.querySelector(`${paginationSelector} .usa-pagination__list`);
@@ -932,7 +933,7 @@ function updatePagination(itemName, paginationSelector, counterSelector, headerA
// Counter should only be displayed if there is more than 1 item
paginationContainer.classList.toggle('display-none', totalItems < 1);
- paginationCounter.innerHTML = `${totalItems} ${itemName}${totalItems > 1 ? 's' : ''}`;
+ paginationCounter.innerHTML = `${totalItems} ${itemName}${totalItems > 1 ? 's' : ''}${searchTerm ? ' for ' + searchTerm : ''}`;
if (hasPrevious) {
const prevPageItem = document.createElement('li');
@@ -1018,6 +1019,28 @@ function updatePagination(itemName, paginationSelector, counterSelector, headerA
}
}
+const updateDisplay = (data, dataWrapper, noDataWrapper, noSearchResultsWrapper) => {
+ const { unfiltered_total, total } = data;
+
+ const showElement = (element) => element.classList.remove('display-none');
+ const hideElement = (element) => element.classList.add('display-none');
+
+ if (unfiltered_total) {
+ if (total) {
+ showElement(dataWrapper);
+ hideElement(noSearchResultsWrapper);
+ hideElement(noDataWrapper);
+ } else {
+ hideElement(dataWrapper);
+ showElement(noSearchResultsWrapper);
+ hideElement(noDataWrapper);
+ }
+ } else {
+ hideElement(dataWrapper);
+ hideElement(noSearchResultsWrapper);
+ showElement(noDataWrapper);
+ }
+};
/**
* An IIFE that listens for DOM Content to be loaded, then executes. This function
@@ -1025,13 +1048,19 @@ function updatePagination(itemName, paginationSelector, counterSelector, headerA
*
*/
document.addEventListener('DOMContentLoaded', function() {
- let domainsWrapper = document.querySelector('.domains-wrapper');
+ let domainsWrapper = document.querySelector('.domains__table-wrapper');
if (domainsWrapper) {
let currentSortBy = 'id';
let currentOrder = 'asc';
- let noDomainsWrapper = document.querySelector('.no-domains-wrapper');
+ let noDomainsWrapper = document.querySelector('.domains__no-data');
+ let noSearchResultsWrapper = document.querySelector('.domains__no-search-results');
let hasLoaded = false;
+ let currentSearchTerm = ''
+ let domainsSearchInput = document.getElementById('domains__search-field');
+ let domainsSearchSubmit = document.getElementById('domains__search-field-submit');
+ let tableHeaders = document.querySelectorAll('.domains__table th[data-sortable]');
+ let tableAnnouncementRegion = document.querySelector('.domains__table-wrapper .usa-table__announcement-region')
/**
* Loads rows in the domains list, as well as updates pagination around the domains list
@@ -1040,10 +1069,11 @@ document.addEventListener('DOMContentLoaded', function() {
* @param {*} sortBy - the sort column option
* @param {*} order - the sort order {asc, desc}
* @param {*} loaded - control for the scrollToElement functionality
+ * @param {*} searchTerm - the search term
*/
- function loadDomains(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) {
+ function loadDomains(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded, searchTerm = currentSearchTerm) {
//fetch json of page of domains, given page # and sort
- fetch(`/get-domains-json/?page=${page}&sort_by=${sortBy}&order=${order}`)
+ fetch(`/get-domains-json/?page=${page}&sort_by=${sortBy}&order=${order}&search_term=${searchTerm}`)
.then(response => response.json())
.then(data => {
if (data.error) {
@@ -1051,17 +1081,11 @@ document.addEventListener('DOMContentLoaded', function() {
return;
}
- // handle the display of proper messaging in the event that no domains exist in the list
- if (data.domains.length) {
- domainsWrapper.classList.remove('display-none');
- noDomainsWrapper.classList.add('display-none');
- } else {
- domainsWrapper.classList.add('display-none');
- noDomainsWrapper.classList.remove('display-none');
- }
+ // handle the display of proper messaging in the event that no domains exist in the list or search returns no results
+ updateDisplay(data, domainsWrapper, noDomainsWrapper, noSearchResultsWrapper);
// identify the DOM element where the domain list will be inserted into the DOM
- const domainList = document.querySelector('.dotgov-table__registered-domains tbody');
+ const domainList = document.querySelector('.domains__table tbody');
domainList.innerHTML = '';
data.domains.forEach(domain => {
@@ -1122,7 +1146,8 @@ document.addEventListener('DOMContentLoaded', function() {
data.num_pages,
data.has_previous,
data.has_next,
- data.total
+ data.total,
+ currentSearchTerm
);
currentSortBy = sortBy;
currentOrder = order;
@@ -1133,7 +1158,7 @@ document.addEventListener('DOMContentLoaded', function() {
// Add event listeners to table headers for sorting
- document.querySelectorAll('.dotgov-table__registered-domains th[data-sortable]').forEach(header => {
+ tableHeaders.forEach(header => {
header.addEventListener('click', function() {
const sortBy = this.getAttribute('data-sortable');
let order = 'asc';
@@ -1147,6 +1172,23 @@ document.addEventListener('DOMContentLoaded', function() {
});
});
+ domainsSearchSubmit.addEventListener('click', function(e) {
+ e.preventDefault();
+ currentSearchTerm = domainsSearchInput.value;
+ loadDomains(1, 'id', 'asc');
+ resetheaders();
+ })
+
+ // Reset UI and accessibility
+ function resetheaders() {
+ tableHeaders.forEach(header => {
+ // unset sort UI in headers
+ window.table.unsetHeader(header);
+ });
+ // Reset the announcement region
+ tableAnnouncementRegion.innerHTML = '';
+ }
+
// Load the first page initially
loadDomains(1);
}
@@ -1157,10 +1199,13 @@ const utcDateString = (dateString) => {
const utcYear = date.getUTCFullYear();
const utcMonth = date.toLocaleString('en-US', { month: 'short', timeZone: 'UTC' });
const utcDay = date.getUTCDate().toString().padStart(2, '0');
- const utcHours = date.getUTCHours().toString().padStart(2, '0');
+ let utcHours = date.getUTCHours();
const utcMinutes = date.getUTCMinutes().toString().padStart(2, '0');
-
- return `${utcMonth} ${utcDay}, ${utcYear}, ${utcHours}:${utcMinutes} UTC`;
+
+ const ampm = utcHours >= 12 ? 'PM' : 'AM';
+ utcHours = utcHours % 12 || 12; // Convert to 12-hour format, '0' hours should be '12'
+
+ return `${utcMonth} ${utcDay}, ${utcYear}, ${utcHours}:${utcMinutes} ${ampm} UTC`;
};
/**
@@ -1169,13 +1214,19 @@ const utcDateString = (dateString) => {
*
*/
document.addEventListener('DOMContentLoaded', function() {
- let domainRequestsWrapper = document.querySelector('.domain-requests-wrapper');
+ let domainRequestsWrapper = document.querySelector('.domain-requests__table-wrapper');
if (domainRequestsWrapper) {
let currentSortBy = 'id';
let currentOrder = 'asc';
- let noDomainRequestsWrapper = document.querySelector('.no-domain-requests-wrapper');
+ let noDomainRequestsWrapper = document.querySelector('.domain-requests__no-data');
+ let noSearchResultsWrapper = document.querySelector('.domain-requests__no-search-results');
let hasLoaded = false;
+ let currentSearchTerm = ''
+ let domainRequestsSearchInput = document.getElementById('domain-requests__search-field');
+ let domainRequestsSearchSubmit = document.getElementById('domain-requests__search-field-submit');
+ let tableHeaders = document.querySelectorAll('.domain-requests__table th[data-sortable]');
+ let tableAnnouncementRegion = document.querySelector('.domain-requests__table-wrapper .usa-table__announcement-region')
/**
* Loads rows in the domain requests list, as well as updates pagination around the domain requests list
@@ -1184,10 +1235,11 @@ document.addEventListener('DOMContentLoaded', function() {
* @param {*} sortBy - the sort column option
* @param {*} order - the sort order {asc, desc}
* @param {*} loaded - control for the scrollToElement functionality
+ * @param {*} searchTerm - the search term
*/
- function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) {
+ function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded, searchTerm = currentSearchTerm) {
//fetch json of page of domain requests, given page # and sort
- fetch(`/get-domain-requests-json/?page=${page}&sort_by=${sortBy}&order=${order}`)
+ fetch(`/get-domain-requests-json/?page=${page}&sort_by=${sortBy}&order=${order}&search_term=${searchTerm}`)
.then(response => response.json())
.then(data => {
if (data.error) {
@@ -1195,17 +1247,11 @@ document.addEventListener('DOMContentLoaded', function() {
return;
}
- // handle the display of proper messaging in the event that no domain requests exist in the list
- if (data.domain_requests.length) {
- domainRequestsWrapper.classList.remove('display-none');
- noDomainRequestsWrapper.classList.add('display-none');
- } else {
- domainRequestsWrapper.classList.add('display-none');
- noDomainRequestsWrapper.classList.remove('display-none');
- }
+ // handle the display of proper messaging in the event that no requests exist in the list or search returns no results
+ updateDisplay(data, domainRequestsWrapper, noDomainRequestsWrapper, noSearchResultsWrapper);
// identify the DOM element where the domain request list will be inserted into the DOM
- const tbody = document.querySelector('.dotgov-table__domain-requests tbody');
+ const tbody = document.querySelector('.domain-requests__table tbody');
tbody.innerHTML = '';
// remove any existing modal elements from the DOM so they can be properly re-initialized
@@ -1272,7 +1318,8 @@ document.addEventListener('DOMContentLoaded', function() {
data.num_pages,
data.has_previous,
data.has_next,
- data.total
+ data.total,
+ currentSearchTerm
);
currentSortBy = sortBy;
currentOrder = order;
@@ -1281,7 +1328,7 @@ document.addEventListener('DOMContentLoaded', function() {
}
// Add event listeners to table headers for sorting
- document.querySelectorAll('.dotgov-table__domain-requests th[data-sortable]').forEach(header => {
+ tableHeaders.forEach(header => {
header.addEventListener('click', function() {
const sortBy = this.getAttribute('data-sortable');
let order = 'asc';
@@ -1294,6 +1341,23 @@ document.addEventListener('DOMContentLoaded', function() {
});
});
+ domainRequestsSearchSubmit.addEventListener('click', function(e) {
+ e.preventDefault();
+ currentSearchTerm = domainRequestsSearchInput.value;
+ loadDomainRequests(1, 'id', 'asc');
+ resetheaders();
+ })
+
+ // Reset UI and accessibility
+ function resetheaders() {
+ tableHeaders.forEach(header => {
+ // unset sort UI in headers
+ window.table.unsetHeader(header);
+ });
+ // Reset the announcement region
+ tableAnnouncementRegion.innerHTML = '';
+ }
+
// Load the first page initially
loadDomainRequests(1);
}
diff --git a/src/registrar/assets/js/uswds-edited.js b/src/registrar/assets/js/uswds-edited.js
index e73f3b6c0..556488554 100644
--- a/src/registrar/assets/js/uswds-edited.js
+++ b/src/registrar/assets/js/uswds-edited.js
@@ -5709,9 +5709,15 @@ const table = behavior({
},
TABLE,
SORTABLE_HEADER,
- SORT_BUTTON
+ SORT_BUTTON,
+ // DOTGOV: Export unsetSort
+ unsetHeader(header) {
+ unsetSort(header);
+ }
});
module.exports = table;
+// DOTGOV: modified uswds.js to add table module to window so that it is accessible to other js
+window.table = table;
},{"../../uswds-core/src/js/config":35,"../../uswds-core/src/js/events":36,"../../uswds-core/src/js/utils/behavior":45,"../../uswds-core/src/js/utils/sanitizer":50,"../../uswds-core/src/js/utils/select":53}],32:[function(require,module,exports){
"use strict";
diff --git a/src/registrar/assets/sass/_theme/_tables.scss b/src/registrar/assets/sass/_theme/_tables.scss
index 26d90d291..a5eb5a4e0 100644
--- a/src/registrar/assets/sass/_theme/_tables.scss
+++ b/src/registrar/assets/sass/_theme/_tables.scss
@@ -98,7 +98,7 @@
}
}
@media (min-width: 1040px){
- .dotgov-table__domain-requests {
+ .domain-requests__table {
th:nth-of-type(1) {
width: 200px;
}
@@ -122,7 +122,7 @@
}
@media (min-width: 1040px){
- .dotgov-table__registered-domains {
+ .domains__table {
th:nth-of-type(1) {
width: 200px;
}
diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html
index fd54769a8..c3877ca3f 100644
--- a/src/registrar/templates/home.html
+++ b/src/registrar/templates/home.html
@@ -23,10 +23,35 @@
-
- Domains
-
-
+
+
+
+
Your registered domains
@@ -50,7 +75,7 @@
aria-live="polite"
>
-
+
You don't have any registered domains.
@@ -61,6 +86,10 @@
+
+
Nothing, nada, zilch.
+
Reset your search or try a different search term.
+
-
- Domain requests
-
-
+
+
+
+
Domain requests
+
+
+
+
+
Your domain requests
@@ -129,9 +183,13 @@
{% endfor %}
-
+
You haven't requested any domains.
-
+
+
+
Nothing, nada, zilch.
+
Reset your search or try a different search term.
+