Repository: cisagov/manage.get.gov

Issue:
Content: Standardize HTML Page Titles
### Issue Description
There are inconsistencies in how HTML page titles are written. 

Follow @kristinacyin's document by using her commented suggestions as a instructions on how to adjust our html page titles on manage.get.gov 

### Acceptance Criteria

- [ ] change the html page titles for manage.get.gov (including admin) by using [this document](https://docs.google.com/document/d/1Nk92LNq0pbPDS0EOjIsIcDEiP2da0Q5j7HoJF7l3xqo/edit#heading=h.hrnpd9cy4be
). All manage.get.gov titles with Word document Suggestions are the ones that need to be changed. **Ignore all the ones for audit logs**

out of scope: changing routes or get.gov titles. 

### Additional Context (optional)

[Discussion on Slack thread](https://cisa-corp.slack.com/archives/C06ES686Q2E/p1706821760593799) about changing tab titles to start with more specific information to generic & maybe removing unneeded information

> I'm wondering if we should go from specific > general in the order of things. For example:
Should  Request a .gov | Review and submit your domain request | .gov Registrar be Review and submit your domain request | Request a .gov | .gov Registrar? -Michelle

> I'm also wondering if we even need the "Request a .gov" part of this. -Michelle

> I'm gonna throw out a curveball.. what about ".Gov domain request | page title" remove "| .gov Registrar" altogether? -Gaby

### Issue Links
Relates to: https://github.com/cisagov/get.gov/issues/299
Related to #1385 ???



Discussion:
@Katherine-Osos - is this pertaining to beta.get.gov or registrar?

@Katherine-Osos, has this been subsumed into the larger content review work? https://github.com/cisagov/manage.get.gov/issues?q=is%3Aissue+is%3Aopen+review+label%3Acontent

@michelle-rago filed a [targeted example](https://github.com/cisagov/manage.get.gov/issues/1385) to fix, too. 
@h-m-f-t For the most part, yes. However, we have multiple people reviewing the content so there's still a chance for inconsistencies in approach. We also need to document the standard in our content guide.

I think we should keep this ticket to do one final pass thru after the content review is completed. But it should be fairly quick.
Ran into issues with my sandbox - will delete branch, pull from main, and redo
Added "dev" label: during pre-sprint planning, the decision from the leads were to assign the remaining work to the dev team. Slotted remaining work for sprint 45.
In hindsight @vickyszuchin I should have realized this needs a bit of refinement before we switched it to dev. I realize this requires a content decision as well as documentation for that content decision, @kristinacyin is that part done? Is the decision just to do "Gov domain request | page title"? This was my assumption but I realized that was based on the PR not on what is documented here.

I temporarily moved this to sprint 46 since there is an outstanding question. cc @Katherine-Osos 
Added "refinement" label, see comment from Alysia on 5/6.
I finally finished updating this doc: https://docs.google.com/document/d/1Nk92LNq0pbPDS0EOjIsIcDEiP2da0Q5j7HoJF7l3xqo/edit?usp=sharing

The suggestions that haven't been accepted yet are changes that still need to be implemented. 

There is a current PR for get.gov changes: https://github.com/cisagov/get.gov/pull/293

There is no current PR for manage.get.gov changes.

FYI: @abroddrick @vickyszuchin 
"refinement" label added:  while the document is being reviewed by dev team.
@kristinacyin

1. Am I understanding correctly that this document is meant to show the actual html page titles we want, and thus that part is decided and now we just need to update them in the code, correct?

2. were route/url changes also supposed to be included in this ticket as an AC or no?
@abroddrick 

1. Only suggestions in the doc need to paid attention to, everything else is what already exists/have already been changed. The suggestions are the changes we want and have already been decided on. 
2.  Yes, changes in the doc are included in the ticket, but can be split to another ticket if it makes more sense to do so. 
Thanks @kristinacyin that clarifies things! I will make it clear the scope is just the html page titles not the routes. Kristina, I am finding it hard to use the suggestions. I can't click a suggestion and have it take to that spot, so I have to scroll through the document and the coloration is kind of hard to tell what's a suggestion because it switches colors based on what was changed. I would not recommend using this format going forward as it's hard for me to actually see the scope of the changes and it will be difficult for someone to make sure they completed everything.
@vickyszuchin can we get a ticket for the get.gov portion and any routes that need to be adjusted

Resolving patch:
diff --git a/src/registrar/admin.py b/src/registrar/admin.py
--- a/src/registrar/admin.py
+++ b/src/registrar/admin.py
@@ -383,6 +383,39 @@ def created(self, obj):
     change_form_template = "admin/change_form_no_submit.html"
     add_form_template = "admin/change_form_no_submit.html"
 
+    # Select log entry to change ->  Log entries
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "Log entries"
+        return super().changelist_view(request, extra_context=extra_context)
+
+    # #786: Skipping on updating audit log tab titles for now
+    # def change_view(self, request, object_id, form_url="", extra_context=None):
+    #     if extra_context is None:
+    #         extra_context = {}
+
+    #     log_entry = self.get_object(request, object_id)
+
+    #     if log_entry:
+    #         # Reset title to empty string
+    #         extra_context["subtitle"] = ""
+    #         extra_context["tabtitle"] = ""
+
+    #         object_repr = log_entry.object_repr  # Hold name of the object
+    #         changes = log_entry.changes
+
+    #         # Check if this is a log entry for an addition and related to the contact model
+    #         # Created [name] -> Created [name] contact | Change log entry
+    #         if (
+    #             all(new_value != "None" for field, (old_value, new_value) in changes.items())
+    #             and log_entry.content_type.model == "contact"
+    #         ):
+    #             extra_context["subtitle"] = f"Created {object_repr} contact"
+    #             extra_context["tabtitle"] = "Change log entry"
+
+    #     return super().change_view(request, object_id, form_url, extra_context=extra_context)
+
 
 class AdminSortFields:
     _name_sort = ["first_name", "last_name", "email"]
@@ -778,6 +811,14 @@ class MyHostAdmin(AuditedAdmin, ImportExportModelAdmin):
     search_help_text = "Search by domain or host name."
     inlines = [HostIPInline]
 
+    # Select host to change -> Host
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "Host"
+        # Get the filtered values
+        return super().changelist_view(request, extra_context=extra_context)
+
 
 class HostIpResource(resources.ModelResource):
     """defines how each field in the referenced model should be mapped to the corresponding fields in the
@@ -793,6 +834,14 @@ class HostIpAdmin(AuditedAdmin, ImportExportModelAdmin):
     resource_classes = [HostIpResource]
     model = models.HostIP
 
+    # Select host ip to change -> Host ip
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "Host IP"
+        # Get the filtered values
+        return super().changelist_view(request, extra_context=extra_context)
+
 
 class ContactResource(resources.ModelResource):
     """defines how each field in the referenced model should be mapped to the corresponding fields in the
@@ -926,6 +975,14 @@ def change_view(self, request, object_id, form_url="", extra_context=None):
 
         return super().change_view(request, object_id, form_url, extra_context=extra_context)
 
+    # Select contact to change -> Contacts
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "Contacts"
+        # Get the filtered values
+        return super().changelist_view(request, extra_context=extra_context)
+
 
 class WebsiteResource(resources.ModelResource):
     """defines how each field in the referenced model should be mapped to the corresponding fields in the
@@ -1043,6 +1100,21 @@ def delete_view(self, request, object_id, extra_context=None):
         else:
             return response
 
+    # User Domain manager [email] is manager on domain [domain name] ->
+    # Domain manager [email] on [domain name]
+    def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+
+        if object_id:
+            obj = self.get_object(request, object_id)
+            if obj:
+                email = obj.user.email
+                domain_name = obj.domain.name
+                extra_context["subtitle"] = f"Domain manager {email} on {domain_name}"
+
+        return super().changeform_view(request, object_id, form_url, extra_context=extra_context)
+
 
 class DomainInvitationAdmin(ListHeaderAdmin):
     """Custom domain invitation admin class."""
@@ -1079,6 +1151,14 @@ class Meta:
 
     change_form_template = "django/admin/email_clipboard_change_form.html"
 
+    # Select domain invitations to change -> Domain invitations
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "Domain invitations"
+        # Get the filtered values
+        return super().changelist_view(request, extra_context=extra_context)
+
 
 class DomainInformationResource(resources.ModelResource):
     """defines how each field in the referenced model should be mapped to the corresponding fields in the
@@ -1219,6 +1299,14 @@ def get_readonly_fields(self, request, obj=None):
         readonly_fields.extend([field for field in self.analyst_readonly_fields])
         return readonly_fields  # Read-only fields for analysts
 
+    # Select domain information to change -> Domain information
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "Domain information"
+        # Get the filtered values
+        return super().changelist_view(request, extra_context=extra_context)
+
 
 class DomainRequestResource(FsmModelResource):
     """defines how each field in the referenced model should be mapped to the corresponding fields in the
@@ -1674,11 +1762,17 @@ def changelist_view(self, request, extra_context=None):
                     if next_char.isdigit():
                         should_apply_default_filter = True
 
+        # Select domain request to change -> Domain requests
+        if extra_context is None:
+            extra_context = {}
+            extra_context["tabtitle"] = "Domain requests"
+
         if should_apply_default_filter:
             # modify the GET of the request to set the selected filter
             modified_get = copy.deepcopy(request.GET)
             modified_get["status__in"] = "submitted,in review,action needed"
             request.GET = modified_get
+
         response = super().changelist_view(request, extra_context=extra_context)
         return response
 
@@ -2244,6 +2338,14 @@ def response_change(self, request, obj):
         # If no redirection is needed, return the original response
         return response
 
+    # Select draft domain to change -> Draft domains
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "Draft domains"
+        # Get the filtered values
+        return super().changelist_view(request, extra_context=extra_context)
+
 
 class PublicContactResource(resources.ModelResource):
     """defines how each field in the referenced model should be mapped to the corresponding fields in the
@@ -2288,6 +2390,20 @@ class PublicContactAdmin(ListHeaderAdmin, ImportExportModelAdmin):
     change_form_template = "django/admin/email_clipboard_change_form.html"
     autocomplete_fields = ["domain"]
 
+    def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+
+        if object_id:
+            obj = self.get_object(request, object_id)
+            if obj:
+                name = obj.name
+                email = obj.email
+                registry_id = obj.registry_id
+                extra_context["subtitle"] = f"{name} <{email}> id: {registry_id}"
+
+        return super().changeform_view(request, object_id, form_url, extra_context=extra_context)
+
 
 class VerifiedByStaffAdmin(ListHeaderAdmin):
     list_display = ("email", "requestor", "truncated_notes", "created_at")
@@ -2340,6 +2456,14 @@ def formfield_for_dbfield(self, dbfield, **kwargs):
     def user_group(self, obj):
         return obj.name
 
+    # Select user groups to change -> User groups
+    def changelist_view(self, request, extra_context=None):
+        if extra_context is None:
+            extra_context = {}
+        extra_context["tabtitle"] = "User groups"
+        # Get the filtered values
+        return super().changelist_view(request, extra_context=extra_context)
+
 
 class WaffleFlagAdmin(FlagAdmin):
     """Custom admin implementation of django-waffle's Flag class"""


Test patch:
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -1087,7 +1087,7 @@ def test_domain_authorizing_official(self):
         """Can load domain's authorizing official page."""
         page = self.client.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
         # once on the sidebar, once in the title
-        self.assertContains(page, "Authorizing official", count=2)
+        self.assertContains(page, "Authorizing official", count=3)
 
     def test_domain_authorizing_official_content(self):
         """Authorizing official information appears on the page."""