diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index 7c523a12a..cd42fd322 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -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;
@@ -1226,7 +1225,7 @@ document.addEventListener('DOMContentLoaded', function() {
let markupForSuborganizationRow = '';
- if (!noPortfolioFlag) {
+ if (portfolioValue) {
markupForSuborganizationRow = `
${suborganization}
@@ -1427,9 +1426,9 @@ document.addEventListener('DOMContentLoaded', function() {
// NOTE: We may need to evolve this as we add more filters.
document.addEventListener('focusin', function(event) {
const accordion = document.querySelector('.usa-accordion--select');
- const accordionIsOpen = document.querySelector('.usa-button--filter[aria-expanded="true"]');
+ const accordionThatIsOpen = document.querySelector('.usa-button--filter[aria-expanded="true"]');
- if (accordionIsOpen && !accordion.contains(event.target)) {
+ if (accordionThatIsOpen && !accordion.contains(event.target)) {
closeFilters();
}
});
@@ -1438,9 +1437,9 @@ document.addEventListener('DOMContentLoaded', function() {
// NOTE: We may need to evolve this as we add more filters.
document.addEventListener('click', function(event) {
const accordion = document.querySelector('.usa-accordion--select');
- const accordionIsOpen = document.querySelector('.usa-button--filter[aria-expanded="true"]');
+ const accordionThatIsOpen = document.querySelector('.usa-button--filter[aria-expanded="true"]');
- if (accordionIsOpen && !accordion.contains(event.target)) {
+ if (accordionThatIsOpen && !accordion.contains(event.target)) {
closeFilters();
}
});
@@ -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.
@@ -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) {
@@ -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) {
@@ -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) : `Not submitted `;
- // Even if the request is not deletable, we may need this empty string for the td if the deletable column is displayed
+ // The markup for the delete function either be a simple trigger or a 3 dots menu with a hidden trigger (in the case of portfolio requests page)
+ // 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 = `
+
+ ${request.creator ? request.creator : ''}
+
+ `
+ }
+
+ // 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 = '';
@@ -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 line-height-sans-5"
aria-controls="toggle-delete-domain-alert-${request.id}"
data-open-modal
>
@@ -1692,8 +1709,57 @@ document.addEventListener('DOMContentLoaded', function() {
`
domainRequestsSectionWrapper.appendChild(modal);
+
+ // Request is deletable, modal and modalTrigger are built. Now check if we are on the portfolio requests page (by seeing if there is a portfolio value) and enhance the modalTrigger accordingly
+ if (portfolioValue) {
+ modalTrigger = `
+
+
+
+ Delete ${domainName}
+
+
+
+ `
+ }
}
+
const row = document.createElement('tr');
row.innerHTML = `
@@ -1702,6 +1768,7 @@ document.addEventListener('DOMContentLoaded', function() {
${submissionDate}
+ ${markupCreatorRow}
${request.status}
@@ -1817,6 +1884,32 @@ document.addEventListener('DOMContentLoaded', function() {
});
}
+ function closeMoreActionMenu(accordionThatIsOpen) {
+ if (accordionThatIsOpen.getAttribute("aria-expanded") === "true") {
+ accordionThatIsOpen.click();
+ }
+ }
+
+ document.addEventListener('focusin', function(event) {
+ closeOpenAccordions(event);
+ });
+
+ document.addEventListener('click', function(event) {
+ closeOpenAccordions(event);
+ });
+
+ function closeOpenAccordions(event) {
+ const openAccordions = document.querySelectorAll('.usa-button--more-actions[aria-expanded="true"]');
+ openAccordions.forEach((openAccordionButton) => {
+ // Find the corresponding accordion
+ const accordion = openAccordionButton.closest('.usa-accordion--more-actions');
+ if (accordion && !accordion.contains(event.target)) {
+ // Close the accordion if the click is outside
+ closeMoreActionMenu(openAccordionButton);
+ }
+ });
+ }
+
// Initial load
loadDomainRequests(1);
}
diff --git a/src/registrar/assets/sass/_theme/_accordions.scss b/src/registrar/assets/sass/_theme/_accordions.scss
index 839d7ac42..df4f686d8 100644
--- a/src/registrar/assets/sass/_theme/_accordions.scss
+++ b/src/registrar/assets/sass/_theme/_accordions.scss
@@ -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;
@@ -14,7 +15,6 @@
// Note, width is determined by a custom width class on one of the children
position: absolute;
z-index: 1;
- top: 33.88px;
left: 0;
border-radius: 4px;
border: solid 1px color('base-lighter');
@@ -31,3 +31,17 @@
margin-top: 0 !important;
}
}
+
+.usa-accordion--select .usa-accordion__content {
+ top: 33.88px;
+}
+
+.usa-accordion--more-actions .usa-accordion__content {
+ top: 30px;
+}
+
+tr:last-child .usa-accordion--more-actions .usa-accordion__content {
+ top: auto;
+ bottom: -10px;
+ right: 30px;
+}
diff --git a/src/registrar/assets/sass/_theme/_base.scss b/src/registrar/assets/sass/_theme/_base.scss
index e3ab4d538..9d2ed4177 100644
--- a/src/registrar/assets/sass/_theme/_base.scss
+++ b/src/registrar/assets/sass/_theme/_base.scss
@@ -159,6 +159,23 @@ abbr[title] {
}
}
+.hidden-mobile-flex {
+ display: none!important;
+}
+.visible-mobile-flex {
+ display: flex!important;
+}
+
+@include at-media(tablet) {
+ .hidden-mobile-flex {
+ display: flex!important;
+ }
+ .visible-mobile-flex {
+ display: none!important;
+ }
+}
+
+
.flex-end {
align-items: flex-end;
}
@@ -200,6 +217,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;
}
diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss
index 12eee9926..d431bfa41 100644
--- a/src/registrar/assets/sass/_theme/_buttons.scss
+++ b/src/registrar/assets/sass/_theme/_buttons.scss
@@ -211,14 +211,7 @@ a.usa-button--unstyled:visited {
align-items: center;
}
-
-.dotgov-table a,
-.usa-link--icon {
- &:visited {
- color: color('primary');
- }
-}
-
+.dotgov-table a
a .usa-icon,
.usa-button--with-icon .usa-icon {
height: 1.3em;
@@ -230,3 +223,9 @@ a .usa-icon,
height: 1.5em;
width: 1.5em;
}
+
+button.text-secondary,
+button.text-secondary:hover,
+.dotgov-table a.text-secondary {
+ color: $theme-color-error;
+}
diff --git a/src/registrar/assets/sass/_theme/_header.scss b/src/registrar/assets/sass/_theme/_header.scss
index 3d72a09cf..d79774d98 100644
--- a/src/registrar/assets/sass/_theme/_header.scss
+++ b/src/registrar/assets/sass/_theme/_header.scss
@@ -89,16 +89,24 @@
.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');
}
+ button[aria-expanded="true"] {
+ color: color('white');
+ }
+ button:not(.usa-current):hover::after {
+ display: none!important;
+ }
}
.usa-nav__secondary {
// I don't know why USWDS has this at 2 rem, which puts it out of alignment
diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py
index 17be3c2bb..4440476b9 100644
--- a/src/registrar/config/urls.py
+++ b/src/registrar/config/urls.py
@@ -79,6 +79,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(),
diff --git a/src/registrar/context_processors.py b/src/registrar/context_processors.py
index 2ac22b2e0..41046ed1c 100644
--- a/src/registrar/context_processors.py
+++ b/src/registrar/context_processors.py
@@ -60,35 +60,42 @@ def add_has_profile_feature_flag_to_context(request):
def portfolio_permissions(request):
"""Make portfolio permissions for the request user available in global context"""
- context = {
+ portfolio_context = {
"has_base_portfolio_permission": False,
- "has_domains_portfolio_permission": False,
- "has_domain_requests_portfolio_permission": False,
+ "has_any_domains_portfolio_permission": False,
+ "has_any_requests_portfolio_permission": False,
+ "has_edit_request_portfolio_permission": False,
+ "has_view_suborganization_portfolio_permission": False,
+ "has_edit_suborganization_portfolio_permission": False,
"has_view_members_portfolio_permission": False,
"has_edit_members_portfolio_permission": False,
- "has_view_suborganization": False,
- "has_edit_suborganization": False,
"portfolio": None,
"has_organization_feature_flag": False,
+ "has_organization_requests_flag": False,
+ "has_organization_members_flag": False,
}
try:
portfolio = request.session.get("portfolio")
+ # Linting: line too long
+ view_suborg = request.user.has_view_suborganization_portfolio_permission(portfolio)
+ edit_suborg = request.user.has_edit_suborganization_portfolio_permission(portfolio)
if portfolio:
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(
- portfolio
- ),
+ "has_edit_request_portfolio_permission": request.user.has_edit_request_portfolio_permission(portfolio),
+ "has_view_suborganization_portfolio_permission": view_suborg,
+ "has_edit_suborganization_portfolio_permission": edit_suborg,
+ "has_any_domains_portfolio_permission": request.user.has_any_domains_portfolio_permission(portfolio),
+ "has_any_requests_portfolio_permission": request.user.has_any_requests_portfolio_permission(portfolio),
"has_view_members_portfolio_permission": request.user.has_view_members_portfolio_permission(portfolio),
"has_edit_members_portfolio_permission": request.user.has_edit_members_portfolio_permission(portfolio),
- "has_view_suborganization": request.user.has_view_suborganization(portfolio),
- "has_edit_suborganization": request.user.has_edit_suborganization(portfolio),
"portfolio": portfolio,
"has_organization_feature_flag": True,
+ "has_organization_requests_flag": request.user.has_organization_requests_flag(),
+ "has_organization_members_flag": request.user.has_organization_members_flag(),
}
- return context
+ return portfolio_context
except AttributeError:
# Handles cases where request.user might not exist
- return context
+ return portfolio_context
diff --git a/src/registrar/migrations/0124_alter_portfolioinvitation_portfolio_additional_permissions_and_more.py b/src/registrar/migrations/0124_alter_portfolioinvitation_portfolio_additional_permissions_and_more.py
new file mode 100644
index 000000000..aab162de9
--- /dev/null
+++ b/src/registrar/migrations/0124_alter_portfolioinvitation_portfolio_additional_permissions_and_more.py
@@ -0,0 +1,64 @@
+# Generated by Django 4.2.10 on 2024-09-09 14:48
+
+import django.contrib.postgres.fields
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("registrar", "0123_alter_portfolioinvitation_portfolio_additional_permissions_and_more"),
+ ]
+
+ 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_members", "View members"),
+ ("edit_members", "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_members", "View members"),
+ ("edit_members", "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,
+ ),
+ ),
+ ]
diff --git a/src/registrar/models/user.py b/src/registrar/models/user.py
index 05cd1f456..929a63525 100644
--- a/src/registrar/models/user.py
+++ b/src/registrar/models/user.py
@@ -198,31 +198,25 @@ def has_base_portfolio_permission(self, portfolio):
def has_edit_org_portfolio_permission(self, portfolio):
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_PORTFOLIO)
- def has_domains_portfolio_permission(self, portfolio):
+ def has_any_domains_portfolio_permission(self, portfolio):
return self._has_portfolio_permission(
portfolio, UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS
) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
- def has_domain_requests_portfolio_permission(self, portfolio):
- # BEGIN
- # Note code below is to add organization_request feature
+ def has_organization_requests_flag(self):
request = HttpRequest()
request.user = self
- has_organization_requests_flag = flag_is_active(request, "organization_requests")
- if not has_organization_requests_flag:
- return False
- # END
- return self._has_portfolio_permission(
- portfolio, UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
- ) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS)
+ return flag_is_active(request, "organization_requests")
+
+ def has_organization_members_flag(self):
+ request = HttpRequest()
+ request.user = self
+ return flag_is_active(request, "organization_members")
def has_view_members_portfolio_permission(self, portfolio):
# BEGIN
# Note code below is to add organization_request feature
- request = HttpRequest()
- request.user = self
- has_organization_members_flag = flag_is_active(request, "organization_members")
- if not has_organization_members_flag:
+ if not self.has_organization_members_flag():
return False
# END
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_MEMBERS)
@@ -230,23 +224,37 @@ def has_view_members_portfolio_permission(self, portfolio):
def has_edit_members_portfolio_permission(self, portfolio):
# BEGIN
# Note code below is to add organization_request feature
- request = HttpRequest()
- request.user = self
- has_organization_members_flag = flag_is_active(request, "organization_members")
- if not has_organization_members_flag:
+ if not self.has_organization_members_flag():
return False
# END
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_MEMBERS)
- def has_view_all_domains_permission(self, portfolio):
+ def has_view_all_domains_portfolio_permission(self, portfolio):
"""Determines if the current user can view all available domains in a given portfolio"""
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS)
+ def has_any_requests_portfolio_permission(self, portfolio):
+ # BEGIN
+ # Note code below is to add organization_request feature
+ if not self.has_organization_requests_flag():
+ return False
+ # END
+ return self._has_portfolio_permission(
+ portfolio, UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
+ ) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_REQUESTS)
+
+ def has_view_all_requests_portfolio_permission(self, portfolio):
+ """Determines if the current user can view all available domain requests in a given portfolio"""
+ return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS)
+
+ def has_edit_request_portfolio_permission(self, portfolio):
+ return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_REQUESTS)
+
# Field specific permission checks
- def has_view_suborganization(self, portfolio):
+ def has_view_suborganization_portfolio_permission(self, portfolio):
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_SUBORGANIZATION)
- def has_edit_suborganization(self, portfolio):
+ def has_edit_suborganization_portfolio_permission(self, portfolio):
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_SUBORGANIZATION)
def get_first_portfolio(self):
@@ -255,36 +263,36 @@ def get_first_portfolio(self):
return permission.portfolio
return None
- def has_edit_requests(self, portfolio):
- return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_REQUESTS)
-
def portfolio_role_summary(self, portfolio):
"""Returns a list of roles based on the user's permissions."""
roles = []
# Define the conditions and their corresponding roles
conditions_roles = [
- (self.has_edit_suborganization(portfolio), ["Admin"]),
+ (self.has_edit_suborganization_portfolio_permission(portfolio), ["Admin"]),
(
- self.has_view_all_domains_permission(portfolio)
- and self.has_domain_requests_portfolio_permission(portfolio)
- and self.has_edit_requests(portfolio),
+ self.has_view_all_domains_portfolio_permission(portfolio)
+ and self.has_any_requests_portfolio_permission(portfolio)
+ and self.has_edit_request_portfolio_permission(portfolio),
["View-only admin", "Domain requestor"],
),
(
- self.has_view_all_domains_permission(portfolio)
- and self.has_domain_requests_portfolio_permission(portfolio),
+ self.has_view_all_domains_portfolio_permission(portfolio)
+ and self.has_any_requests_portfolio_permission(portfolio),
["View-only admin"],
),
(
self.has_base_portfolio_permission(portfolio)
- and self.has_edit_requests(portfolio)
- and self.has_domains_portfolio_permission(portfolio),
+ and self.has_edit_request_portfolio_permission(portfolio)
+ and self.has_any_domains_portfolio_permission(portfolio),
["Domain requestor", "Domain manager"],
),
- (self.has_base_portfolio_permission(portfolio) and self.has_edit_requests(portfolio), ["Domain requestor"]),
(
- self.has_base_portfolio_permission(portfolio) and self.has_domains_portfolio_permission(portfolio),
+ self.has_base_portfolio_permission(portfolio) and self.has_edit_request_portfolio_permission(portfolio),
+ ["Domain requestor"],
+ ),
+ (
+ self.has_base_portfolio_permission(portfolio) and self.has_any_domains_portfolio_permission(portfolio),
["Domain manager"],
),
(self.has_base_portfolio_permission(portfolio), ["Member"]),
@@ -446,8 +454,6 @@ def on_each_login(self):
self.check_domain_invitations_on_login()
self.check_portfolio_invitations_on_login()
- # NOTE TO DAVE: I'd simply suggest that we move these functions outside of the user object,
- # and move them to some sort of utility file. That way we aren't calling request inside here.
def is_org_user(self, request):
has_organization_feature_flag = flag_is_active(request, "organization_feature")
portfolio = request.session.get("portfolio")
@@ -456,7 +462,7 @@ def is_org_user(self, request):
def get_user_domain_ids(self, request):
"""Returns either the domains ids associated with this user on UserDomainRole or Portfolio"""
portfolio = request.session.get("portfolio")
- if self.is_org_user(request) and self.has_view_all_domains_permission(portfolio):
+ if self.is_org_user(request) and self.has_view_all_domains_portfolio_permission(portfolio):
return DomainInformation.objects.filter(portfolio=portfolio).values_list("domain_id", flat=True)
else:
return UserDomainRole.objects.filter(user=self).values_list("domain_id", flat=True)
diff --git a/src/registrar/models/utility/portfolio_helper.py b/src/registrar/models/utility/portfolio_helper.py
index 7afd32603..7f34221fd 100644
--- a/src/registrar/models/utility/portfolio_helper.py
+++ b/src/registrar/models/utility/portfolio_helper.py
@@ -21,7 +21,6 @@ class UserPortfolioPermissionChoices(models.TextChoices):
EDIT_MEMBERS = "edit_members", "Create and edit members"
VIEW_ALL_REQUESTS = "view_all_requests", "View all requests"
- VIEW_CREATED_REQUESTS = "view_created_requests", "View created requests"
EDIT_REQUESTS = "edit_requests", "Create and edit requests"
VIEW_PORTFOLIO = "view_portfolio", "View organization"
diff --git a/src/registrar/registrar_middleware.py b/src/registrar/registrar_middleware.py
index 4b590db1e..6207591ba 100644
--- a/src/registrar/registrar_middleware.py
+++ b/src/registrar/registrar_middleware.py
@@ -6,7 +6,7 @@
from urllib.parse import parse_qs
from django.urls import reverse
from django.http import HttpResponseRedirect
-from registrar.models.user import User
+from registrar.models import User
from waffle.decorators import flag_is_active
from registrar.models.utility.generic_helper import replace_url_queryparams
@@ -144,25 +144,30 @@ def process_view(self, request, view_func, view_args, view_kwargs):
if not request.user.is_authenticated:
return None
- # set the portfolio in the session if it is not set
- if "portfolio" not in request.session or request.session["portfolio"] is None:
- # if multiple portfolios are allowed for this user
- if flag_is_active(request, "multiple_portfolios"):
- # NOTE: we will want to change later to have a workflow for selecting
- # portfolio and another for switching portfolio; for now, select first
- request.session["portfolio"] = request.user.get_first_portfolio()
- elif flag_is_active(request, "organization_feature"):
- request.session["portfolio"] = request.user.get_first_portfolio()
- else:
- request.session["portfolio"] = None
-
- if request.session["portfolio"] is not None and current_path == self.home:
- if request.user.is_org_user(request):
- if request.user.has_domains_portfolio_permission(request.session["portfolio"]):
+ # if multiple portfolios are allowed for this user
+ if flag_is_active(request, "organization_feature"):
+ self.set_portfolio_in_session(request)
+ elif request.session.get("portfolio"):
+ # Edge case: User disables flag while already logged in
+ request.session["portfolio"] = None
+ elif "portfolio" not in request.session:
+ # Set the portfolio in the session if its not already in it
+ request.session["portfolio"] = None
+
+ if request.user.is_org_user(request):
+ if current_path == self.home:
+ if request.user.has_any_domains_portfolio_permission(request.session["portfolio"]):
portfolio_redirect = reverse("domains")
else:
portfolio_redirect = reverse("no-portfolio-domains")
-
return HttpResponseRedirect(portfolio_redirect)
return None
+
+ def set_portfolio_in_session(self, request):
+ # NOTE: we will want to change later to have a workflow for selecting
+ # portfolio and another for switching portfolio; for now, select first
+ if flag_is_active(request, "multiple_portfolios"):
+ request.session["portfolio"] = request.user.get_first_portfolio()
+ else:
+ request.session["portfolio"] = request.user.get_first_portfolio()
diff --git a/src/registrar/templates/domain_detail.html b/src/registrar/templates/domain_detail.html
index d7bc277b3..dd08004a3 100644
--- a/src/registrar/templates/domain_detail.html
+++ b/src/registrar/templates/domain_detail.html
@@ -72,9 +72,9 @@ DNS name servers
{% include "includes/summary_item.html" with title='DNSSEC' value='Not Enabled' edit_link=url editable=is_editable %}
{% endif %}
- {% if portfolio and has_domains_portfolio_permission and has_view_suborganization %}
+ {% if portfolio and has_any_domains_portfolio_permission and has_view_suborganization_portfolio_permission %}
{% url 'domain-suborganization' pk=domain.id as url %}
- {% include "includes/summary_item.html" with title='Suborganization' value=domain.domain_info.sub_organization edit_link=url editable=is_editable|and:has_edit_suborganization %}
+ {% include "includes/summary_item.html" with title='Suborganization' value=domain.domain_info.sub_organization edit_link=url editable=is_editable|and:has_edit_suborganization_portfolio_permission %}
{% else %}
{% url 'domain-org-name-address' pk=domain.id as url %}
{% include "includes/summary_item.html" with title='Organization name and mailing address' value=domain.domain_info address='true' edit_link=url editable=is_editable %}
diff --git a/src/registrar/templates/domain_dsdata.html b/src/registrar/templates/domain_dsdata.html
index 1dd1e1abe..6e18bce13 100644
--- a/src/registrar/templates/domain_dsdata.html
+++ b/src/registrar/templates/domain_dsdata.html
@@ -63,7 +63,7 @@ DS data record {{forloop.counter}}
-
+
Delete
diff --git a/src/registrar/templates/domain_nameservers.html b/src/registrar/templates/domain_nameservers.html
index 70eba6bc0..fd6256f39 100644
--- a/src/registrar/templates/domain_nameservers.html
+++ b/src/registrar/templates/domain_nameservers.html
@@ -52,7 +52,7 @@ DNS name servers
{% endwith %}
-
+
Delete
diff --git a/src/registrar/templates/domain_request_form.html b/src/registrar/templates/domain_request_form.html
index 17948a110..9228e51db 100644
--- a/src/registrar/templates/domain_request_form.html
+++ b/src/registrar/templates/domain_request_form.html
@@ -16,6 +16,26 @@
Previous step
+ {% comment %}
+ TODO: uncomment in #2596
+ {% else %}
+ {% if portfolio %}
+ {% url 'domain-requests' as url_2 %}
+
+
+
+ Domain requests
+
+
+ {% if requested_domain__name %}
+ {{ requested_domain__name }}
+ {% else %}
+ Start a new domain request
+ {% endif %}
+
+
+
+ {% endif %} {% endcomment %}
{% endif %}
{% block form_messages %}
diff --git a/src/registrar/templates/domain_request_other_contacts.html b/src/registrar/templates/domain_request_other_contacts.html
index 4189e8c73..72e4abd8b 100644
--- a/src/registrar/templates/domain_request_other_contacts.html
+++ b/src/registrar/templates/domain_request_other_contacts.html
@@ -40,7 +40,7 @@ Are there other employees who can help verify your request?
Organization contact {{ forloop.counter }}
-
+
Delete
diff --git a/src/registrar/templates/domain_request_status.html b/src/registrar/templates/domain_request_status.html
index 183a8be81..f4defc14e 100644
--- a/src/registrar/templates/domain_request_status.html
+++ b/src/registrar/templates/domain_request_status.html
@@ -8,15 +8,33 @@
{% block content %}