Skip to content

Commit

Permalink
merged to main
Browse files Browse the repository at this point in the history
  • Loading branch information
asaki222 committed Oct 28, 2024
2 parents b5f705f + c787d82 commit 4d8e6b7
Show file tree
Hide file tree
Showing 22 changed files with 1,581 additions and 477 deletions.
184 changes: 153 additions & 31 deletions src/registrar/assets/js/get-gov.js
Original file line number Diff line number Diff line change
Expand Up @@ -1003,25 +1003,24 @@ function unloadModals() {
}

class LoadTableBase {
constructor(tableSelector, tableWrapperSelector, searchFieldId, searchSubmitId, resetSearchBtn, resetFiltersBtn, noDataDisplay, noSearchresultsDisplay) {
this.tableWrapper = document.querySelector(tableWrapperSelector);
this.tableHeaders = document.querySelectorAll(`${tableSelector} th[data-sortable]`);
constructor(sectionSelector) {
this.tableWrapper = document.getElementById(`${sectionSelector}__table-wrapper`);
this.tableHeaders = document.querySelectorAll(`#${sectionSelector} th[data-sortable]`);
this.currentSortBy = 'id';
this.currentOrder = 'asc';
this.currentStatus = [];
this.currentSearchTerm = '';
this.scrollToTable = false;
this.searchInput = document.querySelector(searchFieldId);
this.searchSubmit = document.querySelector(searchSubmitId);
this.tableAnnouncementRegion = document.querySelector(`${tableWrapperSelector} .usa-table__announcement-region`);
this.resetSearchButton = document.querySelector(resetSearchBtn);
this.resetFiltersButton = document.querySelector(resetFiltersBtn);
// NOTE: these 3 can't be used if filters are active on a page with more than 1 table
this.statusCheckboxes = document.querySelectorAll('input[name="filter-status"]');
this.statusIndicator = document.querySelector('.filter-indicator');
this.statusToggle = document.querySelector('.usa-button--filter');
this.noTableWrapper = document.querySelector(noDataDisplay);
this.noSearchResultsWrapper = document.querySelector(noSearchresultsDisplay);
this.searchInput = document.getElementById(`${sectionSelector}__search-field`);
this.searchSubmit = document.getElementById(`${sectionSelector}__search-field-submit`);
this.tableAnnouncementRegion = document.getElementById(`${sectionSelector}__usa-table__announcement-region`);
this.resetSearchButton = document.getElementById(`${sectionSelector}__reset-search`);
this.resetFiltersButton = document.getElementById(`${sectionSelector}__reset-filters`);
this.statusCheckboxes = document.querySelectorAll(`.${sectionSelector} input[name="filter-status"]`);
this.statusIndicator = document.getElementById(`${sectionSelector}__filter-indicator`);
this.statusToggle = document.getElementById(`${sectionSelector}__usa-button--filter`);
this.noTableWrapper = document.getElementById(`${sectionSelector}__no-data`);
this.noSearchResultsWrapper = document.getElementById(`${sectionSelector}__no-search-results`);
this.portfolioElement = document.getElementById('portfolio-js-value');
this.portfolioValue = this.portfolioElement ? this.portfolioElement.getAttribute('data-portfolio') : null;
this.initializeTableHeaders();
Expand Down Expand Up @@ -1363,7 +1362,7 @@ class LoadTableBase {
class DomainsTable extends LoadTableBase {

constructor() {
super('.domains__table', '.domains__table-wrapper', '#domains__search-field', '#domains__search-field-submit', '.domains__reset-search', '.domains__reset-filters', '.domains__no-data', '.domains__no-search-results');
super('domains');
}
/**
* Loads rows in the domains list, as well as updates pagination around the domains list
Expand Down Expand Up @@ -1415,7 +1414,7 @@ class DomainsTable extends LoadTableBase {
this.updateDisplay(data, this.tableWrapper, this.noTableWrapper, this.noSearchResultsWrapper, this.currentSearchTerm);

// identify the DOM element where the domain list will be inserted into the DOM
const domainList = document.querySelector('.domains__table tbody');
const domainList = document.querySelector('#domains tbody');
domainList.innerHTML = '';

data.domains.forEach(domain => {
Expand Down Expand Up @@ -1501,7 +1500,7 @@ class DomainsTable extends LoadTableBase {
class DomainRequestsTable extends LoadTableBase {

constructor() {
super('.domain-requests__table', '.domain-requests__table-wrapper', '#domain-requests__search-field', '#domain-requests__search-field-submit', '.domain-requests__reset-search', '.domain-requests__reset-filters', '.domain-requests__no-data', '.domain-requests__no-search-results');
super('domain-requests');
}

toggleExportButton(requests) {
Expand Down Expand Up @@ -1567,7 +1566,7 @@ class DomainRequestsTable extends LoadTableBase {
this.updateDisplay(data, this.tableWrapper, this.noTableWrapper, this.noSearchResultsWrapper, this.currentSearchTerm);

// identify the DOM element where the domain request list will be inserted into the DOM
const tbody = document.querySelector('.domain-requests__table tbody');
const tbody = document.querySelector('#domain-requests tbody');
tbody.innerHTML = '';

// Unload modals will re-inject the DOM with the initial placeholders to allow for .on() in regular use cases
Expand Down Expand Up @@ -1599,7 +1598,7 @@ class DomainRequestsTable extends LoadTableBase {
delheader.setAttribute('class', 'delete-header');
delheader.innerHTML = `
<span class="usa-sr-only">Delete Action</span>`;
let tableHeaderRow = document.querySelector('.domain-requests__table thead tr');
let tableHeaderRow = document.querySelector('#domain-requests thead tr');
tableHeaderRow.appendChild(delheader);
}
}
Expand Down Expand Up @@ -1872,7 +1871,7 @@ class DomainRequestsTable extends LoadTableBase {
class MembersTable extends LoadTableBase {

constructor() {
super('.members__table', '.members__table-wrapper', '#members__search-field', '#members__search-field-submit', '.members__reset-search', '.members__reset-filters', '.members__no-data', '.members__no-search-results');
super('members');
}

/**
Expand Down Expand Up @@ -1973,7 +1972,7 @@ class MembersTable extends LoadTableBase {
* @param {Array} domain_urls - An array of corresponding domain URLs.
* @returns {string} - A string of HTML displaying the domains assigned to the member.
*/
generateDomainsHTML(num_domains, domain_names, domain_urls) {
generateDomainsHTML(num_domains, domain_names, domain_urls, action_url) {
// Initialize an empty string for the HTML
let domainsHTML = '';

Expand All @@ -1993,7 +1992,7 @@ class MembersTable extends LoadTableBase {

// If there are more than 6 domains, display a "View assigned domains" link
if (num_domains >= 6) {
domainsHTML += "<p><a href='#'>View assigned domains</a></p>";
domainsHTML += `<p><a href="${action_url}/domains">View assigned domains</a></p>`;
}

domainsHTML += "</div>";
Expand Down Expand Up @@ -2091,7 +2090,7 @@ class MembersTable extends LoadTableBase {


// --------- FETCH DATA
// fetch json of page of domais, given params
// fetch json of page of domains, given params
let baseUrl = document.getElementById("get_members_json_url");
if (!baseUrl) {
return;
Expand All @@ -2115,7 +2114,7 @@ class MembersTable extends LoadTableBase {
this.updateDisplay(data, this.tableWrapper, this.noTableWrapper, this.noSearchResultsWrapper, this.currentSearchTerm);

// identify the DOM element where the domain list will be inserted into the DOM
const memberList = document.querySelector('.members__table tbody');
const memberList = document.querySelector('#members tbody');
memberList.innerHTML = '';

const UserPortfolioPermissionChoices = data.UserPortfolioPermissionChoices;
Expand Down Expand Up @@ -2144,7 +2143,7 @@ class MembersTable extends LoadTableBase {
admin_tagHTML = `<span class="usa-tag margin-left-1 bg-primary">Admin</span>`

// generate html blocks for domains and permissions for the member
let domainsHTML = this.generateDomainsHTML(num_domains, domain_names, domain_urls);
let domainsHTML = this.generateDomainsHTML(num_domains, domain_names, domain_urls, action_url);
let permissionsHTML = this.generatePermissionsHTML(member_permissions, UserPortfolioPermissionChoices);

// domainsHTML block and permissionsHTML block need to be wrapped with hide/show toggle, Expand
Expand Down Expand Up @@ -2220,14 +2219,121 @@ class MembersTable extends LoadTableBase {
}
}

class MemberDomainsTable extends LoadTableBase {

constructor() {
super('member-domains');
this.currentSortBy = 'name';
}
/**
* Loads rows in the members list, as well as updates pagination around the members list
* based on the supplied attributes.
* @param {*} page - the page number of the results (starts with 1)
* @param {*} sortBy - the sort column option
* @param {*} order - the sort order {asc, desc}
* @param {*} scroll - control for the scrollToElement functionality
* @param {*} searchTerm - the search term
* @param {*} portfolio - the portfolio id
*/
loadTable(page, sortBy = this.currentSortBy, order = this.currentOrder, scroll = this.scrollToTable, searchTerm =this.currentSearchTerm, portfolio = this.portfolioValue) {

// --------- SEARCH
let searchParams = new URLSearchParams(
{
"page": page,
"sort_by": sortBy,
"order": order,
"search_term": searchTerm,
}
);

let emailValue = this.portfolioElement ? this.portfolioElement.getAttribute('data-email') : null;
let memberIdValue = this.portfolioElement ? this.portfolioElement.getAttribute('data-member-id') : null;
let memberOnly = this.portfolioElement ? this.portfolioElement.getAttribute('data-member-only') : null;

if (portfolio)
searchParams.append("portfolio", portfolio)
if (emailValue)
searchParams.append("email", emailValue)
if (memberIdValue)
searchParams.append("member_id", memberIdValue)
if (memberOnly)
searchParams.append("member_only", memberOnly)


// --------- FETCH DATA
// fetch json of page of domais, given params
let baseUrl = document.getElementById("get_member_domains_json_url");
if (!baseUrl) {
return;
}

let baseUrlValue = baseUrl.innerHTML;
if (!baseUrlValue) {
return;
}

let url = `${baseUrlValue}?${searchParams.toString()}` //TODO: uncomment for search function
fetch(url)
.then(response => response.json())
.then(data => {
if (data.error) {
console.error('Error in AJAX call: ' + data.error);
return;
}

// handle the display of proper messaging in the event that no members exist in the list or search returns no results
this.updateDisplay(data, this.tableWrapper, this.noTableWrapper, this.noSearchResultsWrapper, this.currentSearchTerm);

// identify the DOM element where the domain list will be inserted into the DOM
const memberDomainsList = document.querySelector('#member-domains tbody');
memberDomainsList.innerHTML = '';


data.domains.forEach(domain => {
const row = document.createElement('tr');

row.innerHTML = `
<td scope="row" data-label="Domain name">
${domain.name}
</td>
`;
memberDomainsList.appendChild(row);
});

// Do not scroll on first page load
if (scroll)
ScrollToElement('class', 'member-domains');
this.scrollToTable = true;

// update pagination
this.updatePagination(
'member domain',
'#member-domains-pagination',
'#member-domains-pagination .usa-pagination__counter',
'#member-domains',
data.page,
data.num_pages,
data.has_previous,
data.has_next,
data.total,
);
this.currentSortBy = sortBy;
this.currentOrder = order;
this.currentSearchTerm = searchTerm;
})
.catch(error => console.error('Error fetching domains:', error));
}
}


/**
* An IIFE that listens for DOM Content to be loaded, then executes. This function
* initializes the domains list and associated functionality on the home page of the app.
* initializes the domains list and associated functionality.
*
*/
document.addEventListener('DOMContentLoaded', function() {
const isDomainsPage = document.querySelector("#domains")
const isDomainsPage = document.getElementById("domains")
if (isDomainsPage){
const domainsTable = new DomainsTable();
if (domainsTable.tableWrapper) {
Expand All @@ -2239,11 +2345,11 @@ document.addEventListener('DOMContentLoaded', function() {

/**
* An IIFE that listens for DOM Content to be loaded, then executes. This function
* initializes the domain requests list and associated functionality on the home page of the app.
* initializes the domain requests list and associated functionality.
*
*/
document.addEventListener('DOMContentLoaded', function() {
const domainRequestsSectionWrapper = document.querySelector('.domain-requests');
const domainRequestsSectionWrapper = document.getElementById('domain-requests');
if (domainRequestsSectionWrapper) {
const domainRequestsTable = new DomainRequestsTable();
if (domainRequestsTable.tableWrapper) {
Expand Down Expand Up @@ -2296,11 +2402,11 @@ const utcDateString = (dateString) => {

/**
* An IIFE that listens for DOM Content to be loaded, then executes. This function
* initializes the domains list and associated functionality on the home page of the app.
* initializes the members list and associated functionality.
*
*/
document.addEventListener('DOMContentLoaded', function() {
const isMembersPage = document.querySelector("#members")
const isMembersPage = document.getElementById("members")
if (isMembersPage){
const membersTable = new MembersTable();
if (membersTable.tableWrapper) {
Expand All @@ -2310,6 +2416,22 @@ document.addEventListener('DOMContentLoaded', function() {
}
});

/**
* An IIFE that listens for DOM Content to be loaded, then executes. This function
* initializes the member domains list and associated functionality.
*
*/
document.addEventListener('DOMContentLoaded', function() {
const isMemberDomainsPage = document.getElementById("member-domains")
if (isMemberDomainsPage){
const memberDomainsTable = new MemberDomainsTable();
if (memberDomainsTable.tableWrapper) {
// Initial load
memberDomainsTable.loadTable(1);
}
}
});

/**
* An IIFE that displays confirmation modal on the user profile page
*/
Expand Down
11 changes: 11 additions & 0 deletions src/registrar/assets/sass/_theme/_search.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@use "base" as *;

.usa-search--show-label {
flex-wrap: wrap;
label {
width: 100%;
}
.usa-search--show-label__input-wrapper {
flex: 1;
}
}
1 change: 1 addition & 0 deletions src/registrar/assets/sass/_theme/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
@forward "buttons";
@forward "pagination";
@forward "forms";
@forward "search";
@forward "tooltips";
@forward "fieldsets";
@forward "alerts";
Expand Down
14 changes: 12 additions & 2 deletions src/registrar/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
# --jsons
from registrar.views.domain_requests_json import get_domain_requests_json
from registrar.views.domains_json import get_domains_json
from registrar.views.portfolio_members_json import get_portfolio_members_json
from registrar.views.utility.api_views import (
get_senior_official_from_federal_agency_json,
get_federal_and_portfolio_types_from_federal_agency_json,
Expand Down Expand Up @@ -96,6 +95,11 @@
views.PortfolioMemberEditView.as_view(),
name="member-permissions",
),
path(
"member/<int:pk>/domains",
views.PortfolioMemberDomainsView.as_view(),
name="member-domains",
),
path(
"invitedmember/<int:pk>",
views.PortfolioInvitedMemberView.as_view(),
Expand All @@ -106,6 +110,11 @@
views.PortfolioInvitedMemberEditView.as_view(),
name="invitedmember-permissions",
),
path(
"invitedmember/<int:pk>/domains",
views.PortfolioInvitedMemberDomainsView.as_view(),
name="invitedmember-domains",
),
# path(
# "no-organization-members/",
# views.PortfolioNoMembersView.as_view(),
Expand Down Expand Up @@ -328,7 +337,8 @@
),
path("get-domains-json/", get_domains_json, name="get_domains_json"),
path("get-domain-requests-json/", get_domain_requests_json, name="get_domain_requests_json"),
path("get-portfolio-members-json/", get_portfolio_members_json, name="get_portfolio_members_json"),
path("get-portfolio-members-json/", views.PortfolioMembersJson.as_view(), name="get_portfolio_members_json"),
path("get-member-domains-json/", views.PortfolioMemberDomainsJson.as_view(), name="get_member_domains_json"),
]

# Djangooidc strips out context data from that context, so we define a custom error
Expand Down
10 changes: 8 additions & 2 deletions src/registrar/fixtures/fixtures_domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,18 @@ def _approve_domain_requests(cls, users):

# Approve the current domain request
if domain_request:
cls._approve_request(domain_request, users)
try:
cls._approve_request(domain_request, users)
except Exception as err:
logger.warning(f"Cannot approve domain request in fixtures: {err}")
domain_requests_to_update.append(domain_request)

# Approve the expired domain request
if domain_request_expired:
cls._approve_request(domain_request_expired, users)
try:
cls._approve_request(domain_request_expired, users)
except Exception as err:
logger.warning(f"Cannot approve domain request (expired) in fixtures: {err}")
domain_requests_to_update.append(domain_request_expired)
expired_requests.append(domain_request_expired)

Expand Down
Loading

0 comments on commit 4d8e6b7

Please sign in to comment.