Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2351: Org requests page - [RJM] #2720

Merged
merged 48 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
be8a618
wip
rachidatecs Sep 5, 2024
ba20e74
refactored domain_requests_json
dave-kennedy-ecs Sep 5, 2024
8f8d9a8
last row accordion placement
rachidatecs Sep 5, 2024
bc2ae12
pull
rachidatecs Sep 5, 2024
ec7202b
merge main:
rachidatecs Sep 5, 2024
9bd67cf
fix bug with registrar and basic redirect link stuff
zandercymatics Sep 5, 2024
d802b9a
Add created by column
rachidatecs Sep 5, 2024
2939c89
pull
rachidatecs Sep 5, 2024
3c3fd26
Finishing or canceling a request redirects to domain request view
zandercymatics Sep 5, 2024
9ea0f31
CSS tweaks
rachidatecs Sep 5, 2024
b4dd786
pull
rachidatecs Sep 5, 2024
faf5790
filter requests based on permissions, updated actions based on permis…
dave-kennedy-ecs Sep 5, 2024
b4827ff
merged pulled updates
dave-kennedy-ecs Sep 5, 2024
6a08c1e
migrations file
dave-kennedy-ecs Sep 5, 2024
ea75440
Comment out breadcrumb bar
zandercymatics Sep 6, 2024
bb7a521
Merge branch 'main' into rjm/2351-org-requests-page
zandercymatics Sep 6, 2024
cbdf763
CSS done
rachidatecs Sep 6, 2024
49e6560
merge
rachidatecs Sep 6, 2024
1e9ae7b
cleanup
rachidatecs Sep 6, 2024
7a67845
bug fix
zandercymatics Sep 6, 2024
1af08a6
model and view unit tests
rachidatecs Sep 6, 2024
9f557fc
requests_json tests and some linting
dave-kennedy-ecs Sep 6, 2024
9019792
Fix existing tests
zandercymatics Sep 6, 2024
604da37
merge
dave-kennedy-ecs Sep 6, 2024
a3204c8
Merge branch 'rjm/2351-org-requests-page' of https://github.com/cisag…
dave-kennedy-ecs Sep 6, 2024
540bb64
update session on each request
zandercymatics Sep 6, 2024
3ed5e8c
Fix delete btn alignment
rachidatecs Sep 6, 2024
39834fd
merge
rachidatecs Sep 6, 2024
3d27199
Add registrar_middleware session tests and the Test for withdraw redi…
zandercymatics Sep 6, 2024
2f5f09a
Merge branch 'main' into rjm/2351-org-requests-page
zandercymatics Sep 9, 2024
847bcbe
Merge branch 'main' into rjm/2351-org-requests-page
zandercymatics Sep 9, 2024
67f79a7
Fix migrations
zandercymatics Sep 9, 2024
6f1adc1
Change waffle flag logic (merge conflict)
zandercymatics Sep 9, 2024
3c4b463
Add override_flag for tests
zandercymatics Sep 9, 2024
743f81a
Fix tests + lint
zandercymatics Sep 9, 2024
19ef32b
fix typo
zandercymatics Sep 9, 2024
8e26399
Merge branch 'main' into rjm/2351-org-requests-page
zandercymatics Sep 9, 2024
5013e65
Linting
zandercymatics Sep 10, 2024
19548fc
Merge branch 'main' into rjm/2351-org-requests-page
zandercymatics Sep 10, 2024
0eda760
Rename old usage
zandercymatics Sep 10, 2024
4dfa2f7
Add type hint
zandercymatics Sep 10, 2024
663fc99
Update src/registrar/assets/js/get-gov.js
zandercymatics Sep 11, 2024
a0c73ca
Update src/registrar/templates/includes/header_extended.html
zandercymatics Sep 11, 2024
87cb111
Update src/registrar/views/domain_requests_json.py
zandercymatics Sep 11, 2024
096dce7
PR suggestions
zandercymatics Sep 11, 2024
d7b851e
Merge branch 'rjm/2351-org-requests-page' of github.com:cisagov/manag…
zandercymatics Sep 11, 2024
16fc446
unit tests for the extra column in the template
rachidatecs Sep 12, 2024
4124ad1
Merge branch 'main' into rjm/2351-org-requests-page
zandercymatics Sep 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 91 additions & 7 deletions src/registrar/assets/js/get-gov.js
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,6 @@ document.addEventListener('DOMContentLoaded', function() {
const statusCheckboxes = document.querySelectorAll('input[name="filter-status"]');
const statusIndicator = document.querySelector('.domain__filter-indicator');
const statusToggle = document.querySelector('.usa-button--filter');
const noPortfolioFlag = document.getElementById('no-portfolio-js-flag');
const portfolioElement = document.getElementById('portfolio-js-value');
const portfolioValue = portfolioElement ? portfolioElement.getAttribute('data-portfolio') : null;

Expand Down Expand Up @@ -1226,7 +1225,7 @@ document.addEventListener('DOMContentLoaded', function() {

let markupForSuborganizationRow = '';

if (!noPortfolioFlag) {
if (portfolioValue) {
markupForSuborganizationRow = `
<td>
<span class="text-wrap" aria-label="${domain.suborganization ? suborganization : 'No suborganization'}">${suborganization}</span>
Expand Down Expand Up @@ -1485,6 +1484,8 @@ document.addEventListener('DOMContentLoaded', function() {
const tableHeaders = document.querySelectorAll('.domain-requests__table th[data-sortable]');
const tableAnnouncementRegion = document.querySelector('.domain-requests__table-wrapper .usa-table__announcement-region');
const resetSearchButton = document.querySelector('.domain-requests__reset-search');
const portfolioElement = document.getElementById('portfolio-js-value');
const portfolioValue = portfolioElement ? portfolioElement.getAttribute('data-portfolio') : null;

/**
* Delete is actually a POST API that requires a csrf token. The token will be waiting for us in the template as a hidden input.
Expand Down Expand Up @@ -1533,7 +1534,7 @@ document.addEventListener('DOMContentLoaded', function() {
* @param {*} scroll - control for the scrollToElement functionality
* @param {*} searchTerm - the search term
*/
function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, scroll = scrollToTable, searchTerm = currentSearchTerm) {
function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, scroll = scrollToTable, searchTerm = currentSearchTerm, portfolio = portfolioValue) {
// fetch json of page of domain requests, given params
let baseUrl = document.getElementById("get_domain_requests_json_url");
if (!baseUrl) {
Expand All @@ -1545,7 +1546,12 @@ document.addEventListener('DOMContentLoaded', function() {
return;
}

fetch(`${baseUrlValue}?page=${page}&sort_by=${sortBy}&order=${order}&search_term=${searchTerm}`)
// fetch json of page of requests, given params
let url = `${baseUrlValue}?page=${page}&sort_by=${sortBy}&order=${order}&search_term=${searchTerm}`
if (portfolio)
url += `&portfolio=${portfolio}`

fetch(url)
.then(response => response.json())
.then(data => {
if (data.error) {
Expand Down Expand Up @@ -1601,10 +1607,21 @@ document.addEventListener('DOMContentLoaded', function() {
const actionLabel = request.action_label;
const submissionDate = request.last_submitted_date ? new Date(request.last_submitted_date).toLocaleDateString('en-US', options) : `<span class="text-base">Not submitted</span>`;

// Even if the request is not deletable, we may need this empty string for the td if the deletable column is displayed
// Delete markup will either be a simple trigger or a 3 dots menu with a hidden trigger (in the case of portfolio requests page)
zandercymatics marked this conversation as resolved.
Show resolved Hide resolved
// Even if the request is not deletable, we may need these empty strings for the td if the deletable column is displayed
let modalTrigger = '';

// If the request is deletable, create modal body and insert it
let markupCreatorRow = '';

if (portfolioValue) {
markupCreatorRow = `
<td>
<span class="text-wrap break-word">${request.creator ? request.creator : ''}</span>
</td>
`
}

// If the request is deletable, create modal body and insert it. This is true for both requests and portfolio requests pages
if (request.is_deletable) {
let modalHeading = '';
let modalDescription = '';
Expand All @@ -1627,7 +1644,7 @@ document.addEventListener('DOMContentLoaded', function() {
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"
class="usa-button text-secondary usa-button--unstyled text-no-underline late-loading-modal-trigger"
aria-controls="toggle-delete-domain-alert-${request.id}"
data-open-modal
>
Expand Down Expand Up @@ -1692,8 +1709,44 @@ document.addEventListener('DOMContentLoaded', function() {
`

domainRequestsSectionWrapper.appendChild(modal);

// Request is deletable, modal and modalTrigger are built. Now test is portfolio requests page and enhace the modalTrigger markup
zandercymatics marked this conversation as resolved.
Show resolved Hide resolved
if (portfolioValue) {
modalTrigger = `
<div class="usa-accordion usa-accordion--more-actions margin-right-2">
<div class="usa-accordion__heading">
<button
type="button"
class="usa-button usa-button--unstyled usa-button--with-icon usa-accordion__button usa-button--more-actions"
aria-expanded="false"
aria-controls="more-actions-${request.id}"
>
<svg class="usa-icon top-2px" aria-hidden="true" focusable="false" role="img" width="24">
<use xlink:href="/public/img/sprite.svg#more_vert"></use>
</svg>
</button>
</div>
<div id="more-actions-${request.id}" class="usa-accordion__content usa-prose shadow-1 left-auto right-0" hidden>
<h2>More options</h2>
<a
role="button"
id="button-toggle-delete-domain-alert-${request.id}"
href="#toggle-delete-domain-alert-${request.id}"
class="usa-button text-secondary 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>
</div>
</div>
`
}
}


const row = document.createElement('tr');
row.innerHTML = `
<th scope="row" role="rowheader" data-label="Domain name">
Expand All @@ -1702,6 +1755,7 @@ document.addEventListener('DOMContentLoaded', function() {
<td data-sort-value="${new Date(request.last_submitted_date).getTime()}" data-label="Date submitted">
${submissionDate}
</td>
${markupCreatorRow}
asaki222 marked this conversation as resolved.
Show resolved Hide resolved
<td data-label="Status">
${request.status}
</td>
Expand Down Expand Up @@ -1817,6 +1871,36 @@ document.addEventListener('DOMContentLoaded', function() {
});
}

function closeMoreActionMenu(accordionIsOpen) {
if (accordionIsOpen.getAttribute("aria-expanded") === "true") {
accordionIsOpen.click();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: "accordionIsOpen" looks like a boolean var...but it's clickable so clearly this is referring to an actual DOM element. Might want to rename to reflect its true identity. (eg. "openAccordionButton"? Like what you have later on?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about accordionThatIsOpen? Since it grabs an open accordion element

cc: @rachidatecs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll tackle renaming in the next ticket (search)

}
}

document.addEventListener('focusin', function(event) {
Copy link
Contributor

@CocoByte CocoByte Sep 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(non-blocking comment)--I'm surprised this isn't already built into the controls....are we over-customizing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just making a guess but I think its due to how the default accordion works. I know this work was done before -- @rachidatecs did you have to do some heavy customization of this element to get it to behave this way?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct

const accordions = document.querySelectorAll('.usa-accordion--more-actions');
const openAccordions = document.querySelectorAll('.usa-button--more-actions[aria-expanded="true"]');

openAccordions.forEach((openAccordionButton) => {
const accordion = openAccordionButton.closest('.usa-accordion--more-actions'); // Find the corresponding accordion
if (accordion && !accordion.contains(event.target)) {
closeMoreActionMenu(openAccordionButton); // Close the accordion if the focus is outside
}
});
});

document.addEventListener('click', function(event) {
const accordions = document.querySelectorAll('.usa-accordion--more-actions');
zandercymatics marked this conversation as resolved.
Show resolved Hide resolved
const openAccordions = document.querySelectorAll('.usa-button--more-actions[aria-expanded="true"]');

openAccordions.forEach((openAccordionButton) => {
const accordion = openAccordionButton.closest('.usa-accordion--more-actions'); // Find the corresponding accordion
if (accordion && !accordion.contains(event.target)) {
closeMoreActionMenu(openAccordionButton); // Close the accordion if the click is outside
}
});
});

// Initial load
loadDomainRequests(1);
}
Expand Down
8 changes: 7 additions & 1 deletion src/registrar/assets/sass/_theme/_accordions.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@use "uswds-core" as *;

.usa-accordion--select {
.usa-accordion--select,
.usa-accordion--more-actions {
display: inline-block;
width: auto;
position: relative;
Expand Down Expand Up @@ -31,3 +32,8 @@
margin-top: 0 !important;
}
}

tr:last-child .usa-accordion--more-actions .usa-accordion__content {
top: auto;
bottom: 20px;
}
9 changes: 7 additions & 2 deletions src/registrar/assets/sass/_theme/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ abbr[title] {
}
}

.margin-right-neg-4px {
margin-right: -4px;
// Boost this USWDS utility class for the accordions in the portfolio requests table
.left-auto {
left: auto!important;
}

.break-word {
word-break: break-word;
}
6 changes: 4 additions & 2 deletions src/registrar/assets/sass/_theme/_header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,16 @@
.usa-nav__primary {
.usa-nav-link,
.usa-nav-link:hover,
.usa-nav-link:active {
.usa-nav-link:active,
button {
color: color('primary');
font-weight: font-weight('normal');
font-size: 16px;
}
.usa-current,
.usa-current:hover,
.usa-current:active {
.usa-current:active,
button.usa-current {
font-weight: font-weight('bold');
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/registrar/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
views.PortfolioDomainRequestsView.as_view(),
name="domain-requests",
),
path(
"no-organization-requests/",
views.PortfolioNoDomainRequestsView.as_view(),
name="no-portfolio-requests",
),
path(
"organization/",
views.PortfolioOrganizationView.as_view(),
Expand Down
18 changes: 9 additions & 9 deletions src/registrar/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,20 @@ def portfolio_permissions(request):
return {
"has_base_portfolio_permission": request.user.has_base_portfolio_permission(portfolio),
"has_domains_portfolio_permission": request.user.has_domains_portfolio_permission(portfolio),
"has_domain_requests_portfolio_permission": request.user.has_domain_requests_portfolio_permission(
"has_requests_portfolio_permission": request.user.has_requests_portfolio_permission(
portfolio
),
"has_view_suborganization": request.user.has_view_suborganization(portfolio),
"has_edit_suborganization": request.user.has_edit_suborganization(portfolio),
"has_view_suborganization_portfolio_permission": request.user.has_view_suborganization_portfolio_permission(portfolio),
"has_edit_suborganization_portfolio_permission": request.user.has_edit_suborganization_portfolio_permission(portfolio),
"portfolio": portfolio,
"has_organization_feature_flag": True,
}
return {
"has_base_portfolio_permission": False,
"has_domains_portfolio_permission": False,
"has_domain_requests_portfolio_permission": False,
"has_view_suborganization": False,
"has_edit_suborganization": False,
"has_requests_portfolio_permission": False,
"has_view_suborganization_portfolio_permission": False,
"has_edit_suborganization_portfolio_permission": False,
"portfolio": None,
"has_organization_feature_flag": False,
}
Expand All @@ -89,9 +89,9 @@ def portfolio_permissions(request):
return {
"has_base_portfolio_permission": False,
"has_domains_portfolio_permission": False,
"has_domain_requests_portfolio_permission": False,
"has_view_suborganization": False,
"has_edit_suborganization": False,
"has_requests_portfolio_permission": False,
"has_view_suborganization_portfolio_permission": False,
"has_edit_suborganization_portfolio_permission": False,
"portfolio": None,
"has_organization_feature_flag": False,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Generated by Django 4.2.10 on 2024-09-05 23:39

import django.contrib.postgres.fields
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("registrar", "0122_create_groups_v16"),
]

operations = [
migrations.AlterField(
model_name="portfolioinvitation",
name="portfolio_additional_permissions",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(
choices=[
("view_all_domains", "View all domains and domain reports"),
("view_managed_domains", "View managed domains"),
("view_member", "View members"),
("edit_member", "Create and edit members"),
("view_all_requests", "View all requests"),
("edit_requests", "Create and edit requests"),
("view_portfolio", "View organization"),
("edit_portfolio", "Edit organization"),
("view_suborganization", "View suborganization"),
("edit_suborganization", "Edit suborganization"),
],
max_length=50,
),
blank=True,
help_text="Select one or more additional permissions.",
null=True,
size=None,
),
),
migrations.AlterField(
model_name="userportfoliopermission",
name="additional_permissions",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(
choices=[
("view_all_domains", "View all domains and domain reports"),
("view_managed_domains", "View managed domains"),
("view_member", "View members"),
("edit_member", "Create and edit members"),
("view_all_requests", "View all requests"),
("edit_requests", "Create and edit requests"),
("view_portfolio", "View organization"),
("edit_portfolio", "Edit organization"),
("view_suborganization", "View suborganization"),
("edit_suborganization", "Edit suborganization"),
],
max_length=50,
),
blank=True,
help_text="Select one or more additional permissions.",
null=True,
size=None,
),
),
]
Loading
Loading