This commit is contained in:
Rachid Mrad 2024-10-18 18:22:07 -04:00
parent 71db456200
commit a8fec4fcca
No known key found for this signature in database
4 changed files with 169 additions and 65 deletions

View file

@ -1899,7 +1899,7 @@ class MembersTable extends LoadTableBase {
// --------- FETCH DATA // --------- 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"); let baseUrl = document.getElementById("get_members_json_url");
if (!baseUrl) { if (!baseUrl) {
return; return;
@ -2014,14 +2014,120 @@ class MembersTable extends LoadTableBase {
} }
} }
class MemberDomainsTable extends LoadTableBase {
constructor() {
super('.member-domains__table', '.member-domains__table-wrapper', '#member-domains__search-field', '#member-domains__search-field-submit', '.member-domains__reset-search', '.member-domains__reset-filters', '.member-domains__no-data', '.member-domains__no-search-results');
}
/**
* 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 = 'name', 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__table 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 * 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() { document.addEventListener('DOMContentLoaded', function() {
const isDomainsPage = document.querySelector("#domains") const isDomainsPage = document.getElementById("domains")
if (isDomainsPage){ if (isDomainsPage){
const domainsTable = new DomainsTable(); const domainsTable = new DomainsTable();
if (domainsTable.tableWrapper) { if (domainsTable.tableWrapper) {
@ -2033,11 +2139,11 @@ document.addEventListener('DOMContentLoaded', function() {
/** /**
* An IIFE that listens for DOM Content to be loaded, then executes. This 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() { document.addEventListener('DOMContentLoaded', function() {
const domainRequestsSectionWrapper = document.querySelector('.domain-requests'); const domainRequestsSectionWrapper = document.getElementById('domain-requests');
if (domainRequestsSectionWrapper) { if (domainRequestsSectionWrapper) {
const domainRequestsTable = new DomainRequestsTable(); const domainRequestsTable = new DomainRequestsTable();
if (domainRequestsTable.tableWrapper) { if (domainRequestsTable.tableWrapper) {
@ -2090,11 +2196,11 @@ const utcDateString = (dateString) => {
/** /**
* An IIFE that listens for DOM Content to be loaded, then executes. This function * 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() { document.addEventListener('DOMContentLoaded', function() {
const isMembersPage = document.querySelector("#members") const isMembersPage = document.getElementById("members")
if (isMembersPage){ if (isMembersPage){
const membersTable = new MembersTable(); const membersTable = new MembersTable();
if (membersTable.tableWrapper) { if (membersTable.tableWrapper) {
@ -2104,6 +2210,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 * An IIFE that displays confirmation modal on the user profile page
*/ */

View file

@ -1,8 +1,37 @@
{% load static %} {% load static %}
<section class="section-outlined margin-top-0 section-outlined--border-base-light"> {% if member %}
<span
id="portfolio-js-value"
class="display-none"
data-portfolio="{{ portfolio.id }}"
data-email=""
data-member-id="{{ member.id }}"
data-member-only="true"
></span>
{% else %}
<span
id="portfolio-js-value"
class="display-none"
data-portfolio="{{ portfolio.id }}"
data-email="{{ portfolio_invitation.email }}"
data-member-id=""
data-member-only="true"
></span>
{% endif %}
{% comment %} Stores the json endpoint in a url for easier access {% endcomment %}
{% url 'get_member_domains_json' as url %}
<span id="get_member_domains_json_url" class="display-none">{{url}}</span>
<section class="section-outlined member-domains margin-top-0 section-outlined--border-base-light" id="member-domains">
<h2> <h2>
Domains assigned to {{ email }} Domains assigned to
{% if member %}
{{ member.email }}
{% else %}
{{ portfolio_invitation.email }}
{% endif %}
</h2> </h2>
<div class="section-outlined__header margin-bottom-3 grid-row"> <div class="section-outlined__header margin-bottom-3 grid-row">
@ -25,7 +54,7 @@
</button> </button>
<input <input
class="usa-input" class="usa-input"
id="members__search-field" id="member-domains__search-field"
type="search" type="search"
name="search" name="search"
/> />
@ -49,7 +78,7 @@
<caption class="sr-only">member domains</caption> <caption class="sr-only">member domains</caption>
<thead> <thead>
<tr> <tr>
<th data-sortable="domain" scope="col" role="columnheader">Domains</th> <th data-sortable="name" scope="col" role="columnheader" aria-sort="descending">Domains</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View file

@ -48,17 +48,7 @@
A domain manager can be assigned to any domain across the organization. Domain managers can change domain information, adjust DNS settings, and invite or assign other domain managers to their assigned domains. A domain manager can be assigned to any domain across the organization. Domain managers can change domain information, adjust DNS settings, and invite or assign other domain managers to their assigned domains.
</p> </p>
{% if member %} {% include "includes/member_domains_table.html" %}
{% with member.email as email %}
{% include "includes/member_domains_table.html" with email=email %}
{% endwith %}
{% else %}
{% with portfolio_invitation.email as email %}
{% include "includes/member_domains_table.html" with email=email %}
{% endwith %}
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -27,7 +27,6 @@ class PortfolioMemberDomainsJson(PortfolioMemberDomainsPermission, View):
unfiltered_total = objects.count() unfiltered_total = objects.count()
objects = self.apply_search(objects, request) objects = self.apply_search(objects, request)
objects = self.apply_state_filter(objects, request)
objects = self.apply_sorting(objects, request) objects = self.apply_sorting(objects, request)
paginator = Paginator(objects, 10) paginator = Paginator(objects, 10)
@ -53,14 +52,14 @@ class PortfolioMemberDomainsJson(PortfolioMemberDomainsPermission, View):
"""Get domain ids from request. """Get domain ids from request.
request.get.email - email address of invited member request.get.email - email address of invited member
request.get.member - member id of member request.get.member_id - member id of member
request.get.portfolio - portfolio id of portfolio request.get.portfolio - portfolio id of portfolio
request.get.member_only - whether to return only domains associated with member request.get.member_only - whether to return only domains associated with member
or to return all domains in the portfolio or to return all domains in the portfolio
""" """
portfolio = request.GET.get("portfolio") portfolio = request.GET.get("portfolio")
email = request.GET.get("email") email = request.GET.get("email")
member_id = request.GET.get("member") member_id = request.GET.get("member_id")
member_only = request.GET.get("member_only", "false").lower() in ["true", "1"] member_only = request.GET.get("member_only", "false").lower() in ["true", "1"]
if member_only: if member_only:
if member_id: if member_id:
@ -86,45 +85,9 @@ class PortfolioMemberDomainsJson(PortfolioMemberDomainsPermission, View):
return queryset return queryset
def apply_state_filter(self, queryset, request):
status_param = request.GET.get("status")
if status_param:
status_list = status_param.split(",")
# if unknown is in status_list, append 'dns needed' since both
# unknown and dns needed display as DNS Needed, and both are
# searchable via state parameter of 'unknown'
if "unknown" in status_list:
status_list.append("dns needed")
# Split the status list into normal states and custom states
normal_states = [state for state in status_list if state in Domain.State.values]
custom_states = [state for state in status_list if state == "expired"]
# Construct Q objects for normal states that can be queried through ORM
state_query = Q()
if normal_states:
state_query |= Q(state__in=normal_states)
# Handle custom states in Python, as expired can not be queried through ORM
if "expired" in custom_states:
expired_domain_ids = [domain.id for domain in queryset if domain.state_display() == "Expired"]
state_query |= Q(id__in=expired_domain_ids)
# Apply the combined query
queryset = queryset.filter(state_query)
# If there are filtered states, and expired is not one of them, domains with
# state_display of 'Expired' must be removed
if "expired" not in custom_states:
expired_domain_ids = [domain.id for domain in queryset if domain.state_display() == "Expired"]
queryset = queryset.exclude(id__in=expired_domain_ids)
return queryset
def apply_sorting(self, queryset, request): def apply_sorting(self, queryset, request):
sort_by = request.GET.get("sort_by", "id") sort_by = request.GET.get("sort_by", "name")
order = request.GET.get("order", "asc") order = request.GET.get("order", "asc")
if sort_by == "state_display":
objects = list(queryset)
objects.sort(key=lambda domain: domain.state_display(), reverse=(order == "desc"))
return objects
else:
if order == "desc": if order == "desc":
sort_by = f"-{sort_by}" sort_by = f"-{sort_by}"
return queryset.order_by(sort_by) return queryset.order_by(sort_by)