This commit is contained in:
Rachid Mrad 2024-10-16 15:41:52 -04:00
parent 472186e9b4
commit c5de4b3a1d
No known key found for this signature in database
6 changed files with 104 additions and 26 deletions

View file

@ -1873,6 +1873,41 @@ class MembersTable extends LoadTableBase {
constructor() { 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__table', '.members__table-wrapper', '#members__search-field', '#members__search-field-submit', '.members__reset-search', '.members__reset-filters', '.members__no-data', '.members__no-search-results');
} }
initShowMoreButtons() {
function toggleShowMoreButton(toggleButton, contentDiv, buttonParentRow) {
const spanElement = toggleButton.querySelector('span');
const useElement = toggleButton.querySelector('use');
if (contentDiv.classList.contains('display-none')) {
showElement(contentDiv);
spanElement.textContent = 'Close';
useElement.setAttribute('xlink:href', '/public/img/sprite.svg#expand_less');
buttonParentRow.classList.add('hide-td-borders');
} else {
hideElement(contentDiv);
spanElement.textContent = 'Expand';
useElement.setAttribute('xlink:href', '/public/img/sprite.svg#expand_more');
buttonParentRow.classList.remove('hide-td-borders');
}
}
let toggleButtons = document.querySelectorAll('.usa-button--show-more-button');
toggleButtons.forEach((toggleButton) => {
let dataFor = toggleButton.dataset.for;
let contentDiv = document.getElementById(dataFor);
let buttonParentRow = toggleButton.parentElement.parentElement;
if (contentDiv && contentDiv.tagName.toLowerCase() === 'tr' && contentDiv.classList.contains('show-more-content') && buttonParentRow && buttonParentRow.tagName.toLowerCase() === 'tr') {
toggleButton.addEventListener('click', function() {
toggleShowMoreButton(toggleButton, contentDiv, buttonParentRow);
});
} else {
console.warn('Found a toggle button with no associated toggleable content or parent row');
}
});
}
/** /**
* Loads rows in the members list, as well as updates pagination around the members list * Loads rows in the members list, as well as updates pagination around the members list
* based on the supplied attributes. * based on the supplied attributes.
@ -1930,6 +1965,7 @@ class MembersTable extends LoadTableBase {
const invited = 'Invited'; const invited = 'Invited';
data.members.forEach(member => { data.members.forEach(member => {
const member_id = member.source + member.id;
const member_name = member.name; const member_name = member.name;
const member_display = member.member_display; const member_display = member.member_display;
const member_permissions = member.permissions; const member_permissions = member.permissions;
@ -1979,9 +2015,10 @@ class MembersTable extends LoadTableBase {
let domainsHTML = ''; let domainsHTML = '';
if (num_domains > 0) { if (num_domains > 0) {
domainsHTML += "<h3>Domains assigned</h3>"; domainsHTML += "<div class='desktop:grid-col-5 margin-bottom-2 desktop:margin-bottom-0'>";
domainsHTML += "<p>This member is assigned to " + num_domains + " domains:"; domainsHTML += "<h4 class='margin-y-0 text-primary'>Domains assigned</h4>";
domainsHTML += "<ul>"; domainsHTML += "<p class='margin-y-0'>This member is assigned to " + num_domains + " domains:";
domainsHTML += "<ul class='usa-list usa-list--unstyled margin-y-0'>";
for (let i = 0; i < num_domains && i < 6; i++) { for (let i = 0; i < num_domains && i < 6; i++) {
domainsHTML += `<li><a href="${domain_urls[i]}">${domain_names[i]}</a></li>`; domainsHTML += `<li><a href="${domain_urls[i]}">${domain_names[i]}</a></li>`;
} }
@ -1989,42 +2026,62 @@ class MembersTable extends LoadTableBase {
if (num_domains >= 6) { if (num_domains >= 6) {
domainsHTML += "<p><a href='#'>View assigned domains</a></p>"; domainsHTML += "<p><a href='#'>View assigned domains</a></p>";
} }
domainsHTML += "</div>";
} }
let permissionsHTML = ''; let permissionsHTML = '';
// only display domains permissions if domains assigned if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS)) {
if (domainsHTML) { permissionsHTML += "<p class='margin-top-1 p--blockquote'><strong class='text-base-dark'>Domains:</strong> Can view all organization domains. Can manage domains they are assigned to and edit information about the domain (including DNS settings).</p>";
if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS)) { } else if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)) {
permissionsHTML += "<p><b>Domains:</b> Can view all organization domains. Can manage domains they are assigned to and edit information about the domain (including DNS settings).</p>"; permissionsHTML += "<p class='margin-top-1 p--blockquote'><strong class='text-base-dark'>Domains:</strong> Can manage domains they are assigned to and edit information about the domain (including DNS settings).</p>";
} else if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)) {
permissionsHTML += "<p><b>Domains:</b> Can manage domains they are assigned to and edit information about the domain (including DNS settings).</p>";
}
} }
if (member_permissions.includes(UserPortfolioPermissionChoices.EDIT_REQUESTS)) { if (member_permissions.includes(UserPortfolioPermissionChoices.EDIT_REQUESTS)) {
permissionsHTML += "<p><b>Domain requests:</b> Can view all organization domain requests. Can create domain requests and modify their own requests.</p>"; permissionsHTML += "<p class='margin-top-1 p--blockquote'><strong class='text-base-dark'>Domain requests:</strong> Can view all organization domain requests. Can create domain requests and modify their own requests.</p>";
} else if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS)) { } else if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS)) {
permissionsHTML += "<p><b>Domain requests (view-only):</b> Can view all organization domain requests. Can't create or modify any domain requests.</p>"; permissionsHTML += "<p class='margin-top-1 p--blockquote'><strong class='text-base-dark'>Domain requests (view-only):</strong> Can view all organization domain requests. Can't create or modify any domain requests.</p>";
} }
if (member_permissions.includes(UserPortfolioPermissionChoices.EDIT_MEMBERS)) { if (member_permissions.includes(UserPortfolioPermissionChoices.EDIT_MEMBERS)) {
permissionsHTML += "<p><b>Members:</b> Can manage members including inviting new members, removing current members, and assigning domains to members."; permissionsHTML += "<p class='margin-top-1 p--blockquote'><strong class='text-base-dark'>Members:</strong> Can manage members including inviting new members, removing current members, and assigning domains to members.";
} else if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_MEMBERS)) { } else if (member_permissions.includes(UserPortfolioPermissionChoices.VIEW_MEMBERS)) {
permissionsHTML += "<p><b>Members (view-only):</b> Can view all organizational members. Can't manage any members."; permissionsHTML += "<p> class='margin-top-1 p--blockquote'><strong class='text-base-dark'>Members (view-only):</strong> Can view all organizational members. Can't manage any members.";
} }
// if there are no additional permissions, display a no additional permissions message // if there are no additional permissions, display a no additional permissions message
if (!permissionsHTML) { if (!permissionsHTML) {
permissionsHTML += "<p><b>No additional permissions:</b> There are no additional permissions for this member.</p>"; permissionsHTML += "<p><b>No additional permissions:</b> There are no additional permissions for this member.</p>";
} }
// add permissions header in all cases // add permissions header in all cases
permissionsHTML = "<h3>Additional permissions for this member</h3>" + permissionsHTML; permissionsHTML = "<div class='desktop:grid-col-7'><h4 class='margin-y-0 text-primary'>Additional permissions for this member</h4>" + permissionsHTML + "</div>";
let showMoreButton = '';
const showMoreRow = document.createElement('tr');
if (domainsHTML || permissionsHTML) {
showMoreButton = `
<button
type="button"
class="usa-button--show-more-button usa-button usa-button--unstyled display-block margin-top-2"
data-for=${member_id}
>
<span>Expand</span>
<svg class="usa-icon usa-icon--big" aria-hidden="true" focusable="false" role="img" width="24">
<use xlink:href="/public/img/sprite.svg#expand_more"></use>
</svg>
</button>
`;
showMoreRow.innerHTML = `<td colspan='3' headers="header-member" class="padding-top-0"><div class='grid-row'>${domainsHTML} ${permissionsHTML}</div></td>`;
showMoreRow.classList.add('show-more-content');
showMoreRow.classList.add('display-none');
showMoreRow.id = member_id;
}
row.innerHTML = ` row.innerHTML = `
<th scope="row" role="rowheader" data-label="member email"> <th role="rowheader" headers="header-member" data-label="member email" id='row-header-${member_id}'>
${member_display} ${admin_tagHTML} ${domainsHTML} ${permissionsHTML} ${member_display} ${admin_tagHTML} ${showMoreButton}
</th> </th>
<td data-sort-value="${last_active_sort_value}" data-label="last_active"> <td headers="header-last-active row-header-${member_id}" data-sort-value="${last_active_sort_value}" data-label="last_active">
${last_active_formatted} ${last_active_formatted}
</td> </td>
<td> <td headers="header-action row-header-${member_id}">
<a href="${action_url}"> <a href="${action_url}">
<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#${svg_icon}"></use> <use xlink:href="/public/img/sprite.svg#${svg_icon}"></use>
@ -2034,8 +2091,13 @@ class MembersTable extends LoadTableBase {
</td> </td>
`; `;
memberList.appendChild(row); memberList.appendChild(row);
if (domainsHTML || permissionsHTML) {
memberList.appendChild(showMoreRow);
}
}); });
this.initShowMoreButtons();
// Do not scroll on first page load // Do not scroll on first page load
if (scroll) if (scroll)
ScrollToElement('class', 'members'); ScrollToElement('class', 'members');

View file

@ -258,3 +258,11 @@ a.text-secondary,
a.text-secondary:hover { a.text-secondary:hover {
color: $theme-color-error; color: $theme-color-error;
} }
.usa-button--show-more-button {
font-size: size('ui', 'xs');
text-decoration: none;
.usa-icon {
top: 6px;
}
}

View file

@ -56,8 +56,10 @@ th {
border: none; border: none;
} }
td, th { tr:not(.hide-td-borders) {
border-bottom: 1px solid color('base-lighter'); td, th {
border-bottom: 1px solid color('base-lighter');
}
} }
thead th { thead th {

View file

@ -28,3 +28,8 @@ h2 {
.usa-form fieldset { .usa-form fieldset {
font-size: 1rem; font-size: 1rem;
} }
.p--blockquote {
padding-left: units(1);
border-left: 2px solid color('base-lighter');
}

View file

@ -39,16 +39,16 @@
</div> </div>
<!-- ---------- MAIN TABLE ---------- --> <!-- ---------- MAIN TABLE ---------- -->
<div class="members__table-wrapper display-none usa-table-container--scrollable margin-top-0" tabindex="0"> <div class="members__table-wrapper display-none margin-top-0">
<table class="usa-table usa-table--borderless usa-table--stacked dotgov-table dotgov-table--stacked members__table"> <table class="usa-table usa-table--borderless usa-table--stacked dotgov-table dotgov-table--stacked members__table">
<caption class="sr-only">Your registered members</caption> <caption class="sr-only">Your registered members</caption>
<thead> <thead>
<tr> <tr>
<th data-sortable="member" scope="col" role="columnheader">Member</th> <th data-sortable="member" role="columnheader" id="header-member">Member</th>
<th data-sortable="last_active" scope="col" role="columnheader">Last Active</th> <th data-sortable="last_active" role="columnheader" id="header-last-active">Last Active</th>
<th <th
scope="col" role="columnheader"
role="columnheader" id="header-action"
> >
<span class="usa-sr-only">Action</span> <span class="usa-sr-only">Action</span>
</th> </th>

View file

@ -175,6 +175,7 @@ def serialize_members(request, portfolio, item, user):
# Serialize member data # Serialize member data
member_json = { member_json = {
"id": item.get("id", ""), "id": item.get("id", ""),
"source": item.get("source", ""),
"name": " ".join(filter(None, [item.get("first_name", ""), item.get("last_name", "")])), "name": " ".join(filter(None, [item.get("first_name", ""), item.get("last_name", "")])),
"email": item.get("email_display", ""), "email": item.get("email_display", ""),
"member_display": item.get("member_display", ""), "member_display": item.get("member_display", ""),