From ecc1038c341d096516d08b2dbb772cd5b55a4559 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 5 Sep 2024 21:27:41 -0600 Subject: [PATCH 01/46] Added widescreen detection and scss adjustments for Domains and Domain Request page --- src/registrar/assets/sass/_navigation.scss | 6 ++++++ src/registrar/assets/sass/_theme/_base.scss | 4 ++++ src/registrar/assets/sass/_theme/_containers.scss | 6 ++++++ src/registrar/assets/sass/_theme/styles.scss | 2 ++ src/registrar/config/settings.py | 1 + src/registrar/context_processors.py | 4 ++++ src/registrar/templates/base.html | 2 +- src/registrar/templates/includes/footer.html | 8 ++++---- src/registrar/templates/includes/header_extended.html | 4 ++-- src/registrar/templates/portfolio_base.html | 2 +- 10 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 src/registrar/assets/sass/_navigation.scss create mode 100644 src/registrar/assets/sass/_theme/_containers.scss diff --git a/src/registrar/assets/sass/_navigation.scss b/src/registrar/assets/sass/_navigation.scss new file mode 100644 index 000000000..c87e78295 --- /dev/null +++ b/src/registrar/assets/sass/_navigation.scss @@ -0,0 +1,6 @@ +@use "uswds-core" as *; + +.usa-nav__inner--widescreen, +.usa-navbar--widescreen { + max-width: 1920px; +} \ No newline at end of file diff --git a/src/registrar/assets/sass/_theme/_base.scss b/src/registrar/assets/sass/_theme/_base.scss index 9f8a0cbb6..ecf8df0b8 100644 --- a/src/registrar/assets/sass/_theme/_base.scss +++ b/src/registrar/assets/sass/_theme/_base.scss @@ -192,3 +192,7 @@ abbr[title] { max-width: 50ch; } } + +.usa-banner__inner--widescreen { + max-width: 1920px; +} \ No newline at end of file diff --git a/src/registrar/assets/sass/_theme/_containers.scss b/src/registrar/assets/sass/_theme/_containers.scss new file mode 100644 index 000000000..206fcdceb --- /dev/null +++ b/src/registrar/assets/sass/_theme/_containers.scss @@ -0,0 +1,6 @@ +@use "uswds-core" as *; + +.grid-container--widescreen, +.usa-identifier__container--widescreen { + max-width: 1920px; +} diff --git a/src/registrar/assets/sass/_theme/styles.scss b/src/registrar/assets/sass/_theme/styles.scss index f9df015b4..710b0d193 100644 --- a/src/registrar/assets/sass/_theme/styles.scss +++ b/src/registrar/assets/sass/_theme/styles.scss @@ -24,6 +24,8 @@ @forward "identifier"; @forward "header"; @forward "register-form"; +@forward "containers"; +@forward "navigation"; /*-------------------------------------------------- --- Admin ---------------------------------*/ diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 73aecad7a..9f855d0e9 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -244,6 +244,7 @@ TEMPLATES = [ "registrar.context_processors.add_path_to_context", "registrar.context_processors.add_has_profile_feature_flag_to_context", "registrar.context_processors.portfolio_permissions", + "registrar.context_processors.is_widescreen_mode", ], }, }, diff --git a/src/registrar/context_processors.py b/src/registrar/context_processors.py index ea04dca80..5c2fb6a54 100644 --- a/src/registrar/context_processors.py +++ b/src/registrar/context_processors.py @@ -95,3 +95,7 @@ def portfolio_permissions(request): "portfolio": None, "has_organization_feature_flag": False, } + +def is_widescreen_mode(request): + widescreen_paths = ["/domains/", "/requests/"] + return {"is_widescreen_mode": any(path in request.path for path in widescreen_paths)} #any(path in request.path for path in widescreen_paths) \ No newline at end of file diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html index e5bd1b0b9..b14dab2fa 100644 --- a/src/registrar/templates/base.html +++ b/src/registrar/templates/base.html @@ -78,7 +78,7 @@
-
+
U.S. flag
diff --git a/src/registrar/templates/includes/footer.html b/src/registrar/templates/includes/footer.html index fdf91a64e..c8d237821 100644 --- a/src/registrar/templates/includes/footer.html +++ b/src/registrar/templates/includes/footer.html @@ -3,7 +3,7 @@
-{% endfor %} \ No newline at end of file +{% endfor %} diff --git a/src/registrar/templates/includes/request_status_manage.html b/src/registrar/templates/includes/request_status_manage.html new file mode 100644 index 000000000..2a254df4b --- /dev/null +++ b/src/registrar/templates/includes/request_status_manage.html @@ -0,0 +1,236 @@ +{% load custom_filters %} +{% load static url_helpers %} +
+
+ {% block breadcrumb %} + {% if portfolio %} + {% url 'domain-requests' as url %} + {% else %} + {% url 'home' as url %} + {% endif %} + + {% endblock breadcrumb %} + + {% block header %} + {% if not DomainRequest.requested_domain and DomainRequest.status == DomainRequest.DomainRequestStatus.STARTED %} +

New domain request

+ {% else %} +

Domain request for {{ DomainRequest.requested_domain.name }}

+ {% endif %} + {% endblock header %} + + {% block status_summary %} +
+
+

+ + Status: + + {{ DomainRequest.get_status_display|default:"ERROR Please contact technical support/dev" }} +

+
+
+
+ {% endblock status_summary %} + + {% block status_metadata %} + + {% if portfolio %} + {% if DomainRequest.creator %} +

+ Created by: {{DomainRequest.creator.email|default:DomainRequest.creator.get_formatted_name }} +

+ {% else %} +

+ No creator found: this is an error, please email help@get.gov. +

+ {% endif %} + {% endif %} + + {% with statuses=DomainRequest.DomainRequestStatus last_submitted=DomainRequest.last_submitted_date|date:"F j, Y" first_submitted=DomainRequest.first_submitted_date|date:"F j, Y" last_status_update=DomainRequest.last_status_update|date:"F j, Y" %} + {% comment %} + These are intentionally seperated this way. + There is some code repetition, but it gives us more flexibility rather than a dense reduction. + Leave it this way until we've solidified our requirements. + {% endcomment %} + {% if DomainRequest.status == statuses.STARTED %} + {% with first_started_date=DomainRequest.get_first_status_started_date|date:"F j, Y" %} +

+ {% comment %} + A newly created domain request will not have a value for last_status update. + This is because the status never really updated. + However, if this somehow goes back to started we can default to displaying that new date. + {% endcomment %} + Started on: {{last_status_update|default:first_started_date}} +

+ {% endwith %} + {% elif DomainRequest.status == statuses.SUBMITTED %} +

+ Submitted on: {{last_submitted|default:first_submitted }} +

+

+ Last updated on: {{DomainRequest.updated_at|date:"F j, Y"}} +

+ {% elif DomainRequest.status == statuses.ACTION_NEEDED %} +

+ Submitted on: {{last_submitted|default:first_submitted }} +

+

+ Last updated on: {{DomainRequest.updated_at|date:"F j, Y"}} +

+ {% elif DomainRequest.status == statuses.REJECTED %} +

+ Submitted on: {{last_submitted|default:first_submitted }} +

+

+ Rejected on: {{last_status_update}} +

+ {% elif DomainRequest.status == statuses.WITHDRAWN %} +

+ Submitted on: {{last_submitted|default:first_submitted }} +

+

+ Withdrawn on: {{last_status_update}} +

+ {% else %} + {% comment %} Shown for in_review, approved, ineligible {% endcomment %} +

+ Last updated on: {{DomainRequest.updated_at|date:"F j, Y"}} +

+ {% endif %} + {% endwith %} + {% endblock status_metadata %} + + {% block status_blurb %} + {% if DomainRequest.is_awaiting_review %} +

{% include "includes/domain_request_awaiting_review.html" with show_withdraw_text=DomainRequest.is_withdrawable %}

+ {% endif %} + {% endblock status_blurb %} + + {% block modify_request %} + {% if DomainRequest.is_withdrawable %} +

+ Withdraw request +

+ {% endif %} + {% endblock modify_request %} +
+ +
+ {% block request_summary_header %} +

Summary of your domain request

+ {% endblock request_summary_header%} + + {% block request_summary %} + {% with heading_level='h3' %} + {% with org_type=DomainRequest.get_generic_org_type_display %} + {% include "includes/summary_item.html" with title='Type of organization' value=org_type heading_level=heading_level %} + {% endwith %} + + {% if DomainRequest.tribe_name %} + {% include "includes/summary_item.html" with title='Tribal government' value=DomainRequest.tribe_name heading_level=heading_level %} + + {% if DomainRequest.federally_recognized_tribe %} +

Federally-recognized tribe

+ {% endif %} + + {% if DomainRequest.state_recognized_tribe %} +

State-recognized tribe

+ {% endif %} + + {% endif %} + + {% if DomainRequest.get_federal_type_display %} + {% include "includes/summary_item.html" with title='Federal government branch' value=DomainRequest.get_federal_type_display heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.is_election_board %} + {% with value=DomainRequest.is_election_board|yesno:"Yes,No,Incomplete" %} + {% include "includes/summary_item.html" with title='Election office' value=value heading_level=heading_level %} + {% endwith %} + {% endif %} + + {% if DomainRequest.organization_name %} + {% include "includes/summary_item.html" with title='Organization' value=DomainRequest address='true' heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.about_your_organization %} + {% include "includes/summary_item.html" with title='About your organization' value=DomainRequest.about_your_organization heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.senior_official %} + {% include "includes/summary_item.html" with title='Senior official' value=DomainRequest.senior_official contact='true' heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.current_websites.all %} + {% include "includes/summary_item.html" with title='Current websites' value=DomainRequest.current_websites.all list='true' heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.requested_domain %} + {% include "includes/summary_item.html" with title='.gov domain' value=DomainRequest.requested_domain heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.alternative_domains.all %} + {% include "includes/summary_item.html" with title='Alternative domains' value=DomainRequest.alternative_domains.all list='true' heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.purpose %} + {% include "includes/summary_item.html" with title='Purpose of your domain' value=DomainRequest.purpose heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.creator %} + {% include "includes/summary_item.html" with title='Your contact information' value=DomainRequest.creator contact='true' heading_level=heading_level %} + {% endif %} + + {% if DomainRequest.other_contacts.all %} + {% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.other_contacts.all contact='true' list='true' heading_level=heading_level %} + {% else %} + {% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.no_other_contacts_rationale heading_level=heading_level %} + {% endif %} + + {# We always show this field even if None #} + {% if DomainRequest %} +

CISA Regional Representative

+
    + {% if DomainRequest.cisa_representative_first_name %} + {{ DomainRequest.get_formatted_cisa_rep_name }} + {% else %} + No + {% endif %} +
+

Anything else

+
    + {% if DomainRequest.anything_else %} + {{DomainRequest.anything_else}} + {% else %} + No + {% endif %} +
+ {% endif %} + {% endwith %} + {% endblock request_summary%} +
+
\ No newline at end of file diff --git a/src/registrar/templates/domain_request_status_viewonly.html b/src/registrar/templates/portfolio_domain_request_status_viewonly.html similarity index 76% rename from src/registrar/templates/domain_request_status_viewonly.html rename to src/registrar/templates/portfolio_domain_request_status_viewonly.html index bed5168ad..bb6ee1e66 100644 --- a/src/registrar/templates/domain_request_status_viewonly.html +++ b/src/registrar/templates/portfolio_domain_request_status_viewonly.html @@ -5,5 +5,5 @@ {% block title %}Domain request status | {{ DomainRequest.requested_domain.name }} | {% endblock %} {% block content %} - {% include "includes/domain_request_status_view.html" %} + {% include "includes/portfolio_domain_request_status_view.html" %} {% endblock %} diff --git a/src/registrar/utility/enums.py b/src/registrar/utility/enums.py index c39dd61a1..ad98489e1 100644 --- a/src/registrar/utility/enums.py +++ b/src/registrar/utility/enums.py @@ -72,8 +72,6 @@ class PortfolioDomainRequestStep(StrEnum): appear in the order they are defined. (Order matters.) """ # Portfolio - # TODO - this does not exist yet. - # Fill this in for the portfolio domain request experience. REQUESTING_ENTITY = "portfolio" CURRENT_SITES = "current_sites" DOTGOV_DOMAIN = "dotgov_domain" diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index a3efa260b..2724ec649 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -756,20 +756,6 @@ class DomainRequestStatus(DomainRequestPermissionView): return True -class DomainRequestStatusViewOnly(DomainRequestPortfolioViewonlyView): - template_name = "domain_request_status_viewonly.html" - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - # Create a temp wizard object to grab the step list - wizard = PortfolioDomainRequestWizard() - wizard.request = self.request - context["Step"] = wizard.StepEnum.__members__ - context["steps"] = request_step_list(wizard) - context["form_titles"] = wizard.TITLES - return context - - class DomainRequestWithdrawConfirmation(DomainRequestPermissionWithdrawView): """This page will ask user to confirm if they want to withdraw @@ -902,3 +888,19 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView): duplicates = [item for item, count in object_dict.items() if count > 1] return duplicates + + +# region Portfolio views +class PortfolioDomainRequestStatusViewOnly(DomainRequestPortfolioViewonlyView): + template_name = "portfolio_domain_request_status_viewonly.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + # Create a temp wizard object to grab the step list + wizard = PortfolioDomainRequestWizard() + wizard.request = self.request + context["Step"] = wizard.StepEnum.__members__ + context["steps"] = request_step_list(wizard) + context["form_titles"] = wizard.TITLES + return context +# endregion From 1a8d668fb596a4e1f2b142b45de3d11db470b21a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:06:06 -0600 Subject: [PATCH 28/46] fix some bugs --- .../includes/domain_request_awaiting_review.html | 8 ++++---- .../includes/portfolio_request_review_steps.html | 13 ++++++++++--- .../portfolio_domain_request_status_viewonly.html | 2 +- src/registrar/utility/enums.py | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/registrar/templates/includes/domain_request_awaiting_review.html b/src/registrar/templates/includes/domain_request_awaiting_review.html index 18afc9903..cc9b31ccb 100644 --- a/src/registrar/templates/includes/domain_request_awaiting_review.html +++ b/src/registrar/templates/includes/domain_request_awaiting_review.html @@ -5,10 +5,10 @@

We received your .gov domain request. Our next step is to review your request. This usually takes 30 business days. We’ll email you if we have questions and when we complete our review. Contact us with any questions.

-

- Need to make changes? -

- {% if show_withdraw_text %} +

+ Need to make changes? +

+

If you need to change your request you have to first withdraw it. Once you withdraw the request you can edit it and submit it again. Changing your request might add to the wait time.

{% endif %} diff --git a/src/registrar/templates/includes/portfolio_request_review_steps.html b/src/registrar/templates/includes/portfolio_request_review_steps.html index 303da4675..8f7dba9ac 100644 --- a/src/registrar/templates/includes/portfolio_request_review_steps.html +++ b/src/registrar/templates/includes/portfolio_request_review_steps.html @@ -8,9 +8,16 @@ {% endif %} {% if step == Step.REQUESTING_ENTITY %} - {% with title=form_titles|get_item:step value=domain_request.portfolio|default:"Incomplete"|safe%} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %} - {% endwith %} + + {% if domain_request.organization_name %} + {% with title=form_titles|get_item:step value=domain_request %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url address='true' %} + {% endwith %} + {% else %} + {% with title=form_titles|get_item:step value="Incomplete"|safe %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %} + {% endwith %} + {% endif%} {% endif %} {% if step == Step.CURRENT_SITES %} diff --git a/src/registrar/templates/portfolio_domain_request_status_viewonly.html b/src/registrar/templates/portfolio_domain_request_status_viewonly.html index bb6ee1e66..0378d1b56 100644 --- a/src/registrar/templates/portfolio_domain_request_status_viewonly.html +++ b/src/registrar/templates/portfolio_domain_request_status_viewonly.html @@ -5,5 +5,5 @@ {% block title %}Domain request status | {{ DomainRequest.requested_domain.name }} | {% endblock %} {% block content %} - {% include "includes/portfolio_domain_request_status_view.html" %} + {% include "includes/portfolio_request_status_view.html" %} {% endblock %} diff --git a/src/registrar/utility/enums.py b/src/registrar/utility/enums.py index ad98489e1..21c03917c 100644 --- a/src/registrar/utility/enums.py +++ b/src/registrar/utility/enums.py @@ -72,7 +72,7 @@ class PortfolioDomainRequestStep(StrEnum): appear in the order they are defined. (Order matters.) """ # Portfolio - REQUESTING_ENTITY = "portfolio" + REQUESTING_ENTITY = "organization_name" CURRENT_SITES = "current_sites" DOTGOV_DOMAIN = "dotgov_domain" PURPOSE = "purpose" From b36bd289785689109ae9f88f632f88c3ac09bccd Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Fri, 20 Sep 2024 10:11:05 -0700 Subject: [PATCH 29/46] Update SCSS to allow wrapping instead of truncating --- src/registrar/assets/sass/_theme/_admin.scss | 13 +++++++------ src/registrar/templates/domain_base.html | 2 +- src/registrar/templates/domain_detail.html | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index c3caa053e..346b92389 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -931,9 +931,10 @@ ul.add-list-reset { font-size: 14px; } -.domain-name-truncate { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; -} \ No newline at end of file +.domain-name-wrap { + white-space: normal; /* Allows wrapping */ + word-wrap: break-word; /* Ensures that long words or URLs will break and wrap */ + overflow: visible; /* Ensures no truncation */ + word-break: break-all; /* Breaks words at any point if needed */ + max-width: 100%; /* Adjust as necessary to limit the width */ + } \ No newline at end of file diff --git a/src/registrar/templates/domain_base.html b/src/registrar/templates/domain_base.html index 9f6189fd8..9f7e8d2e6 100644 --- a/src/registrar/templates/domain_base.html +++ b/src/registrar/templates/domain_base.html @@ -9,7 +9,7 @@

Domain name: {{ domain.name }}

diff --git a/src/registrar/templates/domain_detail.html b/src/registrar/templates/domain_detail.html index 4b6ca6e77..dca68f6ef 100644 --- a/src/registrar/templates/domain_detail.html +++ b/src/registrar/templates/domain_detail.html @@ -5,7 +5,7 @@ {% block domain_content %} {{ block.super }}
-

{{ domain.name }}

+

{{ domain.name }}

Date: Fri, 20 Sep 2024 11:30:20 -0600 Subject: [PATCH 30/46] Add unit test for viewonly page --- src/registrar/tests/test_views_request.py | 37 +++++++++++++++++++++++ src/registrar/views/domain_request.py | 4 ++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/registrar/tests/test_views_request.py b/src/registrar/tests/test_views_request.py index 2cb3a381c..71aeb3c1d 100644 --- a/src/registrar/tests/test_views_request.py +++ b/src/registrar/tests/test_views_request.py @@ -3025,3 +3025,40 @@ class TestWizardUnlockingSteps(TestWithUser, WebTest): else: self.fail(f"Expected a redirect, but got a different response: {response}") + + +class TestPortfolioDomainRequestViewonly(TestWithUser, WebTest): + + # Doesn't work with CSRF checking + # hypothesis is that CSRF_USE_SESSIONS is incompatible with WebTest + csrf_checks = False + + def setUp(self): + super().setUp() + self.federal_agency, _ = FederalAgency.objects.get_or_create(agency="General Services Administration") + self.app.set_user(self.user.username) + self.TITLES = DomainRequestWizard.TITLES + + def tearDown(self): + super().tearDown() + DomainRequest.objects.all().delete() + DomainInformation.objects.all().delete() + self.federal_agency.delete() + + @less_console_noise_decorator + @override_flag("organization_feature", active=True) + def test_domain_request_viewonly_displays_correct_fields(self): + """Tests that the viewonly page displays different fields""" + portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Test Portfolio") + UserPortfolioPermission.objects.get_or_create( + user=self.user, portfolio=portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN] + ) + dummy_user, _ = User.objects.get_or_create(username="testusername123456") + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=dummy_user) + domain_request.save() + + detail_page = self.app.get(f"/domain-request/viewonly/{domain_request.id}") + self.assertContains(detail_page, "Requesting entity") + self.assertNotContains(detail_page, "Type of organization") + self.assertContains(detail_page, "city.gov") + self.assertContains(detail_page, "Status:") \ No newline at end of file diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index 2724ec649..8d0648e69 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -26,7 +26,6 @@ from .utility import ( logger = logging.getLogger(__name__) - class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): """ A common set of methods and configuration. @@ -43,6 +42,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): Any method not marked as internal can be overridden in a subclass, although not without consulting the base implementation, first. """ + StepEnum = Step template_name = "" @@ -903,4 +903,6 @@ class PortfolioDomainRequestStatusViewOnly(DomainRequestPortfolioViewonlyView): context["steps"] = request_step_list(wizard) context["form_titles"] = wizard.TITLES return context + + # endregion From 56a7cf6ac1001f89120154ab2e39d1e64c614b2c Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Fri, 20 Sep 2024 10:41:34 -0700 Subject: [PATCH 31/46] Remove extra comments --- src/registrar/assets/sass/_theme/_admin.scss | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 346b92389..3e6d0d171 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -932,9 +932,9 @@ ul.add-list-reset { } .domain-name-wrap { - white-space: normal; /* Allows wrapping */ - word-wrap: break-word; /* Ensures that long words or URLs will break and wrap */ - overflow: visible; /* Ensures no truncation */ - word-break: break-all; /* Breaks words at any point if needed */ - max-width: 100%; /* Adjust as necessary to limit the width */ + white-space: normal; + word-wrap: break-word; + overflow: visible; + word-break: break-all; + max-width: 100%; } \ No newline at end of file From 16076a1b7562d0baab7c9f769698854024c356de Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:44:45 -0600 Subject: [PATCH 32/46] Update test_models.py --- src/registrar/tests/test_models.py | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index a6e889503..a6cac1389 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -114,6 +114,54 @@ class TestDomainRequest(TestCase): with less_console_noise(): return self.assertRaises(Exception, None, exception_type) + @less_console_noise_decorator + def test_request_is_withdrawable(self): + """Tests the is_withdrawable function""" + domain_request_1 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.SUBMITTED, + name="city2.gov", + ) + domain_request_2 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.IN_REVIEW, + name="city3.gov", + ) + domain_request_3 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.ACTION_NEEDED, + name="city4.gov", + ) + domain_request_4 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.REJECTED, + name="city5.gov", + ) + self.assertTrue(domain_request_1.is_withdrawable()) + self.assertTrue(domain_request_2.is_withdrawable()) + self.assertTrue(domain_request_3.is_withdrawable()) + self.assertFalse(domain_request_4.is_withdrawable()) + + @less_console_noise_decorator + def test_request_is_awaiting_review(self): + """Tests the is_awaiting_review function""" + domain_request_1 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.SUBMITTED, + name="city2.gov", + ) + domain_request_2 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.IN_REVIEW, + name="city3.gov", + ) + domain_request_3 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.ACTION_NEEDED, + name="city4.gov", + ) + domain_request_4 = completed_domain_request( + status=DomainRequest.DomainRequestStatus.REJECTED, + name="city5.gov", + ) + self.assertTrue(domain_request_1.is_awaiting_review()) + self.assertTrue(domain_request_2.is_awaiting_review()) + self.assertFalse(domain_request_3.is_awaiting_review()) + self.assertFalse(domain_request_4.is_awaiting_review()) + @less_console_noise_decorator def test_federal_agency_set_to_non_federal_on_approve(self): """Ensures that when the federal_agency field is 'none' when .approve() is called, From 2f2dec715cce9160353ee40849794cf1f94835d0 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:48:37 -0600 Subject: [PATCH 33/46] linting --- src/registrar/forms/utility/wizard_form_helper.py | 1 - src/registrar/tests/test_views_request.py | 2 +- src/registrar/utility/enums.py | 3 +++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/registrar/forms/utility/wizard_form_helper.py b/src/registrar/forms/utility/wizard_form_helper.py index 578d6462d..45a493d30 100644 --- a/src/registrar/forms/utility/wizard_form_helper.py +++ b/src/registrar/forms/utility/wizard_form_helper.py @@ -290,4 +290,3 @@ def request_step_list(request_wizard): if condition: step_list.append(step) return step_list - diff --git a/src/registrar/tests/test_views_request.py b/src/registrar/tests/test_views_request.py index 71aeb3c1d..8530859e2 100644 --- a/src/registrar/tests/test_views_request.py +++ b/src/registrar/tests/test_views_request.py @@ -3061,4 +3061,4 @@ class TestPortfolioDomainRequestViewonly(TestWithUser, WebTest): self.assertContains(detail_page, "Requesting entity") self.assertNotContains(detail_page, "Type of organization") self.assertContains(detail_page, "city.gov") - self.assertContains(detail_page, "Status:") \ No newline at end of file + self.assertContains(detail_page, "Status:") diff --git a/src/registrar/utility/enums.py b/src/registrar/utility/enums.py index 21c03917c..b4fc5ed6f 100644 --- a/src/registrar/utility/enums.py +++ b/src/registrar/utility/enums.py @@ -3,6 +3,7 @@ from enum import Enum from registrar.utility import StrEnum + class ValidationReturnType(Enum): """Determines the return value of the validate_and_handle_errors class""" @@ -64,6 +65,7 @@ class Step(StrEnum): REQUIREMENTS = "requirements" REVIEW = "review" + class PortfolioDomainRequestStep(StrEnum): """ Names for each page of the portfolio domain request wizard. @@ -71,6 +73,7 @@ class PortfolioDomainRequestStep(StrEnum): As with Django's own `TextChoices` class, steps will appear in the order they are defined. (Order matters.) """ + # Portfolio REQUESTING_ENTITY = "organization_name" CURRENT_SITES = "current_sites" From 7ef2e953761bdc32bbb7e0544f5d86a47a12be07 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 20 Sep 2024 12:13:29 -0600 Subject: [PATCH 34/46] remove unused import --- src/registrar/forms/utility/wizard_form_helper.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/registrar/forms/utility/wizard_form_helper.py b/src/registrar/forms/utility/wizard_form_helper.py index 45a493d30..ba3c37e1e 100644 --- a/src/registrar/forms/utility/wizard_form_helper.py +++ b/src/registrar/forms/utility/wizard_form_helper.py @@ -4,7 +4,6 @@ from itertools import zip_longest from typing import Callable from django.db.models.fields.related import ForeignObjectRel from django import forms -from registrar.utility.enums import Step from registrar.models import DomainRequest, Contact From a0e745824fd97ce17f3ae1da1706d71471abb83a Mon Sep 17 00:00:00 2001 From: asaki222 Date: Fri, 20 Sep 2024 14:55:11 -0400 Subject: [PATCH 35/46] reverted a change --- src/registrar/templates/includes/summary_item.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/includes/summary_item.html b/src/registrar/templates/includes/summary_item.html index 93aada291..11e1d971b 100644 --- a/src/registrar/templates/includes/summary_item.html +++ b/src/registrar/templates/includes/summary_item.html @@ -7,7 +7,7 @@ {% if heading_level %} <{{ heading_level }} {% else %} -

@@ -15,7 +15,7 @@ {% if heading_level %} {% else %} -

+ {% endif %} {% if sub_header_text %}

{{ sub_header_text }}

From f6b2aa7a3f9a5177e3e152888af7e8199e18eb31 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Fri, 20 Sep 2024 12:56:32 -0600 Subject: [PATCH 36/46] Implemented Design feedback (updated margins for org domains table to match the margins for non-org domains table) --- src/registrar/templates/portfolio_base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/portfolio_base.html b/src/registrar/templates/portfolio_base.html index 054118468..86e43c962 100644 --- a/src/registrar/templates/portfolio_base.html +++ b/src/registrar/templates/portfolio_base.html @@ -8,7 +8,7 @@ {% if user.is_authenticated %} {# the entire logged in page goes here #} -
+
{% block messages %} {% include "includes/form_messages.html" %} {% endblock %} From 87dcbedb80d661681c4b9cdf88bc7c6aa05508b5 Mon Sep 17 00:00:00 2001 From: CuriousX Date: Fri, 20 Sep 2024 13:00:18 -0600 Subject: [PATCH 37/46] Update src/registrar/assets/sass/_theme/_base.scss Co-authored-by: Rachid Mrad <107004823+rachidatecs@users.noreply.github.com> --- src/registrar/assets/sass/_theme/_base.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/assets/sass/_theme/_base.scss b/src/registrar/assets/sass/_theme/_base.scss index 806261810..85f453dac 100644 --- a/src/registrar/assets/sass/_theme/_base.scss +++ b/src/registrar/assets/sass/_theme/_base.scss @@ -110,7 +110,7 @@ with the searchbar in widescreen mode. EXPLANATION: The existing frontend implementation puts the searchbar and export button in two separate columns in a grid, which creates a solid wrap-around effect -for mobile divices. The searchbar had a max-width that exactly equaled the max width +for mobile devices. The searchbar had a max-width that exactly equaled the max width of its parent column (for non-widescreens), so there wasn't any issue at this time of implementation. However, during immplementation of widescreen mode this small max-width caused the searchbar to From bb8e81ea8674c1fde2dad00c19277613dbad307d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:00:18 -0600 Subject: [PATCH 38/46] Update domain_request.py --- src/registrar/views/domain_request.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index 8d0648e69..b7462f300 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -43,7 +43,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): although not without consulting the base implementation, first. """ - StepEnum = Step + StepEnum: Step = Step # type: ignore template_name = "" # uniquely namespace the wizard in urls.py @@ -501,7 +501,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): # TODO - this is a WIP until the domain request experience for portfolios is complete class PortfolioDomainRequestWizard(DomainRequestWizard): - StepEnum = PortfolioDomainRequestStep + StepEnum: PortfolioDomainRequestStep = PortfolioDomainRequestStep # type: ignore TITLES = { StepEnum.REQUESTING_ENTITY: _("Requesting entity"), From f6cb03de87cddb7a362f50df07a9023aee716e6f Mon Sep 17 00:00:00 2001 From: CocoByte Date: Fri, 20 Sep 2024 13:04:11 -0600 Subject: [PATCH 39/46] fix footer widescreen --- src/registrar/assets/sass/_theme/_containers.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/assets/sass/_theme/_containers.scss b/src/registrar/assets/sass/_theme/_containers.scss index d9a127746..7473615ad 100644 --- a/src/registrar/assets/sass/_theme/_containers.scss +++ b/src/registrar/assets/sass/_theme/_containers.scss @@ -1,7 +1,8 @@ @use "uswds-core" as *; @use "base" as *; +//NOTE: !important is needed because it gets overriden by other .scss for footer nav .grid-container--widescreen, .usa-identifier__container--widescreen { - max-width: $widescreen-max-width; + max-width: $widescreen-max-width !important; } From de50e7b42026e7fa47e75c5e966dac8956fcef4f Mon Sep 17 00:00:00 2001 From: CocoByte Date: Fri, 20 Sep 2024 13:52:38 -0600 Subject: [PATCH 40/46] remove scss code from merge resolve --- src/registrar/assets/sass/_theme/_buttons.scss | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss index eb05d67e5..2e4469e12 100644 --- a/src/registrar/assets/sass/_theme/_buttons.scss +++ b/src/registrar/assets/sass/_theme/_buttons.scss @@ -236,14 +236,6 @@ a.withdraw_outline:active { 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 { From 36e50cb61af2a999a0fd64f0b9d63f9ea35f4b3c Mon Sep 17 00:00:00 2001 From: asaki222 Date: Fri, 20 Sep 2024 16:05:05 -0400 Subject: [PATCH 41/46] reverted to dt/dl list --- src/registrar/templates/includes/summary_item.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/registrar/templates/includes/summary_item.html b/src/registrar/templates/includes/summary_item.html index 11e1d971b..d22582da7 100644 --- a/src/registrar/templates/includes/summary_item.html +++ b/src/registrar/templates/includes/summary_item.html @@ -28,9 +28,9 @@ {% include "includes/contact.html" with contact=value|first %} {% else %} {% if value %} -
    +
    {% for item in value %} -
  • +

    Contact {{forloop.counter}}

    -
  • -
  • + +
    {% include "includes/contact.html" with contact=item %} -
  • + {% endfor %} -
+ {% elif custom_text_for_value_none %}

{{ custom_text_for_value_none }} From f974c64b328a4df29579582fc29448dd80d0a795 Mon Sep 17 00:00:00 2001 From: asaki222 Date: Fri, 20 Sep 2024 16:06:18 -0400 Subject: [PATCH 42/46] added back styling --- src/registrar/templates/includes/summary_item.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/includes/summary_item.html b/src/registrar/templates/includes/summary_item.html index d22582da7..a481b7a80 100644 --- a/src/registrar/templates/includes/summary_item.html +++ b/src/registrar/templates/includes/summary_item.html @@ -9,8 +9,11 @@ {% else %}

+ class="summary-item__title + font-sans-md + text-primary-dark text-semibold + margin-top-0 margin-bottom-05 + padding-right-1"> {{ title }} {% if heading_level %} From e12c406e2ee16f9da1303d34b0a95b8f130326e1 Mon Sep 17 00:00:00 2001 From: asaki222 Date: Fri, 20 Sep 2024 16:07:04 -0400 Subject: [PATCH 43/46] fixed spacing --- src/registrar/templates/includes/summary_item.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/templates/includes/summary_item.html b/src/registrar/templates/includes/summary_item.html index a481b7a80..29d366f6c 100644 --- a/src/registrar/templates/includes/summary_item.html +++ b/src/registrar/templates/includes/summary_item.html @@ -13,7 +13,8 @@ font-sans-md text-primary-dark text-semibold margin-top-0 margin-bottom-05 - padding-right-1"> + padding-right-1" + > {{ title }} {% if heading_level %} From 2e028a0f44ac2e60c0cfe6ac21c51927580b3461 Mon Sep 17 00:00:00 2001 From: asaki222 Date: Fri, 20 Sep 2024 16:07:40 -0400 Subject: [PATCH 44/46] fixed spacing again O.o --- src/registrar/templates/includes/summary_item.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/includes/summary_item.html b/src/registrar/templates/includes/summary_item.html index 29d366f6c..d4c68395f 100644 --- a/src/registrar/templates/includes/summary_item.html +++ b/src/registrar/templates/includes/summary_item.html @@ -14,7 +14,7 @@ text-primary-dark text-semibold margin-top-0 margin-bottom-05 padding-right-1" - > + > {{ title }} {% if heading_level %} From 7e3a2266a224fed31b3d48c2180ee0c8bd9423ea Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 20 Sep 2024 16:27:39 -0400 Subject: [PATCH 45/46] initial implementation --- src/registrar/models/user.py | 16 ++++---------- .../models/user_portfolio_permission.py | 8 ++----- src/registrar/tests/test_utilities.py | 22 +++++++++++++++++++ src/registrar/utility/email.py | 2 ++ src/registrar/utility/waffle.py | 11 ++++++++++ 5 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 src/registrar/tests/test_utilities.py create mode 100644 src/registrar/utility/waffle.py diff --git a/src/registrar/models/user.py b/src/registrar/models/user.py index 929a63525..ae76d648b 100644 --- a/src/registrar/models/user.py +++ b/src/registrar/models/user.py @@ -3,7 +3,6 @@ import logging from django.contrib.auth.models import AbstractUser from django.db import models from django.db.models import Q -from django.http import HttpRequest from registrar.models import DomainInformation, UserDomainRole from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices @@ -14,6 +13,7 @@ from .transition_domain import TransitionDomain from .verified_by_staff import VerifiedByStaff from .domain import Domain from .domain_request import DomainRequest +from registrar.utility.waffle import flag_is_active_for_user from waffle.decorators import flag_is_active from phonenumber_field.modelfields import PhoneNumberField # type: ignore @@ -204,14 +204,10 @@ class User(AbstractUser): ) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS) def has_organization_requests_flag(self): - request = HttpRequest() - request.user = self - return flag_is_active(request, "organization_requests") + return flag_is_active_for_user(self, "organization_requests") def has_organization_members_flag(self): - request = HttpRequest() - request.user = self - return flag_is_active(request, "organization_members") + return flag_is_active_for_user(self, "organization_members") def has_view_members_portfolio_permission(self, portfolio): # BEGIN @@ -422,12 +418,8 @@ class User(AbstractUser): for invitation in PortfolioInvitation.objects.filter( email__iexact=self.email, status=PortfolioInvitation.PortfolioInvitationStatus.INVITED ): - # need to create a bogus request and assign user to it, in order to pass request - # to flag_is_active - request = HttpRequest() - request.user = self only_single_portfolio = ( - not flag_is_active(request, "multiple_portfolios") and self.get_first_portfolio() is None + not flag_is_active_for_user(self, "multiple_portfolios") and self.get_first_portfolio() is None ) if only_single_portfolio or flag_is_active(None, "multiple_portfolios"): try: diff --git a/src/registrar/models/user_portfolio_permission.py b/src/registrar/models/user_portfolio_permission.py index 0c2487df3..f7bafc8c6 100644 --- a/src/registrar/models/user_portfolio_permission.py +++ b/src/registrar/models/user_portfolio_permission.py @@ -1,7 +1,6 @@ from django.db import models from django.forms import ValidationError -from django.http import HttpRequest -from waffle import flag_is_active +from registrar.utility.waffle import flag_is_active_for_user from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices from .utility.time_stamped_model import TimeStampedModel from django.contrib.postgres.fields import ArrayField @@ -101,11 +100,8 @@ class UserPortfolioPermission(TimeStampedModel): # Check if a user is set without accessing the related object. has_user = bool(self.user_id) if self.pk is None and has_user: - # Have to create a bogus request to set the user and pass to flag_is_active - request = HttpRequest() - request.user = self.user existing_permissions = UserPortfolioPermission.objects.filter(user=self.user) - if not flag_is_active(request, "multiple_portfolios") and existing_permissions.exists(): + if not flag_is_active_for_user(self.user, "multiple_portfolios") and existing_permissions.exists(): raise ValidationError( "Only one portfolio permission is allowed per user when multiple portfolios are disabled." ) diff --git a/src/registrar/tests/test_utilities.py b/src/registrar/tests/test_utilities.py new file mode 100644 index 000000000..b615ae71c --- /dev/null +++ b/src/registrar/tests/test_utilities.py @@ -0,0 +1,22 @@ +from django.test import TestCase +from django.contrib.auth.models import User +from waffle.testutils import override_flag +from registrar.utility.waffle import flag_is_active_for_user + +class FlagIsActiveForUserTest(TestCase): + + def setUp(self): + # Set up a test user + self.user = User.objects.create_user(username="testuser", password="testpassword") + + @override_flag("test_flag", active=True) + def test_flag_active_for_user(self): + # Test that the flag is active for the user + is_active = flag_is_active_for_user(self.user, "test_flag") + self.assertTrue(is_active) + + @override_flag("test_flag", active=False) + def test_flag_inactive_for_user(self): + # Test that the flag is inactive for the user + is_active = flag_is_active_for_user(self.user, "test_flag") + self.assertFalse(is_active) diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 1fe1be596..5f8a93bd9 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -108,6 +108,8 @@ def send_templated_email( def _can_send_email(to_address, bcc_address): """Raises an EmailSendingError if we cannot send an email. Does nothing otherwise.""" + # testing below a global waffle flag which will not be associated with a user + # or with http request, so pass None to flag_is_active if flag_is_active(None, "disable_email_sending"): # type: ignore message = "Could not send email. Email sending is disabled due to flag 'disable_email_sending'." raise EmailSendingError(message) diff --git a/src/registrar/utility/waffle.py b/src/registrar/utility/waffle.py new file mode 100644 index 000000000..16ec03f0d --- /dev/null +++ b/src/registrar/utility/waffle.py @@ -0,0 +1,11 @@ +from django.http import HttpRequest +from waffle.decorators import flag_is_active + +def flag_is_active_for_user(user, flag_name): + """flag_is_active_for_user can be used when a waffle_flag may be + activated for a user, but the context of where the flag needs to + be tested does not have a request object available. + When the request is available, flag_is_active should be used.""" + request = HttpRequest() + request.user = user + return flag_is_active(request, flag_name) \ No newline at end of file From 5475f07d9bd43c90c1e1c79907eaef2a65561203 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 20 Sep 2024 16:35:23 -0400 Subject: [PATCH 46/46] fixed unit test and linting --- src/registrar/tests/test_utilities.py | 5 +++-- src/registrar/utility/waffle.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/registrar/tests/test_utilities.py b/src/registrar/tests/test_utilities.py index b615ae71c..5a2234d66 100644 --- a/src/registrar/tests/test_utilities.py +++ b/src/registrar/tests/test_utilities.py @@ -1,13 +1,14 @@ from django.test import TestCase -from django.contrib.auth.models import User +from registrar.models import User from waffle.testutils import override_flag from registrar.utility.waffle import flag_is_active_for_user + class FlagIsActiveForUserTest(TestCase): def setUp(self): # Set up a test user - self.user = User.objects.create_user(username="testuser", password="testpassword") + self.user = User.objects.create_user(username="testuser") @override_flag("test_flag", active=True) def test_flag_active_for_user(self): diff --git a/src/registrar/utility/waffle.py b/src/registrar/utility/waffle.py index 16ec03f0d..a78799e4c 100644 --- a/src/registrar/utility/waffle.py +++ b/src/registrar/utility/waffle.py @@ -1,6 +1,7 @@ from django.http import HttpRequest from waffle.decorators import flag_is_active + def flag_is_active_for_user(user, flag_name): """flag_is_active_for_user can be used when a waffle_flag may be activated for a user, but the context of where the flag needs to @@ -8,4 +9,4 @@ def flag_is_active_for_user(user, flag_name): When the request is available, flag_is_active should be used.""" request = HttpRequest() request.user = user - return flag_is_active(request, flag_name) \ No newline at end of file + return flag_is_active(request, flag_name)