diff --git a/src/registrar/admin.py b/src/registrar/admin.py
index 7b04f3e9d..8afc2d97f 100644
--- a/src/registrar/admin.py
+++ b/src/registrar/admin.py
@@ -1995,7 +1995,7 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@admin.display(description=_("Requested Domain"))
def custom_requested_domain(self, obj):
# Example: Show different icons based on `status`
- url = reverse("admin:registrar_domainrequest_changelist") + f"?portfolio={obj.id}"
+ url = reverse("admin:registrar_domainrequest_changelist") + f"{obj.id}"
text = obj.requested_domain
if obj.portfolio:
return format_html(' {} ', url, text)
diff --git a/src/registrar/assets/src/js/getgov/domain-dnssec.js b/src/registrar/assets/src/js/getgov/domain-dnssec.js
new file mode 100644
index 000000000..860359fe0
--- /dev/null
+++ b/src/registrar/assets/src/js/getgov/domain-dnssec.js
@@ -0,0 +1,15 @@
+import { submitForm } from './helpers.js';
+
+export function initDomainDNSSEC() {
+ document.addEventListener('DOMContentLoaded', function() {
+ let domain_dnssec_page = document.getElementById("domain-dnssec");
+ if (domain_dnssec_page) {
+ const button = document.getElementById("disable-dnssec-button");
+ if (button) {
+ button.addEventListener("click", function () {
+ submitForm("disable-dnssec-form");
+ });
+ }
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/registrar/assets/src/js/getgov/domain-dsdata.js b/src/registrar/assets/src/js/getgov/domain-dsdata.js
new file mode 100644
index 000000000..7c0871bec
--- /dev/null
+++ b/src/registrar/assets/src/js/getgov/domain-dsdata.js
@@ -0,0 +1,27 @@
+import { submitForm } from './helpers.js';
+
+export function initDomainDSData() {
+ document.addEventListener('DOMContentLoaded', function() {
+ let domain_dsdata_page = document.getElementById("domain-dsdata");
+ if (domain_dsdata_page) {
+ const override_button = document.getElementById("disable-override-click-button");
+ const cancel_button = document.getElementById("btn-cancel-click-button");
+ const cancel_close_button = document.getElementById("btn-cancel-click-close-button");
+ if (override_button) {
+ override_button.addEventListener("click", function () {
+ submitForm("disable-override-click-form");
+ });
+ }
+ if (cancel_button) {
+ cancel_button.addEventListener("click", function () {
+ submitForm("btn-cancel-click-form");
+ });
+ }
+ if (cancel_close_button) {
+ cancel_close_button.addEventListener("click", function () {
+ submitForm("btn-cancel-click-form");
+ });
+ }
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/registrar/assets/src/js/getgov/domain-managers.js b/src/registrar/assets/src/js/getgov/domain-managers.js
new file mode 100644
index 000000000..26eccd8cd
--- /dev/null
+++ b/src/registrar/assets/src/js/getgov/domain-managers.js
@@ -0,0 +1,20 @@
+import { submitForm } from './helpers.js';
+
+export function initDomainManagersPage() {
+ document.addEventListener('DOMContentLoaded', function() {
+ let domain_managers_page = document.getElementById("domain-managers");
+ if (domain_managers_page) {
+ // Add event listeners for all buttons matching user-delete-button-{NUMBER}
+ const deleteButtons = document.querySelectorAll('[id^="user-delete-button-"]'); // Select buttons with ID starting with "user-delete-button-"
+ deleteButtons.forEach((button) => {
+ const buttonId = button.id; // e.g., "user-delete-button-1"
+ const number = buttonId.split('-').pop(); // Extract the NUMBER part
+ const formId = `user-delete-form-${number}`; // Generate the corresponding form ID
+
+ button.addEventListener("click", function () {
+ submitForm(formId); // Pass the form ID to submitForm
+ });
+ });
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/registrar/assets/src/js/getgov/domain-request-form.js b/src/registrar/assets/src/js/getgov/domain-request-form.js
new file mode 100644
index 000000000..d9b660a50
--- /dev/null
+++ b/src/registrar/assets/src/js/getgov/domain-request-form.js
@@ -0,0 +1,12 @@
+import { submitForm } from './helpers.js';
+
+export function initDomainRequestForm() {
+ document.addEventListener('DOMContentLoaded', function() {
+ const button = document.getElementById("domain-request-form-submit-button");
+ if (button) {
+ button.addEventListener("click", function () {
+ submitForm("submit-domain-request-form");
+ });
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/registrar/assets/src/js/getgov/form-errors.js b/src/registrar/assets/src/js/getgov/form-errors.js
new file mode 100644
index 000000000..ec1faaccf
--- /dev/null
+++ b/src/registrar/assets/src/js/getgov/form-errors.js
@@ -0,0 +1,19 @@
+export function initFormErrorHandling() {
+ document.addEventListener('DOMContentLoaded', function() {
+ const errorSummary = document.getElementById('form-errors');
+ const firstErrorField = document.querySelector('.usa-input--error');
+ if (firstErrorField) {
+ // Scroll to the first field in error
+ firstErrorField.scrollIntoView({ behavior: 'smooth', block: 'center' });
+
+ // Add focus to the first field in error
+ setTimeout(() => {
+ firstErrorField.focus();
+ }, 50);
+ } else if (errorSummary) {
+ // Scroll to the error summary
+ errorSummary.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }
+
+ });
+}
\ No newline at end of file
diff --git a/src/registrar/assets/src/js/getgov/helpers.js b/src/registrar/assets/src/js/getgov/helpers.js
index 1afd84520..93c25ee45 100644
--- a/src/registrar/assets/src/js/getgov/helpers.js
+++ b/src/registrar/assets/src/js/getgov/helpers.js
@@ -75,3 +75,16 @@ export function debounce(handler, cooldown=600) {
export function getCsrfToken() {
return document.querySelector('input[name="csrfmiddlewaretoken"]').value;
}
+
+/**
+ * Helper function to submit a form
+ * @param {} form_id - the id of the form to be submitted
+ */
+export function submitForm(form_id) {
+ let form = document.getElementById(form_id);
+ if (form) {
+ form.submit();
+ } else {
+ console.error("Form '" + form_id + "' not found.");
+ }
+}
diff --git a/src/registrar/assets/src/js/getgov/main.js b/src/registrar/assets/src/js/getgov/main.js
index f5ebc83a3..6ff402aa4 100644
--- a/src/registrar/assets/src/js/getgov/main.js
+++ b/src/registrar/assets/src/js/getgov/main.js
@@ -11,6 +11,11 @@ import { initMembersTable } from './table-members.js';
import { initMemberDomainsTable } from './table-member-domains.js';
import { initEditMemberDomainsTable } from './table-edit-member-domains.js';
import { initPortfolioNewMemberPageToggle, initAddNewMemberPageListeners, initPortfolioMemberPageRadio } from './portfolio-member-page.js';
+import { initDomainRequestForm } from './domain-request-form.js';
+import { initDomainManagersPage } from './domain-managers.js';
+import { initDomainDSData } from './domain-dsdata.js';
+import { initDomainDNSSEC } from './domain-dnssec.js';
+import { initFormErrorHandling } from './form-errors.js';
initDomainValidators();
@@ -36,6 +41,13 @@ initMembersTable();
initMemberDomainsTable();
initEditMemberDomainsTable();
+initDomainRequestForm();
+initDomainManagersPage();
+initDomainDSData();
+initDomainDNSSEC();
+
+initFormErrorHandling();
+
// Init the portfolio new member page
initPortfolioMemberPageRadio();
initPortfolioNewMemberPageToggle();
diff --git a/src/registrar/assets/src/js/getgov/table-base.js b/src/registrar/assets/src/js/getgov/table-base.js
index e526c6b5f..97c256734 100644
--- a/src/registrar/assets/src/js/getgov/table-base.js
+++ b/src/registrar/assets/src/js/getgov/table-base.js
@@ -495,7 +495,8 @@ export class BaseTable {
// Add event listeners to table headers for sorting
initializeTableHeaders() {
this.tableHeaders.forEach(header => {
- header.addEventListener('click', () => {
+ header.addEventListener('click', event => {
+ let button = header.querySelector('.usa-table__header__button')
const sortBy = header.getAttribute('data-sortable');
let order = 'asc';
// sort order will be ascending, unless the currently sorted column is ascending, and the user
@@ -505,6 +506,13 @@ export class BaseTable {
}
// load the results with the updated sort
this.loadTable(1, sortBy, order);
+ // If the click occurs outside of the button, need to simulate a button click in order
+ // for USWDS listener on the button to execute.
+ // Check first to see if click occurs outside of the button
+ if (!button.contains(event.target)) {
+ // Simulate a button click
+ button.click();
+ }
});
});
}
diff --git a/src/registrar/assets/src/js/getgov/table-domains.js b/src/registrar/assets/src/js/getgov/table-domains.js
index 20d9ef7de..a6373a5c2 100644
--- a/src/registrar/assets/src/js/getgov/table-domains.js
+++ b/src/registrar/assets/src/js/getgov/table-domains.js
@@ -31,6 +31,9 @@ export class DomainsTable extends BaseTable {
`
}
+ const isExpiring = domain.state_display === "Expiring soon"
+ const iconType = isExpiring ? "error_outline" : "info_outline";
+ const iconColor = isExpiring ? "text-secondary-vivid" : "text-accent-cool"
row.innerHTML = `
${domain.name}
@@ -41,14 +44,14 @@ export class DomainsTable extends BaseTable {
${domain.state_display}
-
+
${markupForSuborganizationRow}
@@ -77,3 +80,30 @@ export function initDomainsTable() {
}
});
}
+
+// For clicking the "Expiring" checkbox
+document.addEventListener('DOMContentLoaded', () => {
+ const expiringLink = document.getElementById('link-expiring-domains');
+
+ if (expiringLink) {
+ // Grab the selection for the status filter by
+ const statusCheckboxes = document.querySelectorAll('input[name="filter-status"]');
+
+ expiringLink.addEventListener('click', (event) => {
+ event.preventDefault();
+ // Loop through all statuses
+ statusCheckboxes.forEach(checkbox => {
+ // To find the for checkbox for "Expiring soon"
+ if (checkbox.value === "expiring") {
+ // If the checkbox is not already checked, check it
+ if (!checkbox.checked) {
+ checkbox.checked = true;
+ // Do the checkbox action
+ let event = new Event('change');
+ checkbox.dispatchEvent(event)
+ }
+ }
+ });
+ });
+ }
+});
\ No newline at end of file
diff --git a/src/registrar/assets/src/sass/_theme/_admin.scss b/src/registrar/assets/src/sass/_theme/_admin.scss
index 58ce1e4df..5bb523cac 100644
--- a/src/registrar/assets/src/sass/_theme/_admin.scss
+++ b/src/registrar/assets/src/sass/_theme/_admin.scss
@@ -176,7 +176,16 @@ html[data-theme="dark"] {
color: var(--primary-fg);
}
+// Reset the USWDS styles for alerts
+@include at-media(desktop) {
+ .dashboard .usa-alert__body--widescreen {
+ padding-left: 4rem !important;
+ }
+ .dashboard .usa-alert__body--widescreen::before {
+ left: 1.5rem !important;
+ }
+}
#branding h1,
h1, h2, h3,
diff --git a/src/registrar/assets/src/sass/_theme/_alerts.scss b/src/registrar/assets/src/sass/_theme/_alerts.scss
index 9579cc057..b27fa8806 100644
--- a/src/registrar/assets/src/sass/_theme/_alerts.scss
+++ b/src/registrar/assets/src/sass/_theme/_alerts.scss
@@ -1,21 +1,18 @@
@use "uswds-core" as *;
@use "base" as *;
-// Fixes some font size disparities with the Figma
-// for usa-alert alert elements
-.usa-alert {
- .usa-alert__heading.larger-font-sizing {
- font-size: units(3);
- }
-}
-.usa-alert__text.measure-none {
- max-width: measure(none);
-}
+/*----------------
+ Alert Layout
+-----------------*/
// The icon was off center for some reason
// Fixes that issue
-@media (min-width: 64em){
+@include at-media(desktop) {
+ // NOTE: !important is used because _font.scss overrides this
+ .usa-alert__body--widescreen {
+ max-width: $widescreen-max-width !important;
+ }
.usa-alert--warning{
.usa-alert__body::before {
left: 1rem !important;
@@ -24,13 +21,29 @@
.usa-alert__body.margin-left-1 {
margin-left: 0.5rem!important;
}
+
+ .usa-alert__body--widescreen::before {
+ left: 4rem !important;
+ }
+ .usa-alert__body--widescreen {
+ padding-left: 7rem!important;
+ }
}
-// NOTE: !important is used because _font.scss overrides this
-.usa-alert__body--widescreen {
- max-width: $widescreen-max-width !important;
+/*----------------
+ Alert Fonts
+-----------------*/
+// Fixes some font size disparities with the Figma
+// for usa-alert alert elements
+.usa-alert {
+ .usa-alert__heading.larger-font-sizing {
+ font-size: 1.5rem;
+ }
}
+/*----------------
+ Alert Coloring
+-----------------*/
.usa-site-alert--hot-pink {
.usa-alert {
background-color: $hot-pink;
@@ -47,3 +60,4 @@
background-color: color('base-darkest');
}
}
+
diff --git a/src/registrar/assets/src/sass/_theme/_base.scss b/src/registrar/assets/src/sass/_theme/_base.scss
index 62f9f436e..23f6b6978 100644
--- a/src/registrar/assets/src/sass/_theme/_base.scss
+++ b/src/registrar/assets/src/sass/_theme/_base.scss
@@ -2,6 +2,8 @@
@use "cisa_colors" as *;
$widescreen-max-width: 1920px;
+$widescreen-x-padding: 4.5rem;
+
$hot-pink: #FFC3F9;
/* Styles for making visible to screen reader / AT users only. */
@@ -252,6 +254,15 @@ abbr[title] {
max-width: $widescreen-max-width;
}
+// This is used in cases where we want to align content to widescreen margins
+// but we don't want the content itself to have widescreen widths
+@include at-media(desktop) {
+ .padding-x--widescreen {
+ padding-left: $widescreen-x-padding !important;
+ padding-right: $widescreen-x-padding !important;
+ }
+}
+
.margin-right-neg-4px {
margin-right: -4px;
}
@@ -265,4 +276,8 @@ abbr[title] {
margin: 0;
height: 1.5em;
width: 1.5em;
+}
+
+.maxw-fit-content {
+ max-width: fit-content;
}
\ No newline at end of file
diff --git a/src/registrar/assets/src/sass/_theme/_containers.scss b/src/registrar/assets/src/sass/_theme/_containers.scss
index 7473615ad..24ad480f2 100644
--- a/src/registrar/assets/src/sass/_theme/_containers.scss
+++ b/src/registrar/assets/src/sass/_theme/_containers.scss
@@ -6,3 +6,21 @@
.usa-identifier__container--widescreen {
max-width: $widescreen-max-width !important;
}
+
+
+// NOTE: !important is used because we are overriding default
+// USWDS paddings in a few locations
+@include at-media(desktop) {
+ .grid-container--widescreen {
+ padding-left: $widescreen-x-padding !important;
+ padding-right: $widescreen-x-padding !important;
+ }
+}
+
+// matches max-width to equal the max-width of .grid-container
+// used to trick the eye into thinking we have left-aligned a
+// regular grid-container within a widescreen (see instances
+// where is_widescreen_centered is used in the html).
+.max-width--grid-container {
+ max-width: 960px;
+}
\ No newline at end of file
diff --git a/src/registrar/assets/src/sass/_theme/_header.scss b/src/registrar/assets/src/sass/_theme/_header.scss
index 53eab90d8..ffb880a7b 100644
--- a/src/registrar/assets/src/sass/_theme/_header.scss
+++ b/src/registrar/assets/src/sass/_theme/_header.scss
@@ -110,8 +110,8 @@
}
}
.usa-nav__secondary {
- // I don't know why USWDS has this at 2 rem, which puts it out of alignment
- right: 3rem;
+ right: 1rem;
+ padding-right: $widescreen-x-padding;
color: color('white');
bottom: 4.3rem;
.usa-nav-link,
diff --git a/src/registrar/assets/src/sass/_theme/_tables.scss b/src/registrar/assets/src/sass/_theme/_tables.scss
index 45f0b5245..ea160396e 100644
--- a/src/registrar/assets/src/sass/_theme/_tables.scss
+++ b/src/registrar/assets/src/sass/_theme/_tables.scss
@@ -88,8 +88,14 @@ th {
}
@include at-media(tablet-lg) {
- th[data-sortable]:not([aria-sort]) .usa-table__header__button {
+ th[data-sortable] .usa-table__header__button {
right: auto;
+
+ &[aria-sort=ascending],
+ &[aria-sort=descending],
+ &:not([aria-sort]) {
+ right: auto;
+ }
}
}
}
diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py
index 050950c9b..0111245a1 100644
--- a/src/registrar/config/settings.py
+++ b/src/registrar/config/settings.py
@@ -251,7 +251,7 @@ TEMPLATES = [
"registrar.context_processors.org_user_status",
"registrar.context_processors.add_path_to_context",
"registrar.context_processors.portfolio_permissions",
- "registrar.context_processors.is_widescreen_mode",
+ "registrar.context_processors.is_widescreen_centered",
],
},
},
diff --git a/src/registrar/context_processors.py b/src/registrar/context_processors.py
index 9f5d0162f..b3d9c3727 100644
--- a/src/registrar/context_processors.py
+++ b/src/registrar/context_processors.py
@@ -69,9 +69,19 @@ def portfolio_permissions(request):
"has_organization_requests_flag": False,
"has_organization_members_flag": False,
"is_portfolio_admin": False,
+ "has_domain_renewal_flag": False,
}
try:
portfolio = request.session.get("portfolio")
+
+ # These feature flags will display and doesn't depend on portfolio
+ portfolio_context.update(
+ {
+ "has_organization_feature_flag": True,
+ "has_domain_renewal_flag": request.user.has_domain_renewal_flag(),
+ }
+ )
+
# Linting: line too long
view_suborg = request.user.has_view_suborganization_portfolio_permission(portfolio)
edit_suborg = request.user.has_edit_suborganization_portfolio_permission(portfolio)
@@ -90,6 +100,7 @@ def portfolio_permissions(request):
"has_organization_requests_flag": request.user.has_organization_requests_flag(),
"has_organization_members_flag": request.user.has_organization_members_flag(),
"is_portfolio_admin": request.user.is_portfolio_admin(portfolio),
+ "has_domain_renewal_flag": request.user.has_domain_renewal_flag(),
}
return portfolio_context
@@ -98,31 +109,21 @@ def portfolio_permissions(request):
return portfolio_context
-def is_widescreen_mode(request):
- widescreen_paths = [] # If this list is meant to include specific paths, populate it.
- portfolio_widescreen_paths = [
+def is_widescreen_centered(request):
+ include_paths = [
"/domains/",
"/requests/",
- "/request/",
- "/no-organization-requests/",
- "/no-organization-domains/",
- "/domain-request/",
+ "/members/",
]
- # widescreen_paths can be a bear as it trickles down sub-urls. exclude_paths gives us a way out.
exclude_paths = [
"/domains/edit",
+ "members/new-member/",
]
- # Check if the current path matches a widescreen path or the root path.
- is_widescreen = any(path in request.path for path in widescreen_paths) or request.path == "/"
+ is_excluded = any(exclude_path in request.path for exclude_path in exclude_paths)
- # Check if the user is an organization user and the path matches portfolio paths.
- is_portfolio_widescreen = (
- hasattr(request.user, "is_org_user")
- and request.user.is_org_user(request)
- and any(path in request.path for path in portfolio_widescreen_paths)
- and not any(exclude_path in request.path for exclude_path in exclude_paths)
- )
+ # Check if the current path matches a path in included_paths or the root path.
+ is_widescreen_centered = any(path in request.path for path in include_paths) or request.path == "/"
# Return a dictionary with the widescreen mode status.
- return {"is_widescreen_mode": is_widescreen or is_portfolio_widescreen}
+ return {"is_widescreen_centered": is_widescreen_centered and not is_excluded}
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 19e96719f..6eb2fac07 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -2,7 +2,7 @@ from itertools import zip_longest
import logging
import ipaddress
import re
-from datetime import date
+from datetime import date, timedelta
from typing import Optional
from django_fsm import FSMField, transition, TransitionNotAllowed # type: ignore
@@ -40,6 +40,7 @@ from .utility.time_stamped_model import TimeStampedModel
from .public_contact import PublicContact
from .user_domain_role import UserDomainRole
+from waffle.decorators import flag_is_active
logger = logging.getLogger(__name__)
@@ -1152,14 +1153,29 @@ class Domain(TimeStampedModel, DomainHelper):
now = timezone.now().date()
return self.expiration_date < now
- def state_display(self):
+ def is_expiring(self):
+ """
+ Check if the domain's expiration date is within 60 days.
+ Return True if domain expiration date exists and within 60 days
+ and otherwise False bc there's no expiration date meaning so not expiring
+ """
+ if self.expiration_date is None:
+ return False
+
+ now = timezone.now().date()
+
+ threshold_date = now + timedelta(days=60)
+ return now < self.expiration_date <= threshold_date
+
+ def state_display(self, request=None):
"""Return the display status of the domain."""
- if self.is_expired() and self.state != self.State.UNKNOWN:
+ if self.is_expired() and (self.state != self.State.UNKNOWN):
return "Expired"
+ elif flag_is_active(request, "domain_renewal") and self.is_expiring():
+ return "Expiring soon"
elif self.state == self.State.UNKNOWN or self.state == self.State.DNS_NEEDED:
return "DNS needed"
- else:
- return self.state.capitalize()
+ return self.state.capitalize()
def map_epp_contact_to_public_contact(self, contact: eppInfo.InfoContactResultData, contact_id, contact_type):
"""Maps the Epp contact representation to a PublicContact object.
diff --git a/src/registrar/models/user.py b/src/registrar/models/user.py
index bdfc6f804..2b5b56a78 100644
--- a/src/registrar/models/user.py
+++ b/src/registrar/models/user.py
@@ -14,6 +14,8 @@ 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 django.utils import timezone
+from datetime import timedelta
from phonenumber_field.modelfields import PhoneNumberField # type: ignore
@@ -163,6 +165,20 @@ class User(AbstractUser):
active_requests_count = self.domain_requests_created.filter(status__in=allowed_states).count()
return active_requests_count
+ def get_num_expiring_domains(self, request):
+ """Return number of expiring domains"""
+ domain_ids = self.get_user_domain_ids(request)
+ now = timezone.now().date()
+ expiration_window = 60
+ threshold_date = now + timedelta(days=expiration_window)
+ num_of_expiring_domains = Domain.objects.filter(
+ id__in=domain_ids,
+ expiration_date__isnull=False,
+ expiration_date__lte=threshold_date,
+ expiration_date__gt=now,
+ ).count()
+ return num_of_expiring_domains
+
def get_rejected_requests_count(self):
"""Return count of rejected requests"""
return self.domain_requests_created.filter(status=DomainRequest.DomainRequestStatus.REJECTED).count()
@@ -259,6 +275,9 @@ class User(AbstractUser):
def is_portfolio_admin(self, portfolio):
return "Admin" in self.portfolio_role_summary(portfolio)
+ def has_domain_renewal_flag(self):
+ return flag_is_active_for_user(self, "domain_renewal")
+
def get_first_portfolio(self):
permission = self.portfolio_permissions.first()
if permission:
diff --git a/src/registrar/templates/401.html b/src/registrar/templates/401.html
index d7c7f83ae..7698c4f82 100644
--- a/src/registrar/templates/401.html
+++ b/src/registrar/templates/401.html
@@ -5,8 +5,8 @@
{% block title %}{% translate "Unauthorized | " %}{% endblock %}
{% block content %}
-
-
+
+
{% translate "You are not authorized to view this page" %}
diff --git a/src/registrar/templates/403.html b/src/registrar/templates/403.html
index 999d5f98e..a04453fe9 100644
--- a/src/registrar/templates/403.html
+++ b/src/registrar/templates/403.html
@@ -5,8 +5,8 @@
{% block title %}{% translate "Forbidden | " %}{% endblock %}
{% block content %}
-
-
+
+
{% translate "You're not authorized to view this page." %}
diff --git a/src/registrar/templates/404.html b/src/registrar/templates/404.html
index 471575558..2bf9ecf02 100644
--- a/src/registrar/templates/404.html
+++ b/src/registrar/templates/404.html
@@ -5,8 +5,8 @@
{% block title %}{% translate "Page not found | " %}{% endblock %}
{% block content %}
-
-
+
+
{% translate "We couldn’t find that page" %}
diff --git a/src/registrar/templates/500.html b/src/registrar/templates/500.html
index a0663816b..fad909ddb 100644
--- a/src/registrar/templates/500.html
+++ b/src/registrar/templates/500.html
@@ -5,8 +5,8 @@
{% block title %}{% translate "Server error | " %}{% endblock %}
{% block content %}
-
-
+
+
{% translate "We're having some trouble." %}
diff --git a/src/registrar/templates/admin/app_list.html b/src/registrar/templates/admin/app_list.html
index 49fb59e79..aaf3dc423 100644
--- a/src/registrar/templates/admin/app_list.html
+++ b/src/registrar/templates/admin/app_list.html
@@ -39,7 +39,7 @@
{% for model in app.models %}
{% if model.admin_url %}
- {{ model.name }}
+ {{ model.name }}
{% else %}
{{ model.name }}
{% endif %}
diff --git a/src/registrar/templates/admin/fieldset.html b/src/registrar/templates/admin/fieldset.html
index 40cd98ca8..20b76217b 100644
--- a/src/registrar/templates/admin/fieldset.html
+++ b/src/registrar/templates/admin/fieldset.html
@@ -61,7 +61,7 @@ https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/
{% if field.field.help_text %}
{# .gov override #}
{% block help_text %}
-
+
{{ field.field.help_text|safe }}
{% endblock help_text %}
diff --git a/src/registrar/templates/admin/transfer_user.html b/src/registrar/templates/admin/transfer_user.html
index 3ba136b93..61444b173 100644
--- a/src/registrar/templates/admin/transfer_user.html
+++ b/src/registrar/templates/admin/transfer_user.html
@@ -43,7 +43,7 @@
Select a user
{% for user in other_users %}
-
+
{{ user.first_name }} {{ user.last_name }}
{% endfor %}
diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html
index de257f52c..dd6417ccb 100644
--- a/src/registrar/templates/base.html
+++ b/src/registrar/templates/base.html
@@ -97,7 +97,7 @@