From 196ab6323b7c8a3d63821b35a971b567c18cde43 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:06:15 -0600 Subject: [PATCH 01/30] Add copy button --- src/registrar/admin.py | 19 ++++++- src/registrar/assets/sass/_theme/_admin.scss | 19 +++++++ src/registrar/templates/admin/fieldset.html | 49 +++++++++++++++++++ .../admin/includes/contact_fieldset.html | 48 ++++++++++++++++++ .../admin/public_contact_change_form.html | 8 +++ 5 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/registrar/templates/admin/fieldset.html create mode 100644 src/registrar/templates/django/admin/includes/contact_fieldset.html create mode 100644 src/registrar/templates/django/admin/public_contact_change_form.html diff --git a/src/registrar/admin.py b/src/registrar/admin.py index ff8046da9..01ad5e960 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -640,6 +640,17 @@ class ContactAdmin(ListHeaderAdmin): # in autocomplete_fields for user ordering = ["first_name", "last_name", "email"] + fieldsets = [ + ( + None, + { + "fields": ["user", "first_name", "middle_name", "last_name", "title", "email", "phone"] + }, + ) + ] + + change_form_template = "django/admin/public_contact_change_form.html" + # We name the custom prop 'contact' because linter # is not allowing a short_description attr on it # This gets around the linter limitation, for now. @@ -1805,6 +1816,12 @@ class DraftDomainAdmin(ListHeaderAdmin): ordering = ["name"] +class PublicContactAdmin(ListHeaderAdmin): + """Custom PublicContact admin class.""" + + change_form_template = "django/admin/public_contact_change_form.html" + + class VerifiedByStaffAdmin(ListHeaderAdmin): list_display = ("email", "requestor", "truncated_notes", "created_at") search_fields = ["email"] @@ -1845,7 +1862,7 @@ admin.site.register(models.DraftDomain, DraftDomainAdmin) # do not propagate to registry and logic not applied admin.site.register(models.Host, MyHostAdmin) admin.site.register(models.Website, WebsiteAdmin) -admin.site.register(models.PublicContact, AuditedAdmin) +admin.site.register(models.PublicContact, PublicContactAdmin) admin.site.register(models.DomainRequest, DomainRequestAdmin) admin.site.register(models.TransitionDomain, TransitionDomainAdmin) admin.site.register(models.VerifiedByStaff, VerifiedByStaffAdmin) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index dc67bc8b6..6909f77c2 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -299,3 +299,22 @@ input.admin-confirm-button { display: contents !important; } } + +.admin-icon-group { + position: relative; + display: flex; + align-items: center; + + .usa-button__icon { + position: absolute; + right: 0; + top: 0; + height: 100%; + border: none; + background: transparent; + padding: 0 1rem; + margin: 0; + } +} + + diff --git a/src/registrar/templates/admin/fieldset.html b/src/registrar/templates/admin/fieldset.html new file mode 100644 index 000000000..dadae5811 --- /dev/null +++ b/src/registrar/templates/admin/fieldset.html @@ -0,0 +1,49 @@ +{% load i18n static %} + +{% comment %} +This is copied from Djangos implementation of this template, with added "blocks" +It is not inherently customizable on its own, so we can modify this instead. +https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/includes/fieldset.html +{% endcomment %} +
+ {% block fieldset_title %} + {% if fieldset.name %}

{{ fieldset.name }}

{% endif %} + {% endblock fieldset_title %} + + {% block fieldset_description %} + {% if fieldset.description %} +
{{ fieldset.description|safe }}
+ {% endif %} + {% endblock fieldset_description %} + + {% block fieldset_lines %} + {% for line in fieldset %} +
+ {% if line.fields|length == 1 %}{{ line.errors }}{% else %}
{% endif %} + {% for field in line %} +
+ {% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %} +
+ {% if field.is_checkbox %} + {{ field.field }}{{ field.label_tag }} + {% else %} + {{ field.label_tag }} + {% if field.is_readonly %} +
{{ field.contents }}
+ {% else %} + {{ field.field }} + {% endif %} + {% endif %} +
+ {% if field.field.help_text %} +
+
{{ field.field.help_text|safe }}
+
+ {% endif %} +
+ {% endfor %} + {% if not line.fields|length == 1 %}
{% endif %} +
+ {% endfor %} + {% endblock fieldset_lines %} +
\ No newline at end of file diff --git a/src/registrar/templates/django/admin/includes/contact_fieldset.html b/src/registrar/templates/django/admin/includes/contact_fieldset.html new file mode 100644 index 000000000..c2a10f4fd --- /dev/null +++ b/src/registrar/templates/django/admin/includes/contact_fieldset.html @@ -0,0 +1,48 @@ +{% extends "admin/fieldset.html" %} +{% load i18n static %} + +{% comment %} +This is using a custom implementation fieldset.html (see admin/fieldset.html) +{% endcomment %} +{% block fieldset_lines %} +{% for line in fieldset %} +
+ {% if line.fields|length == 1 %}{{ line.errors }}{% else %}
{% endif %} + {% for field in line %} +
+ {% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %} +
+ {% if field.is_checkbox %} + {{ field.field }}{{ field.label_tag }} + {% else %} + {{ field.label_tag }} + {% if field.is_readonly %} +
{{ field.contents }}
+ {% elif field.field.name == "email" %} +
+ {{ field.field }} + +
+ {% else %} + {{ field.field }} + {% endif %} + {% endif %} +
+ {% if field.field.help_text %} +
+
{{ field.field.help_text|safe }}
+
+ {% endif %} +
+ {% endfor %} + {% if not line.fields|length == 1 %}
{% endif %} +
+{% endfor %} + +{% endblock fieldset_lines %} diff --git a/src/registrar/templates/django/admin/public_contact_change_form.html b/src/registrar/templates/django/admin/public_contact_change_form.html new file mode 100644 index 000000000..181201d0b --- /dev/null +++ b/src/registrar/templates/django/admin/public_contact_change_form.html @@ -0,0 +1,8 @@ +{% extends 'admin/change_form.html' %} +{% load i18n static %} + +{% block field_sets %} + {% for fieldset in adminform %} + {% include "django/admin/includes/contact_fieldset.html" %} + {% endfor %} +{% endblock %} From 44c4e2ef26ca07f8e576ab6bca7ff5783e8431cb Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:46:29 -0600 Subject: [PATCH 02/30] Add checkbox --- src/registrar/assets/js/get-gov-admin.js | 42 +++++++++++++++++++ .../admin/includes/contact_fieldset.html | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index ff73acb65..df748c840 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -76,6 +76,48 @@ function openInNewTab(el, removeAttribute = false){ prepareDjangoAdmin(); })(); +/** An IIFE for pages in DjangoAdmin that use a clipboard button +*/ +(function (){ + function copyToClipboardAndChangeIcon(button) { + // Assuming the input is the previous sibling of the button + let input = button.previousElementSibling; + + // Copy input value to clipboard + if (input) { + navigator.clipboard.writeText(input.value).then(function() { + // Change the icon to a checkmark on successful copy + let buttonIcon = button .querySelector('.usa-button__clipboard use'); + if (buttonIcon) { + let currentHref = buttonIcon.getAttribute('xlink:href'); + let baseHref = currentHref.split('#')[0]; + + // Append the new icon reference + buttonIcon.setAttribute('xlink:href', baseHref + '#check'); + setTimeout(function() { + // Change back to the copy icon + buttonIcon.setAttribute('xlink:href', currentHref); + }, 2000); + } + + }).catch(function(error) { + console.error('Clipboard copy failed', error); + }); + } + } + + function handleClipboardButtons() { + clipboardButtons = document.querySelectorAll(".usa-button__clipboard") + clipboardButtons.forEach((button) => { + button.addEventListener("click", ()=>{copyToClipboardAndChangeIcon(button)}); + }); + } + + handleClipboardButtons(); + +})(); + + /** * An IIFE to listen to changes on filter_horizontal and enable or disable the change/delete/view buttons as applicable * diff --git a/src/registrar/templates/django/admin/includes/contact_fieldset.html b/src/registrar/templates/django/admin/includes/contact_fieldset.html index c2a10f4fd..90e8f911f 100644 --- a/src/registrar/templates/django/admin/includes/contact_fieldset.html +++ b/src/registrar/templates/django/admin/includes/contact_fieldset.html @@ -21,7 +21,7 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {% elif field.field.name == "email" %}
{{ field.field }} - +
\ No newline at end of file diff --git a/src/registrar/templates/django/admin/includes/contact_fieldset.html b/src/registrar/templates/django/admin/includes/contact_fieldset.html index 90e8f911f..ce8777420 100644 --- a/src/registrar/templates/django/admin/includes/contact_fieldset.html +++ b/src/registrar/templates/django/admin/includes/contact_fieldset.html @@ -1,5 +1,4 @@ {% extends "admin/fieldset.html" %} -{% load i18n static %} {% comment %} This is using a custom implementation fieldset.html (see admin/fieldset.html) @@ -19,16 +18,7 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {% if field.is_readonly %}
{{ field.contents }}
{% elif field.field.name == "email" %} -
- {{ field.field }} - -
+ {% include "admin/input_with_clipboard.html" with field=field.field %} {% else %} {{ field.field }} {% endif %} From 48a4278240ec7d5581a68da7ddc436a362460ab2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:22:17 -0600 Subject: [PATCH 05/30] Add emails to other pages --- src/registrar/admin.py | 11 +++++++++-- ...nge_form.html => email_clipboard_change_form.html} | 2 +- ...ct_fieldset.html => email_clipboard_fieldset.html} | 0 3 files changed, 10 insertions(+), 3 deletions(-) rename src/registrar/templates/django/admin/{public_contact_change_form.html => email_clipboard_change_form.html} (66%) rename src/registrar/templates/django/admin/includes/{contact_fieldset.html => email_clipboard_fieldset.html} (100%) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 01ad5e960..e86b9f282 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -649,7 +649,9 @@ class ContactAdmin(ListHeaderAdmin): ) ] - change_form_template = "django/admin/public_contact_change_form.html" + autocomplete_fields = ["user"] + + change_form_template = "django/admin/email_clipboard_change_form.html" # We name the custom prop 'contact' because linter # is not allowing a short_description attr on it @@ -832,6 +834,8 @@ class DomainInvitationAdmin(ListHeaderAdmin): # error. readonly_fields = ["status"] + change_form_template = "django/admin/email_clipboard_change_form.html" + class DomainInformationAdmin(ListHeaderAdmin): """Customize domain information admin class.""" @@ -1327,6 +1331,8 @@ class TransitionDomainAdmin(ListHeaderAdmin): search_fields = ["username", "domain_name"] search_help_text = "Search by user or domain name." + change_form_template = "django/admin/email_clipboard_change_form.html" + class DomainInformationInline(admin.StackedInline): """Edit a domain information on the domain page. @@ -1819,7 +1825,8 @@ class DraftDomainAdmin(ListHeaderAdmin): class PublicContactAdmin(ListHeaderAdmin): """Custom PublicContact admin class.""" - change_form_template = "django/admin/public_contact_change_form.html" + change_form_template = "django/admin/email_clipboard_change_form.html" + autocomplete_fields = ["domain"] class VerifiedByStaffAdmin(ListHeaderAdmin): diff --git a/src/registrar/templates/django/admin/public_contact_change_form.html b/src/registrar/templates/django/admin/email_clipboard_change_form.html similarity index 66% rename from src/registrar/templates/django/admin/public_contact_change_form.html rename to src/registrar/templates/django/admin/email_clipboard_change_form.html index 181201d0b..15cb11841 100644 --- a/src/registrar/templates/django/admin/public_contact_change_form.html +++ b/src/registrar/templates/django/admin/email_clipboard_change_form.html @@ -3,6 +3,6 @@ {% block field_sets %} {% for fieldset in adminform %} - {% include "django/admin/includes/contact_fieldset.html" %} + {% include "django/admin/includes/email_clipboard_fieldset.html" %} {% endfor %} {% endblock %} diff --git a/src/registrar/templates/django/admin/includes/contact_fieldset.html b/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html similarity index 100% rename from src/registrar/templates/django/admin/includes/contact_fieldset.html rename to src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html From 438df069d646982776f87640f442542a393dc5b8 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:10:08 -0600 Subject: [PATCH 06/30] WIP for new copy fields --- .../includes/domain_request_detail_table.html | 27 +++++++++++++++---- .../includes/domain_request_fieldset.html | 16 ++++++++++- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/registrar/templates/django/admin/includes/domain_request_detail_table.html b/src/registrar/templates/django/admin/includes/domain_request_detail_table.html index c25812b4d..32c8aa49a 100644 --- a/src/registrar/templates/django/admin/includes/domain_request_detail_table.html +++ b/src/registrar/templates/django/admin/includes/domain_request_detail_table.html @@ -17,11 +17,28 @@ Email {% if user.email or user.contact.email %} - {% if user.contact.email %} - {{ user.contact.email }} - {% else %} - {{ user.email }} - {% endif %} + + + {% if user.contact.email %} + {{ user.contact.email }} + + {% else %} + {{ user.email }} + + {% endif %} + + + + {% else %} Nothing found {% endif %} diff --git a/src/registrar/templates/django/admin/includes/domain_request_fieldset.html b/src/registrar/templates/django/admin/includes/domain_request_fieldset.html index 980fe0bfd..11e1e21c6 100644 --- a/src/registrar/templates/django/admin/includes/domain_request_fieldset.html +++ b/src/registrar/templates/django/admin/includes/domain_request_fieldset.html @@ -62,7 +62,21 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {{contact.first_name}} {{contact.last_name}} {{ contact.title }} - {{ contact.email }} + + + + {{ contact.email }} + + {{ contact.phone }} {% endfor %} From 2931900d57a914e04969d75365cc4ac2dd09d7fc Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:07:33 -0600 Subject: [PATCH 07/30] Unit test, styling --- src/registrar/assets/js/get-gov-admin.js | 5 ++- src/registrar/assets/sass/_theme/_admin.scss | 15 ++++--- .../includes/domain_request_detail_table.html | 42 +++++++++++-------- .../includes/domain_request_fieldset.html | 13 +++--- src/registrar/tests/test_admin.py | 21 ++++++---- 5 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index b78362dc6..d4b309a4a 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -177,9 +177,10 @@ function openInNewTab(el, removeAttribute = false){ copyToClipboardAndChangeIcon(button); }); - // Add a class that removes the outline style on click + // Add a class that adds the outline style on click button.addEventListener("mousedown", function() { - this.classList.remove("no-outline-on-click"); + console.log(`applying mousedown on ${this} vs ${button}`); + this.classList.add("no-outline-on-click"); }); // But add it back in after the user clicked, diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 0a29eedff..a4a9fca54 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -381,14 +381,19 @@ table.dja-user-detail-table { input { // Allow for padding around the copy button - padding-right: 35px; + padding-right: 35px !important; // Match the height of other inputs - min-height: 2.25rem; + min-height: 2.25rem !important; } - .no-outline-on-click:focus { - outline: none !important; +} + +td.font-size-sm { + button.usa-button__icon { + font-size: 16px; } } - +.no-outline-on-click:focus { + outline: none !important; +} diff --git a/src/registrar/templates/django/admin/includes/domain_request_detail_table.html b/src/registrar/templates/django/admin/includes/domain_request_detail_table.html index 32c8aa49a..b1afd6a68 100644 --- a/src/registrar/templates/django/admin/includes/domain_request_detail_table.html +++ b/src/registrar/templates/django/admin/includes/domain_request_detail_table.html @@ -13,34 +13,39 @@ {% else %} Nothing found {% endif %} + {# Placeholder col for actions (like copy) or additional padding #} + Email {% if user.email or user.contact.email %} + {% if user.contact.email %} + {{ user.contact.email }} + {% else %} + {{ user.email }} + {% endif %} + - - {% if user.contact.email %} - {{ user.contact.email }} - - {% else %} - {{ user.email }} - - {% endif %} - - + + + {% else %} Nothing found + {% endif %} @@ -54,6 +59,7 @@ {% else %} Nothing found {% endif %} + diff --git a/src/registrar/templates/django/admin/includes/domain_request_fieldset.html b/src/registrar/templates/django/admin/includes/domain_request_fieldset.html index 11e1e21c6..976969667 100644 --- a/src/registrar/templates/django/admin/includes/domain_request_fieldset.html +++ b/src/registrar/templates/django/admin/includes/domain_request_fieldset.html @@ -62,10 +62,13 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {{contact.first_name}} {{contact.last_name}} {{ contact.title }} - - + {{ contact.email }} + {{ contact.phone }} + {# Copy button for the email #} + + - {{ contact.email }} - - {{ contact.phone }} {% endfor %} diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index b29776f81..7bcfc388f 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1304,18 +1304,19 @@ class TestDomainRequestAdmin(MockEppLib): self.assertEqual(response.status_code, 200) self.assertContains(response, domain_request.requested_domain.name) - # Check that the modal has the right content - # Check for the header - # == Check for the creator == # # Check for the right title, email, and phone number in the response. # We only need to check for the end tag # (Otherwise this test will fail if we change classes, etc) + expected_email = "meoward.jones@igorville.gov" expected_creator_fields = [ # Field, expected value ("title", "Treat inspector"), - ("email", "meoward.jones@igorville.gov"), + ("email", f"{expected_email}"), + # Check for the existence of the copy button input. + # Lets keep things simple to minimize future conflicts. + ("email_copy_button_input", f'"), ] self.assert_response_contains_distinct_values(response, expected_creator_fields) @@ -1324,20 +1325,24 @@ class TestDomainRequestAdmin(MockEppLib): self.assertContains(response, "Meoward Jones") # == Check for the submitter == # + expected_email = "mayor@igorville.gov" expected_submitter_fields = [ # Field, expected value ("title", "Admin Tester"), - ("email", "mayor@igorville.gov"), + ("email", f"{expected_email}"), + ("email_copy_button_input", f'"), ] self.assert_response_contains_distinct_values(response, expected_submitter_fields) self.assertContains(response, "Testy2 Tester2") # == Check for the authorizing_official == # + expected_email = "testy@town.com" expected_ao_fields = [ # Field, expected value ("title", "Chief Tester"), - ("email", "testy@town.com"), + ("email", f"{expected_email}"), + ("email_copy_button_input", f'"), ] self.assert_response_contains_distinct_values(response, expected_ao_fields) @@ -1359,10 +1364,12 @@ class TestDomainRequestAdmin(MockEppLib): self.assertContains(response, "Phone", count=3) # == Test the other_employees field == # + expected_email = "testy@town.com" expected_other_employees_fields = [ # Field, expected value ("title", "Another Tester"), - ("email", "testy2@town.com"), + ("email", f"{expected_email}"), + ("email_copy_button_input", f'"), ] self.assert_response_contains_distinct_values(response, expected_other_employees_fields) From 54072a479e8699b8488472a9b7c21b1185d22a5c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:49:09 -0600 Subject: [PATCH 08/30] Update detail_table_fieldset.html --- .../admin/includes/detail_table_fieldset.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html index f5a5b71ee..3d9d038d6 100644 --- a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html +++ b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html @@ -51,6 +51,21 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {{ contact.title }} {{ contact.email }} {{ contact.phone }} + {# Copy button for the email #} + + + + {% endfor %} From be07a06a15bc71fcb75ebf10ef2d51ea74df0bf6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:14:16 -0600 Subject: [PATCH 09/30] Add additional copy buttons --- src/registrar/admin.py | 4 ++ .../includes/email_clipboard_fieldset.html | 41 ++++--------------- src/registrar/tests/common.py | 3 +- src/registrar/tests/test_admin.py | 16 ++++++-- 4 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 4a2a4515a..61409c31f 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -536,6 +536,8 @@ class MyUserAdmin(BaseUserAdmin): # in autocomplete_fields for user ordering = ["first_name", "last_name", "email"] + change_form_template = "django/admin/email_clipboard_change_form.html" + def get_search_results(self, request, queryset, search_term): """ Override for get_search_results. This affects any upstream model using autocomplete_fields, @@ -1808,6 +1810,8 @@ class VerifiedByStaffAdmin(ListHeaderAdmin): "requestor", ] + change_form_template = "django/admin/email_clipboard_change_form.html" + def truncated_notes(self, obj): # Truncate the 'notes' field to 50 characters return str(obj.notes)[:50] diff --git a/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html b/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html index ce8777420..f959f8edf 100644 --- a/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html +++ b/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html @@ -1,38 +1,13 @@ -{% extends "admin/fieldset.html" %} +{% extends "django/admin/includes/detail_table_fieldset.html" %} {% comment %} This is using a custom implementation fieldset.html (see admin/fieldset.html) {% endcomment %} -{% block fieldset_lines %} -{% for line in fieldset %} -
- {% if line.fields|length == 1 %}{{ line.errors }}{% else %}
{% endif %} - {% for field in line %} -
- {% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %} -
- {% if field.is_checkbox %} - {{ field.field }}{{ field.label_tag }} - {% else %} - {{ field.label_tag }} - {% if field.is_readonly %} -
{{ field.contents }}
- {% elif field.field.name == "email" %} - {% include "admin/input_with_clipboard.html" with field=field.field %} - {% else %} - {{ field.field }} - {% endif %} - {% endif %} -
- {% if field.field.help_text %} -
-
{{ field.field.help_text|safe }}
-
- {% endif %} -
- {% endfor %} - {% if not line.fields|length == 1 %}
{% endif %} -
-{% endfor %} -{% endblock fieldset_lines %} +{% block field_other %} + {% if field.field.name == "email" %} + {% include "admin/input_with_clipboard.html" with field=field.field %} + {% else %} + {{ block.super }} + {% endif %} +{% endblock field_other %} diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 655fda02b..afc30a16f 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -158,7 +158,7 @@ class GenericTestHelper(TestCase): Example Usage: ``` self.assert_sort_helper( - self.factory, self.superuser, self.admin, self.url, DomainInformation, "1", ("domain__name",) + "1", ("domain__name",) ) ``` @@ -204,7 +204,6 @@ class GenericTestHelper(TestCase): {"action": "delete_selected", "select_across": selected_across, "index": index, "_selected_action": "23"}, follow=True, ) - print(f"what is the response? {response}") return response diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index c69759fb2..7e42cb0d5 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -2022,10 +2022,14 @@ class TestDomainInformationAdmin(TestCase): # Check for the right title, email, and phone number in the response. # We only need to check for the end tag # (Otherwise this test will fail if we change classes, etc) + expected_email = "meoward.jones@igorville.gov" expected_creator_fields = [ # Field, expected value ("title", "Treat inspector"), - ("email", "meoward.jones@igorville.gov"), + ("email", f"{expected_email}"), + # Check for the existence of the copy button input. + # Lets keep things simple to minimize future conflicts. + ("email_copy_button_input", f'"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields) @@ -2034,20 +2038,24 @@ class TestDomainInformationAdmin(TestCase): self.assertContains(response, "Meoward Jones") # == Check for the submitter == # + expected_email = "mayor@igorville.gov" expected_submitter_fields = [ # Field, expected value ("title", "Admin Tester"), - ("email", "mayor@igorville.gov"), + ("email", f"{expected_email}"), + ("email_copy_button_input", f'"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_submitter_fields) self.assertContains(response, "Testy2 Tester2") # == Check for the authorizing_official == # + expected_email = "testy@town.com" expected_ao_fields = [ # Field, expected value ("title", "Chief Tester"), ("email", "testy@town.com"), + ("email_copy_button_input", f'"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_ao_fields) @@ -2069,10 +2077,12 @@ class TestDomainInformationAdmin(TestCase): self.assertContains(response, "Phone", count=3) # == Test the other_employees field == # + expected_email = "testy@town.com" expected_other_employees_fields = [ # Field, expected value ("title", "Another Tester"), - ("email", "testy2@town.com"), + ("email", f"{expected_email}"), + ("email_copy_button_input", f'"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields) From 058955100a81120aed1bcd1e668998b39463a62d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:21:55 -0600 Subject: [PATCH 10/30] Linting --- src/registrar/admin.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 61409c31f..f18fdd26a 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -645,9 +645,7 @@ class ContactAdmin(ListHeaderAdmin): fieldsets = [ ( None, - { - "fields": ["user", "first_name", "middle_name", "last_name", "title", "email", "phone"] - }, + {"fields": ["user", "first_name", "middle_name", "last_name", "title", "email", "phone"]}, ) ] From 15e99af5f03680da839ae1017c9caf555a81285c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:37:47 -0600 Subject: [PATCH 11/30] Add copy button --- src/registrar/assets/js/get-gov-admin.js | 19 +++++- src/registrar/assets/sass/_theme/_admin.scss | 21 ++++-- .../admin/includes/contact_detail_list.html | 9 +++ .../admin/includes/contact_detail_table.html | 65 ------------------- .../admin/includes/detail_table_fieldset.html | 12 +++- 5 files changed, 55 insertions(+), 71 deletions(-) delete mode 100644 src/registrar/templates/django/admin/includes/contact_detail_table.html diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 19f6b7dbd..2ac16d919 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -140,6 +140,12 @@ function openInNewTab(el, removeAttribute = false){ /** An IIFE for pages in DjangoAdmin that use a clipboard button */ (function (){ + + function copyInnerTextToClipboard(elem) { + let text = elem.innerText + navigator.clipboard.writeText(text) + } + function copyToClipboardAndChangeIcon(button) { // Assuming the input is the previous sibling of the button let input = button.previousElementSibling; @@ -179,7 +185,6 @@ function openInNewTab(el, removeAttribute = false){ // Add a class that adds the outline style on click button.addEventListener("mousedown", function() { - console.log(`applying mousedown on ${this} vs ${button}`); this.classList.add("no-outline-on-click"); }); @@ -192,7 +197,19 @@ function openInNewTab(el, removeAttribute = false){ }); } + function handleClipboardLinks() { + let emailButtons = document.querySelectorAll(".usa-button__clipboard-link"); + if (emailButtons){ + emailButtons.forEach((button) => { + button.addEventListener("click", ()=>{ + copyInnerTextToClipboard(button); + }) + }); + } + } + handleClipboardButtons(); + handleClipboardLinks(); })(); diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index c777ef291..d1e000033 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -404,6 +404,13 @@ address.margin-top-neg-1__detail-list { address.dja-address-contact-list { font-size: 0.8125rem; color: var(--body-quiet-color); + button.usa-button__clipboard-link { + font-size: 0.8125rem !important; + } +} + +td button.usa-button__clipboard-link { + font-size: 0.8125rem !important; } // Mimic the normal label size @@ -416,6 +423,14 @@ address.dja-address-contact-list { font-size: 0.875rem; color: var(--body-quiet-color); } + + address button.usa-button__clipboard-link { + font-size: 0.875rem !important; + } + + td button.usa-button__clipboard-link { + font-size: 0.875rem !important; + } } .errors span.select2-selection { @@ -442,8 +457,6 @@ address.dja-address-contact-list { } -td.font-size-sm { - button.usa-button__icon { - font-size: 16px; - } +.no-outline-on-click:focus { + outline: none !important; } \ No newline at end of file diff --git a/src/registrar/templates/django/admin/includes/contact_detail_list.html b/src/registrar/templates/django/admin/includes/contact_detail_list.html index 6afe4c8d6..cded7526b 100644 --- a/src/registrar/templates/django/admin/includes/contact_detail_list.html +++ b/src/registrar/templates/django/admin/includes/contact_detail_list.html @@ -25,9 +25,18 @@ {# Email #} {% if user.email or user.contact.email %} {% if user.contact.email %} + {% else %} + {% endif %}
{% else %} diff --git a/src/registrar/templates/django/admin/includes/contact_detail_table.html b/src/registrar/templates/django/admin/includes/contact_detail_table.html deleted file mode 100644 index b1afd6a68..000000000 --- a/src/registrar/templates/django/admin/includes/contact_detail_table.html +++ /dev/null @@ -1,65 +0,0 @@ -{% load i18n static %} - - - - - - {% if user.title or user.contact.title %} - {% if user.contact.title %} - - {% else %} - - {% endif %} - {% else %} - - {% endif %} - {# Placeholder col for actions (like copy) or additional padding #} - - - - - {% if user.email or user.contact.email %} - {% if user.contact.email %} - - {% else %} - - {% endif %} - - - - {% else %} - - - {% endif %} - - - - {% if user.phone or user.contact.phone %} - {% if user.contact.phone %} - - {% else %} - - {% endif %} - {% else %} - - {% endif %} - - - -
Title{{ user.contact.title }}{{ user.title }}Nothing found
Email{{ user.contact.email }}{{ user.email }} - {% if user.contact.email %} - - {% else %} - - {% endif %} - - Nothing found
Phone{{ user.contact.phone }}{{ user.phone }}Nothing found
diff --git a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html index 47145faf2..53bdbe821 100644 --- a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html +++ b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html @@ -92,7 +92,17 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {{ contact.get_formatted_name }} {{ contact.title }} - {{ contact.email }} + + + {{ contact.phone }} {% endfor %} From 6c22cf7169f098af8bcfbaac7d240a6567c9b522 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:56:27 -0600 Subject: [PATCH 12/30] Fix unit tests --- src/registrar/assets/sass/_theme/_admin.scss | 28 ++++++-------------- src/registrar/tests/test_admin.py | 4 +-- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index d1e000033..ebd0d1b5b 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -390,53 +390,41 @@ address.margin-top-neg-1__detail-list { margin-top: 5px !important; } // Mimic the normal label size - dt { - font-size: 0.8125rem; - color: var(--body-quiet-color); - } - - address { + address, dt { font-size: 0.8125rem; color: var(--body-quiet-color); } } +td button.usa-button__clipboard-link, address.dja-address-contact-list { + font-size: 0.8125rem !important; +} + address.dja-address-contact-list { - font-size: 0.8125rem; color: var(--body-quiet-color); button.usa-button__clipboard-link { font-size: 0.8125rem !important; } } -td button.usa-button__clipboard-link { - font-size: 0.8125rem !important; -} - // Mimic the normal label size @media (max-width: 1024px){ - .dja-detail-list dt { - font-size: 0.875rem; - color: var(--body-quiet-color); - } - .dja-detail-list address { + .dja-detail-list dt, .dja-detail-list address { font-size: 0.875rem; color: var(--body-quiet-color); } - address button.usa-button__clipboard-link { + address button.usa-button__clipboard-link, td button.usa-button__clipboard-link { font-size: 0.875rem !important; } - td button.usa-button__clipboard-link { - font-size: 0.875rem !important; - } } .errors span.select2-selection { border: 1px solid var(--error-fg) !important; } +// Make the clipboard button "float" inside of the input box .admin-icon-group { position: relative; display: flex; diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index bbbf385d9..1f7ba7c71 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1306,7 +1306,7 @@ class TestDomainRequestAdmin(MockEppLib): ("title", "Treat inspector"), ("email", "meoward.jones@igorville.gov"), ("phone", "(555) 123 12345"), - ("email_copy_button_input", f'"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields) @@ -2035,7 +2035,7 @@ class TestDomainInformationAdmin(TestCase): ("title", "Treat inspector"), ("email", "meoward.jones@igorville.gov"), ("phone", "(555) 123 12345"), - ("email_copy_button_input", f'"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields) From 892607bd658b780a29d08d015acfd90738173e07 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:06:36 -0600 Subject: [PATCH 13/30] Update test_admin.py --- src/registrar/tests/test_admin.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 1f7ba7c71..c285c8f37 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1306,7 +1306,6 @@ class TestDomainRequestAdmin(MockEppLib): ("title", "Treat inspector"), ("email", "meoward.jones@igorville.gov"), ("phone", "(555) 123 12345"), - ("email_copy_button_input", f"{expected_email}"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields) @@ -2035,7 +2034,6 @@ class TestDomainInformationAdmin(TestCase): ("title", "Treat inspector"), ("email", "meoward.jones@igorville.gov"), ("phone", "(555) 123 12345"), - ("email_copy_button_input", f"{expected_email}"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_creator_fields) From 47b7fb8f492976d6c1337f41396bf6eba72348d1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:11:28 -0600 Subject: [PATCH 14/30] Remove bad tests No longer applicable here --- src/registrar/tests/test_admin.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index c285c8f37..759fd8b9e 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1319,7 +1319,6 @@ class TestDomainRequestAdmin(MockEppLib): ("title", "Admin Tester"), ("email", "mayor@igorville.gov"), ("phone", "(555) 555 5556"), - ("email_copy_button_input", f'"), ("email", "testy@town.com"), ("phone", "(555) 555 5555"), - ("email_copy_button_input", f' Date: Mon, 1 Apr 2024 14:13:48 -0600 Subject: [PATCH 15/30] Revert "Remove bad tests" This reverts commit 47b7fb8f492976d6c1337f41396bf6eba72348d1. --- src/registrar/tests/test_admin.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 759fd8b9e..c285c8f37 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1319,6 +1319,7 @@ class TestDomainRequestAdmin(MockEppLib): ("title", "Admin Tester"), ("email", "mayor@igorville.gov"), ("phone", "(555) 555 5556"), + ("email_copy_button_input", f'"), ("email", "testy@town.com"), ("phone", "(555) 555 5555"), + ("email_copy_button_input", f' Date: Mon, 1 Apr 2024 14:21:35 -0600 Subject: [PATCH 16/30] New unit tests --- src/registrar/tests/test_admin.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index c285c8f37..3999acc4e 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1319,7 +1319,6 @@ class TestDomainRequestAdmin(MockEppLib): ("title", "Admin Tester"), ("email", "mayor@igorville.gov"), ("phone", "(555) 555 5556"), - ("email_copy_button_input", f'"), - ("email", "testy@town.com"), - ("phone", "(555) 555 5555"), - ("email_copy_button_input", f' Date: Mon, 1 Apr 2024 15:47:15 -0600 Subject: [PATCH 17/30] Update test_admin.py --- src/registrar/tests/test_admin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 3999acc4e..b73d9bce1 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1324,7 +1324,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertContains(response, "Testy2 Tester2") # == Check for the authorizing_official == # - expected_email = "testy@town.com" + expected_ao_fields = [ # Field, expected value ("title", "Chief Tester"), @@ -1338,7 +1338,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertContains(response, "Testy Tester", count=5) # == Test the other_employees field == # - expected_email = "testy@town.com" + expected_other_employees_fields = [ # Field, expected value ("title", "Another Tester"), @@ -2052,7 +2052,7 @@ class TestDomainInformationAdmin(TestCase): self.assertContains(response, "Testy2 Tester2") # == Check for the authorizing_official == # - expected_email = "testy@town.com" + expected_ao_fields = [ # Field, expected value ("title", "Chief Tester"), @@ -2066,7 +2066,7 @@ class TestDomainInformationAdmin(TestCase): self.assertContains(response, "Testy Tester", count=5) # == Test the other_employees field == # - expected_email = "testy@town.com" + expected_other_employees_fields = [ # Field, expected value ("title", "Another Tester"), From f753f3e6f1209b7c12934d327bc11dc5ce80ba09 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:06:41 -0600 Subject: [PATCH 18/30] Linter --- src/registrar/tests/test_admin.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index b73d9bce1..804b94711 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1300,7 +1300,6 @@ class TestDomainRequestAdmin(MockEppLib): # == Check for the creator == # # Check for the right title, email, and phone number in the response. - expected_email = "meoward.jones@igorville.gov" expected_creator_fields = [ # Field, expected value ("title", "Treat inspector"), @@ -1313,7 +1312,6 @@ class TestDomainRequestAdmin(MockEppLib): self.assertContains(response, "Meoward Jones") # == Check for the submitter == # - expected_email = "mayor@igorville.gov" expected_submitter_fields = [ # Field, expected value ("title", "Admin Tester"), @@ -2028,7 +2026,6 @@ class TestDomainInformationAdmin(TestCase): # Check for the right title, email, and phone number in the response. # We only need to check for the end tag # (Otherwise this test will fail if we change classes, etc) - expected_email = "meoward.jones@igorville.gov" expected_creator_fields = [ # Field, expected value ("title", "Treat inspector"), @@ -2041,7 +2038,6 @@ class TestDomainInformationAdmin(TestCase): self.assertContains(response, "Meoward Jones") # == Check for the submitter == # - expected_email = "mayor@igorville.gov" expected_submitter_fields = [ # Field, expected value ("title", "Admin Tester"), From 34232f9b6c8199e5d5136a19972ac1794ddad988 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:48:33 -0600 Subject: [PATCH 19/30] Change stlying --- src/registrar/assets/js/get-gov-admin.js | 1 + src/registrar/assets/sass/_theme/_admin.scss | 31 ++++++++++++++ .../assets/sass/_theme/_tooltips.scss | 6 +-- .../templates/admin/input_with_clipboard.html | 6 ++- .../admin/includes/contact_detail_list.html | 41 ++++++++++++++----- .../admin/includes/detail_table_fieldset.html | 27 +++++++----- src/registrar/templates/domain_users.html | 2 +- src/registrar/templates/home.html | 2 +- 8 files changed, 89 insertions(+), 27 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 4ae0af4a5..581c2b899 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -155,6 +155,7 @@ function openInNewTab(el, removeAttribute = false){ navigator.clipboard.writeText(input.value).then(function() { // Change the icon to a checkmark on successful copy let buttonIcon = button .querySelector('.usa-button__clipboard use'); + console.log(`what is the button icon ${buttonIcon}`) if (buttonIcon) { let currentHref = buttonIcon.getAttribute('xlink:href'); let baseHref = currentHref.split('#')[0]; diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index c636aab5c..8b5870b86 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -556,8 +556,39 @@ address.dja-address-contact-list { min-height: 2.25rem !important; } + button { + line-height: 15px; + } + +} + +.admin-icon-group.admin-icon-group__clipboard-link { + position: relative; + display: inline; + align-items: center; + + .usa-button__icon { + position: absolute; + right: auto; + left: 4px; + height: 100%; + } + button { + font-size: unset !important; + display: inline-flex; + padding-top: 4px; + line-height: 14px; + } } .no-outline-on-click:focus { outline: none !important; +} + +svg.no-pointer-events { + use { + // USWDS has weird interactions with SVGs regarding tooltips, + // and other components. In this event, we need to disable pointer interactions. + pointer-events: none; + } } \ No newline at end of file diff --git a/src/registrar/assets/sass/_theme/_tooltips.scss b/src/registrar/assets/sass/_theme/_tooltips.scss index 01348e1b1..04c6f3cda 100644 --- a/src/registrar/assets/sass/_theme/_tooltips.scss +++ b/src/registrar/assets/sass/_theme/_tooltips.scss @@ -2,7 +2,7 @@ // Only apply this custom wrapping to desktop @include at-media(desktop) { - .usa-tooltip__body { + .usa-tooltip--registrar .usa-tooltip__body { width: 350px; white-space: normal; text-align: center; @@ -10,7 +10,7 @@ } @include at-media(tablet) { - .usa-tooltip__body { + .usa-tooltip--registrar .usa-tooltip__body { width: 250px !important; white-space: normal !important; text-align: center !important; @@ -18,7 +18,7 @@ } @include at-media(mobile) { - .usa-tooltip__body { + .usa-tooltip--registrar .usa-tooltip__body { width: 250px !important; white-space: normal !important; text-align: center !important; diff --git a/src/registrar/templates/admin/input_with_clipboard.html b/src/registrar/templates/admin/input_with_clipboard.html index c2de55bf1..76f76b63f 100644 --- a/src/registrar/templates/admin/input_with_clipboard.html +++ b/src/registrar/templates/admin/input_with_clipboard.html @@ -10,10 +10,14 @@ Template for an input field with a clipboard class="usa-button usa-button--unstyled padding-right-1 usa-button__icon usa-button__clipboard" type="button" > +
+
\ No newline at end of file diff --git a/src/registrar/templates/django/admin/includes/contact_detail_list.html b/src/registrar/templates/django/admin/includes/contact_detail_list.html index cded7526b..48a980fbc 100644 --- a/src/registrar/templates/django/admin/includes/contact_detail_list.html +++ b/src/registrar/templates/django/admin/includes/contact_detail_list.html @@ -25,18 +25,37 @@ {# Email #} {% if user.email or user.contact.email %} {% if user.contact.email %} - + {{ user.contact.email }} | + {% else %} - + {{ user.email }} | + {% endif %}
{% else %} diff --git a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html index 53bdbe821..459ffe438 100644 --- a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html +++ b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html @@ -84,7 +84,7 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) - + @@ -93,17 +93,24 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) + {% endfor %} diff --git a/src/registrar/templates/domain_users.html b/src/registrar/templates/domain_users.html index 65da4ef6b..5196b641a 100644 --- a/src/registrar/templates/domain_users.html +++ b/src/registrar/templates/domain_users.html @@ -84,7 +84,7 @@ {% else %} Date: Thu, 4 Apr 2024 12:41:33 -0600 Subject: [PATCH 20/30] Add copy logic --- src/registrar/assets/js/get-gov-admin.js | 32 +++++++++++++++++-- src/registrar/assets/sass/_theme/_admin.scss | 27 ++++++++++++++++ .../admin/includes/contact_detail_list.html | 21 ++++++++++-- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 581c2b899..a5f71ee0b 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -149,23 +149,49 @@ function openInNewTab(el, removeAttribute = false){ function copyToClipboardAndChangeIcon(button) { // Assuming the input is the previous sibling of the button let input = button.previousElementSibling; - + let userId = input.getAttribute("user-id") // Copy input value to clipboard if (input) { navigator.clipboard.writeText(input.value).then(function() { // Change the icon to a checkmark on successful copy - let buttonIcon = button .querySelector('.usa-button__clipboard use'); - console.log(`what is the button icon ${buttonIcon}`) + let buttonIcon = button.querySelector('.usa-button__clipboard use'); if (buttonIcon) { let currentHref = buttonIcon.getAttribute('xlink:href'); let baseHref = currentHref.split('#')[0]; // Append the new icon reference buttonIcon.setAttribute('xlink:href', baseHref + '#check'); + + // Find the nearest .admin-icon-group__success-dialog and update its classes + let brElement = null + let successDialog = document.querySelector(`#email-clipboard__success-dialog-${userId}`); + if (successDialog) { + successDialog.classList.remove('display-none'); + // Find the associated BR if it exists + brElement = successDialog.nextElementSibling + } + + // If the element directly below the success dialog is a br, hide it. + // This is for dynamic styling reasons + if (brElement && brElement.tagName === 'BR' && brElement.classList.contains('admin-icon-group__br')) { + brElement.classList.add('display-none'); + } + setTimeout(function() { // Change back to the copy icon buttonIcon.setAttribute('xlink:href', currentHref); + + // Hide the success dialog + if (successDialog){ + successDialog.classList.add("display-none"); + } + + // Show the regular br + if (brElement) { + brElement.classList.remove("display-none"); + } }, 1500); + } }).catch(function(error) { diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 8b5870b86..a3f969d9c 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -578,6 +578,33 @@ address.dja-address-contact-list { display: inline-flex; padding-top: 4px; line-height: 14px; + color: var(--link-fg); + } +} + +.usa-alert--slim.usa-alert--slim--dja-admin { + .usa-alert__body:before { + top: 0.4rem; + left: 10px + } + .usa-alert__body { + padding-left: 2.5rem; + } +} +@media (prefers-color-scheme: dark) { + .usa-alert--success.usa-alert--slim--dja-admin { + border-left-color: var(--accent); + .usa-alert__body { + background-color: var(--darkened-bg); + } + + .usa-alert__body:before { + background-color: var(--body-quiet-color); + } + + p { + color: var(--body-quiet-color); + } } } diff --git a/src/registrar/templates/django/admin/includes/contact_detail_list.html b/src/registrar/templates/django/admin/includes/contact_detail_list.html index 48a980fbc..4949d4194 100644 --- a/src/registrar/templates/django/admin/includes/contact_detail_list.html +++ b/src/registrar/templates/django/admin/includes/contact_detail_list.html @@ -43,7 +43,7 @@ {% else %} {{ user.email }} | + {% endif %} -
+
{% else %} None
{% endif %} From 95f9860bd9b0b770a775a2a66700f8dd56335da1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 4 Apr 2024 13:27:40 -0600 Subject: [PATCH 21/30] Add dialog --- src/registrar/assets/js/get-gov-admin.js | 18 ++++++++++++- src/registrar/assets/sass/_theme/_admin.scss | 10 ++++++++ .../admin/includes/contact_detail_list.html | 19 +++++++++++++- .../includes/email_clipboard_fieldset.html | 25 +++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index a5f71ee0b..1755a2a1c 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -163,9 +163,21 @@ function openInNewTab(el, removeAttribute = false){ buttonIcon.setAttribute('xlink:href', baseHref + '#check'); // Find the nearest .admin-icon-group__success-dialog and update its classes + let parentFlexContainer = null let brElement = null - let successDialog = document.querySelector(`#email-clipboard__success-dialog-${userId}`); + let successDialog = null + if (userId) { + successDialog = document.querySelector(`#email-clipboard__success-dialog-${userId}`); + }else { + successDialog = document.querySelector("#email-clipboard__success-dialog"); + } + if (successDialog) { + if (!userId) { + parentFlexContainer = successDialog.closest('.flex-container'); + // Flex container overrides display-none + parentFlexContainer.classList.remove('dja-important__display-none'); + } successDialog.classList.remove('display-none'); // Find the associated BR if it exists brElement = successDialog.nextElementSibling @@ -190,6 +202,10 @@ function openInNewTab(el, removeAttribute = false){ if (brElement) { brElement.classList.remove("display-none"); } + + if (parentFlexContainer) { + parentFlexContainer.classList.add("dja-important__display-none"); + } }, 1500); } diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index a3f969d9c..8e8294976 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -590,6 +590,12 @@ address.dja-address-contact-list { .usa-alert__body { padding-left: 2.5rem; } + + .admin-icon-group__success-dialog--input { + .usa-alert__body { + padding-right: 53px !important; + } + } } @media (prefers-color-scheme: dark) { .usa-alert--success.usa-alert--slim--dja-admin { @@ -618,4 +624,8 @@ svg.no-pointer-events { // and other components. In this event, we need to disable pointer interactions. pointer-events: none; } +} + +.dja-important__display-none { + display: none !important; } \ No newline at end of file diff --git a/src/registrar/templates/django/admin/includes/contact_detail_list.html b/src/registrar/templates/django/admin/includes/contact_detail_list.html index 4949d4194..b00e51547 100644 --- a/src/registrar/templates/django/admin/includes/contact_detail_list.html +++ b/src/registrar/templates/django/admin/includes/contact_detail_list.html @@ -27,7 +27,7 @@ {% if user.contact.email %} {{ user.contact.email }} | + {% else %} {{ user.email }} | +{% endif %} \ No newline at end of file diff --git a/src/registrar/templates/django/admin/includes/contact_detail_list.html b/src/registrar/templates/django/admin/includes/contact_detail_list.html index b00e51547..8ad6fb96d 100644 --- a/src/registrar/templates/django/admin/includes/contact_detail_list.html +++ b/src/registrar/templates/django/admin/includes/contact_detail_list.html @@ -25,71 +25,11 @@ {# Email #} {% if user.email or user.contact.email %} {% if user.contact.email %} - {{ user.contact.email }} | - - + {{ user.contact.email }} + {% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %} {% else %} - {{ user.email }} | - - + {{ user.email }} + {% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %} {% endif %}
{% else %} diff --git a/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html b/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html index ecd2a7d83..f959f8edf 100644 --- a/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html +++ b/src/registrar/templates/django/admin/includes/email_clipboard_fieldset.html @@ -11,28 +11,3 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) {{ block.super }} {% endif %} {% endblock field_other %} - -{% block after_help_text %} - {% if field.field.name == "email" %} -
- - -
- {% endif %} -{% endblock %} \ No newline at end of file From 6dc6299a0ff3f14dfa4dc479fa9bc28dd7157eab Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:09:56 -0600 Subject: [PATCH 23/30] Fix styling --- src/registrar/assets/js/get-gov-admin.js | 2 +- src/registrar/assets/sass/_theme/_admin.scss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index abe0877c1..844872144 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -170,7 +170,7 @@ function openInNewTab(el, removeAttribute = false){ // Change back to the copy icon buttonIcon.setAttribute('xlink:href', currentHref); nearestSpan.innerText = "Copy" - }, 1500); + }, 2000); } diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 94b497e8f..54160b4ff 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -399,13 +399,13 @@ address.margin-top-neg-1__detail-list { } td button.usa-button__clipboard-link, address.dja-address-contact-list { - font-size: 0.8125rem !important; + font-size: unset; } address.dja-address-contact-list { color: var(--body-quiet-color); button.usa-button__clipboard-link { - font-size: 0.8125rem !important; + font-size: unset; } } From 5535b9178e37962e19eb589e1f156f2e3a0feb13 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:09:36 -0600 Subject: [PATCH 24/30] Update detail_table_fieldset.html --- .../django/admin/includes/detail_table_fieldset.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html index 459ffe438..3ed8c4333 100644 --- a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html +++ b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html @@ -97,7 +97,7 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) - From e9332edc8b4a24ebdc7334465fcde84da872f39d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:21:45 -0600 Subject: [PATCH 25/30] Fix button styling --- src/registrar/assets/js/get-gov-admin.js | 7 +++++++ src/registrar/assets/sass/_theme/_admin.scss | 4 ++++ .../django/admin/includes/detail_table_fieldset.html | 8 ++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 844872144..2439d1346 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -164,11 +164,18 @@ function openInNewTab(el, removeAttribute = false){ // Change the button text nearestSpan = button.querySelector("span") + if (button.classList.contains('usa-button')) { + nearestSpan.innerText = "Copy email"; + } else { + nearestSpan.innerText = "Copy"; + } nearestSpan.innerText = "Copied to clipboard" setTimeout(function() { // Change back to the copy icon buttonIcon.setAttribute('xlink:href', currentHref); + usa-button__small + if (button.classList.) nearestSpan.innerText = "Copy" }, 2000); diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 54160b4ff..fd66754bc 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -597,3 +597,7 @@ address.dja-address-contact-list { .no-outline-on-click:focus { outline: none !important; } + +.usa-button__small-text { + font-size: small; +} diff --git a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html index 3ed8c4333..a0a679290 100644 --- a/src/registrar/templates/django/admin/includes/detail_table_fieldset.html +++ b/src/registrar/templates/django/admin/includes/detail_table_fieldset.html @@ -84,7 +84,7 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
Other contact informationOther contact information
{{ contact.get_formatted_name }} {{ contact.title }} - + {{ contact.email }} + {{ contact.phone }} + + +
{{ contact.phone }} +
- + @@ -97,10 +97,10 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html) - From 113b9b62bd2af783bf514c42823a2d75ad77df66 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:25:09 -0600 Subject: [PATCH 26/30] Update get-gov-admin.js --- src/registrar/assets/js/get-gov-admin.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 2439d1346..954035f95 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -164,19 +164,16 @@ function openInNewTab(el, removeAttribute = false){ // Change the button text nearestSpan = button.querySelector("span") - if (button.classList.contains('usa-button')) { - nearestSpan.innerText = "Copy email"; - } else { - nearestSpan.innerText = "Copy"; - } nearestSpan.innerText = "Copied to clipboard" setTimeout(function() { // Change back to the copy icon buttonIcon.setAttribute('xlink:href', currentHref); - usa-button__small - if (button.classList.) - nearestSpan.innerText = "Copy" + if (button.classList.contains('usa-button')) { + nearestSpan.innerText = "Copy email"; + } else { + nearestSpan.innerText = "Copy"; + } }, 2000); } From e4976e9da5a5d1dbad3693578f42aaaf111b6b5b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:37:57 -0600 Subject: [PATCH 27/30] Fix err --- src/registrar/assets/js/get-gov-admin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 954035f95..2909a48be 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -169,7 +169,7 @@ function openInNewTab(el, removeAttribute = false){ setTimeout(function() { // Change back to the copy icon buttonIcon.setAttribute('xlink:href', currentHref); - if (button.classList.contains('usa-button')) { + if (button.classList.contains('usa-button__small-text')) { nearestSpan.innerText = "Copy email"; } else { nearestSpan.innerText = "Copy"; From 3837c3ca21b91e1aba0d2680a86c1f510956a498 Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Fri, 5 Apr 2024 14:50:33 -0700 Subject: [PATCH 28/30] updated files --- ops/manifests/manifest-ab.yaml | 2 +- ops/manifests/manifest-stable.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ops/manifests/manifest-ab.yaml b/ops/manifests/manifest-ab.yaml index 3ca800392..c7228a7c4 100644 --- a/ops/manifests/manifest-ab.yaml +++ b/ops/manifests/manifest-ab.yaml @@ -5,7 +5,7 @@ applications: - python_buildpack path: ../../src instances: 1 - memory: 512M + memory: 1G stack: cflinuxfs4 timeout: 180 command: ./run.sh diff --git a/ops/manifests/manifest-stable.yaml b/ops/manifests/manifest-stable.yaml index a70035445..80c97339f 100644 --- a/ops/manifests/manifest-stable.yaml +++ b/ops/manifests/manifest-stable.yaml @@ -5,7 +5,7 @@ applications: - python_buildpack path: ../../src instances: 2 - memory: 512M + memory: 1G stack: cflinuxfs4 timeout: 180 command: ./run.sh From 839b325e66b38d5281e92d941d0300d64fdd1373 Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Fri, 5 Apr 2024 15:59:25 -0700 Subject: [PATCH 29/30] undo my manifest change --- ops/manifests/manifest-ab.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ops/manifests/manifest-ab.yaml b/ops/manifests/manifest-ab.yaml index c7228a7c4..3ca800392 100644 --- a/ops/manifests/manifest-ab.yaml +++ b/ops/manifests/manifest-ab.yaml @@ -5,7 +5,7 @@ applications: - python_buildpack path: ../../src instances: 1 - memory: 1G + memory: 512M stack: cflinuxfs4 timeout: 180 command: ./run.sh From 9a2e827634d63fbe702c2beb3a06abaac92bff0a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 8 Apr 2024 08:34:39 -0600 Subject: [PATCH 30/30] Fix unit tests --- src/registrar/tests/test_admin.py | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index af10dd2eb..bf92b3178 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1455,41 +1455,37 @@ class TestDomainRequestAdmin(MockEppLib): self.assertContains(response, "Meoward Jones") # == Check for the submitter == # + self.assertContains(response, "mayor@igorville.gov", count=2) expected_submitter_fields = [ # Field, expected value ("title", "Admin Tester"), - ("email", "mayor@igorville.gov"), ("phone", "(555) 555 5556"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_submitter_fields) self.assertContains(response, "Testy2 Tester2") # == Check for the authorizing_official == # - + self.assertContains(response, "testy@town.com", count=2) expected_ao_fields = [ # Field, expected value ("title", "Chief Tester"), - ("email", "testy@town.com"), ("phone", "(555) 555 5555"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_ao_fields) - # count=5 because the underlying domain has two users with this name. - # The dropdown has 3 of these. - self.assertContains(response, "Testy Tester", count=5) + self.assertContains(response, "Testy Tester", count=10) # == Test the other_employees field == # - + self.assertContains(response, "testy2@town.com", count=2) expected_other_employees_fields = [ # Field, expected value ("title", "Another Tester"), - ("email", "testy2@town.com"), ("phone", "(555) 555 5557"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields) # Test for the copy link - self.assertContains(response, "usa-button__clipboard-link", count=4) + self.assertContains(response, "usa-button__clipboard", count=4) def test_save_model_sets_restricted_status_on_user(self): with less_console_noise(): @@ -2219,41 +2215,37 @@ class TestDomainInformationAdmin(TestCase): self.assertContains(response, "Meoward Jones") # == Check for the submitter == # + self.assertContains(response, "mayor@igorville.gov", count=2) expected_submitter_fields = [ # Field, expected value ("title", "Admin Tester"), - ("email", "mayor@igorville.gov"), ("phone", "(555) 555 5556"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_submitter_fields) self.assertContains(response, "Testy2 Tester2") # == Check for the authorizing_official == # - + self.assertContains(response, "testy@town.com", count=2) expected_ao_fields = [ # Field, expected value ("title", "Chief Tester"), - ("email", "testy@town.com"), ("phone", "(555) 555 5555"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_ao_fields) - # count=5 because the underlying domain has two users with this name. - # The dropdown has 3 of these. - self.assertContains(response, "Testy Tester", count=5) + self.assertContains(response, "Testy Tester", count=10) # == Test the other_employees field == # - + self.assertContains(response, "testy2@town.com", count=2) expected_other_employees_fields = [ # Field, expected value ("title", "Another Tester"), - ("email", "testy2@town.com"), ("phone", "(555) 555 5557"), ] self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields) # Test for the copy link - self.assertContains(response, "usa-button__clipboard-link", count=4) + self.assertContains(response, "usa-button__clipboard", count=4) def test_readonly_fields_for_analyst(self): """Ensures that analysts have their permissions setup correctly"""
Other contact informationOther contact information
{{ contact.phone }} +