From 7e918ff537e517f8d70eab13396638ba711b07ad Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Thu, 7 Sep 2023 17:33:37 -0400 Subject: [PATCH 1/7] admin: add favicon, fix button height bug, remove link from table caption, add search helper text to logentry, remove submit buttons from logentry --- src/registrar/admin.py | 13 ++++++++++++ src/registrar/assets/sass/_theme/_admin.scss | 8 +++++--- src/registrar/templates/admin/app_list.html | 6 ++++-- src/registrar/templates/admin/base_site.html | 18 +++++++++++++++++ .../templates/admin/change_form.html | 2 +- .../admin/change_form_no_submit.html | 20 +++++++++++++++++++ 6 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/registrar/templates/admin/change_form_no_submit.html diff --git a/src/registrar/admin.py b/src/registrar/admin.py index d6109a0cc..7b798e692 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -6,9 +6,20 @@ from django.http.response import HttpResponseRedirect from django.urls import reverse from registrar.models.utility.admin_sort_fields import AdminSortFields from . import models +from auditlog.models import LogEntry # type: ignore +from auditlog.admin import LogEntryAdmin # type: ignore + logger = logging.getLogger(__name__) +class CustomLogEntryAdmin(LogEntryAdmin): + # Overwrite the generated LogEntry admin class + + search_help_text = "Search by resource, changed field, or user." + + change_form_template = 'admin/change_form_no_submit.html' + add_form_template = 'admin/change_form_no_submit.html' + class AuditedAdmin(admin.ModelAdmin, AdminSortFields): """Custom admin to make auditing easier.""" @@ -400,6 +411,8 @@ class DomainApplicationAdmin(ListHeaderAdmin): return super().change_view(request, object_id, form_url, extra_context) +admin.site.unregister(LogEntry) # Unregister the default registration +admin.site.register(LogEntry, CustomLogEntryAdmin) admin.site.register(models.User, MyUserAdmin) admin.site.register(models.UserDomainRole, AuditedAdmin) admin.site.register(models.Contact, ContactAdmin) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index b87257344..739e3578d 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -140,7 +140,7 @@ h1, h2, h3 { font-weight: font-weight('bold'); } -table > caption > a { +table > caption > span { font-weight: font-weight('bold'); text-transform: none; } @@ -158,8 +158,10 @@ table > caption > a { padding-top: 20px; } -// 'Delete button' layout bug -.submit-row a.deletelink { +// Fix django admin button height bugs +.submit-row a.deletelink, +.delete-confirmation form .cancel-link, +.submit-row a.closelink { height: auto!important; } diff --git a/src/registrar/templates/admin/app_list.html b/src/registrar/templates/admin/app_list.html index fb5934470..3b402827e 100644 --- a/src/registrar/templates/admin/app_list.html +++ b/src/registrar/templates/admin/app_list.html @@ -4,11 +4,13 @@ {% for app in app_list %}
+ {# .gov override: remove link #} + {# end .gov override #} - {# .gov override #} + {# .gov override: add headers #} diff --git a/src/registrar/templates/admin/base_site.html b/src/registrar/templates/admin/base_site.html index 6b641722f..dcdd29e2f 100644 --- a/src/registrar/templates/admin/base_site.html +++ b/src/registrar/templates/admin/base_site.html @@ -2,6 +2,24 @@ {% load static %} {% load i18n %} +{% block extrahead %} + + + + + +{% endblock %} + {% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} {% block extrastyle %}{{ block.super }} diff --git a/src/registrar/templates/admin/change_form.html b/src/registrar/templates/admin/change_form.html index e0f9ae1a4..78dac9ac0 100644 --- a/src/registrar/templates/admin/change_form.html +++ b/src/registrar/templates/admin/change_form.html @@ -9,4 +9,4 @@ {% endblock %} {% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/src/registrar/templates/admin/change_form_no_submit.html b/src/registrar/templates/admin/change_form_no_submit.html new file mode 100644 index 000000000..04a491aae --- /dev/null +++ b/src/registrar/templates/admin/change_form_no_submit.html @@ -0,0 +1,20 @@ +{% extends "admin/change_form.html" %} + +{% comment %} Replace the Django ul markup with a div. We'll edit the child markup accordingly in change_form_object_tools {% endcomment %} +{% block object-tools %} +{% if change and not is_popup %} +
+ {% block object-tools-items %} + {{ block.super }} + {% endblock %} +
+{% endif %} +{% endblock %} + +{% block submit_buttons_top %} + {# Do not render the submit buttons #} +{% endblock %} + +{% block submit_buttons_bottom %} + {# Do not render the submit buttons #} +{% endblock %} From 4ca3a2712e313cdc76601b190469a5e6808f8f1b Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Fri, 8 Sep 2023 12:01:53 -0400 Subject: [PATCH 2/7] remoce links from resources columns in audit log --- src/registrar/admin.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 7b798e692..9d0f9397e 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -8,14 +8,33 @@ from registrar.models.utility.admin_sort_fields import AdminSortFields from . import models from auditlog.models import LogEntry # type: ignore from auditlog.admin import LogEntryAdmin # type: ignore - +from django.contrib.auth import get_user_model logger = logging.getLogger(__name__) class CustomLogEntryAdmin(LogEntryAdmin): # Overwrite the generated LogEntry admin class + # list_select_related = ["content_type", "actor"] + list_display = [ + "created", + "custom_resource_url", + "action", + "msg_short", + "user_url", + ] + # search_fields = [ + # "content_type", + # "object_repr", + # "changes", + # ] - search_help_text = "Search by resource, changed field, or user." + def custom_resource_url(self, obj): + # Replace 'my_field' with the name of your field + return f"{obj.content_type} - {obj.object_repr}" # Return the field value without a link + + custom_resource_url.short_description = 'Resource' + + search_help_text = "Search by resource, changes, or user." change_form_template = 'admin/change_form_no_submit.html' add_form_template = 'admin/change_form_no_submit.html' From b45c5665d3fd3f29719dc43342195ed3366ec124 Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Fri, 8 Sep 2023 17:50:28 -0400 Subject: [PATCH 3/7] add email address to contact table, add domain info search, columns, filters, add domain invite columns, search, add domain columns, filters, add domain roles, add website search --- src/registrar/admin.py | 154 ++++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 31 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 9d0f9397e..1d26c714a 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -6,38 +6,34 @@ from django.http.response import HttpResponseRedirect from django.urls import reverse from registrar.models.utility.admin_sort_fields import AdminSortFields from . import models -from auditlog.models import LogEntry # type: ignore -from auditlog.admin import LogEntryAdmin # type: ignore -from django.contrib.auth import get_user_model +from auditlog.models import LogEntry # type: ignore +from auditlog.admin import LogEntryAdmin # type: ignore logger = logging.getLogger(__name__) + class CustomLogEntryAdmin(LogEntryAdmin): - # Overwrite the generated LogEntry admin class - # list_select_related = ["content_type", "actor"] + """Overwrite the generated LogEntry admin class""" + list_display = [ "created", - "custom_resource_url", + "resource", "action", "msg_short", "user_url", ] - # search_fields = [ - # "content_type", - # "object_repr", - # "changes", - # ] - - def custom_resource_url(self, obj): - # Replace 'my_field' with the name of your field - return f"{obj.content_type} - {obj.object_repr}" # Return the field value without a link - - custom_resource_url.short_description = 'Resource' - + + # We name the custom prop 'resource' because linter + # is not allowing a short_description attr on it + # This gets around the linter limitation, for now. + def resource(self, obj): + # Return the field value without a link + return f"{obj.content_type} - {obj.object_repr}" + search_help_text = "Search by resource, changes, or user." - - change_form_template = 'admin/change_form_no_submit.html' - add_form_template = 'admin/change_form_no_submit.html' + + change_form_template = "admin/change_form_no_submit.html" + add_form_template = "admin/change_form_no_submit.html" class AuditedAdmin(admin.ModelAdmin, AdminSortFields): @@ -121,14 +117,12 @@ class ListHeaderAdmin(AuditedAdmin): class UserContactInline(admin.StackedInline): - """Edit a user's profile on the user page.""" model = models.Contact class MyUserAdmin(BaseUserAdmin): - """Custom user admin class to use our inlines.""" inlines = [UserContactInline] @@ -182,23 +176,35 @@ class MyUserAdmin(BaseUserAdmin): class HostIPInline(admin.StackedInline): - """Edit an ip address on the host page.""" model = models.HostIP class MyHostAdmin(AuditedAdmin): - """Custom host admin class to use our inlines.""" inlines = [HostIPInline] class DomainAdmin(ListHeaderAdmin): - """Custom domain admin class to add extra buttons.""" + # Columns + list_display = [ + "name", + "organization_type", + "state", + ] + + def organization_type(self, obj): + return ( + obj.domain_info.organization_type + ) + + # Filters + list_filter = ["domain_info__organization_type"] + search_fields = ["name"] search_help_text = "Search by domain name." change_form_template = "django/admin/domain_change_form.html" @@ -252,11 +258,97 @@ class ContactAdmin(ListHeaderAdmin): search_fields = ["email", "first_name", "last_name"] search_help_text = "Search by firstname, lastname or email." + list_display = [ + "contact", + "email", + ] + + # 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. + def contact(self, obj): + if obj.first_name or obj.last_name: + return obj.get_formatted_name() + elif obj.email: + return obj.email + elif obj.pk: + return str(obj.pk) + else: + return "" + + +class WebsiteAdmin(ListHeaderAdmin): + """Custom website admin class.""" + + # Search + search_fields = [ + "website", + ] + search_help_text = "Search by website." + + +class UserDomainRoleAdmin(ListHeaderAdmin): + """Custom domain role admin class.""" + + # Columns + list_display = [ + "user", + "domain", + "role", + ] + + # Search + search_fields = [ + "user__first_name", + "user__last_name", + "domain__name", + "role", + ] + search_help_text = "Search by user, domain, or role." + + +class DomainInvitationAdmin(ListHeaderAdmin): + """Custom domain invitation admin class.""" + + # Columns + list_display = [ + "email", + "domain", + "status", + ] + + # Search + search_fields = [ + "email", + "domain__name", + ] + search_help_text = "Search by email or domain." + + +class DomainInformationAdmin(ListHeaderAdmin): + """Customize domain information admin class.""" + + # Columns + list_display = [ + "domain", + "organization_type", + "created_at", + "submitter", + ] + + # Filters + list_filter = ["organization_type"] + + # Search + search_fields = [ + "domain__name", + ] + search_help_text = "Search by domain." class DomainApplicationAdmin(ListHeaderAdmin): - """Customize the applications listing view.""" + """Custom domain applications admin class.""" # Set multi-selects 'read-only' (hide selects and show data) # based on user perms and application creator's status @@ -433,12 +525,12 @@ class DomainApplicationAdmin(ListHeaderAdmin): admin.site.unregister(LogEntry) # Unregister the default registration admin.site.register(LogEntry, CustomLogEntryAdmin) admin.site.register(models.User, MyUserAdmin) -admin.site.register(models.UserDomainRole, AuditedAdmin) +admin.site.register(models.UserDomainRole, UserDomainRoleAdmin) admin.site.register(models.Contact, ContactAdmin) -admin.site.register(models.DomainInvitation, AuditedAdmin) -admin.site.register(models.DomainInformation, AuditedAdmin) +admin.site.register(models.DomainInvitation, DomainInvitationAdmin) +admin.site.register(models.DomainInformation, DomainInformationAdmin) admin.site.register(models.Domain, DomainAdmin) admin.site.register(models.Host, MyHostAdmin) admin.site.register(models.Nameserver, MyHostAdmin) -admin.site.register(models.Website, AuditedAdmin) +admin.site.register(models.Website, WebsiteAdmin) admin.site.register(models.DomainApplication, DomainApplicationAdmin) From 2ba48edb7f95aacdda82c47d1286da38f72a6cce Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Fri, 8 Sep 2023 18:34:31 -0400 Subject: [PATCH 4/7] lint --- 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 1d26c714a..a7026e8cc 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -198,9 +198,7 @@ class DomainAdmin(ListHeaderAdmin): ] def organization_type(self, obj): - return ( - obj.domain_info.organization_type - ) + return obj.domain_info.organization_type # Filters list_filter = ["domain_info__organization_type"] From 2df68d4b5273be1c683e17cd34425230898a927f Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Mon, 11 Sep 2023 16:06:36 -0400 Subject: [PATCH 5/7] typecast obj and add a comment to the contact custom list_display for ContactAdmin --- src/registrar/admin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index a7026e8cc..069c07311 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -264,7 +264,8 @@ class ContactAdmin(ListHeaderAdmin): # 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. - def contact(self, obj): + def contact(self, obj: models.Contact): + """ Duplicate the contact _str_""" if obj.first_name or obj.last_name: return obj.get_formatted_name() elif obj.email: From 2dd6bc6f05289a03318581797895c8f31f83f7df Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Mon, 11 Sep 2023 17:50:49 -0400 Subject: [PATCH 6/7] fix unsortable custom columns, fix font-size discrepancy on fixed buttons, lint --- src/registrar/admin.py | 8 +++++++- src/registrar/assets/sass/_theme/_admin.scss | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 069c07311..4bf466912 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -200,6 +200,10 @@ class DomainAdmin(ListHeaderAdmin): def organization_type(self, obj): return obj.domain_info.organization_type + organization_type.admin_order_field = ( # type: ignore + "domain_info__organization_type" + ) + # Filters list_filter = ["domain_info__organization_type"] @@ -265,7 +269,7 @@ class ContactAdmin(ListHeaderAdmin): # is not allowing a short_description attr on it # This gets around the linter limitation, for now. def contact(self, obj: models.Contact): - """ Duplicate the contact _str_""" + """Duplicate the contact _str_""" if obj.first_name or obj.last_name: return obj.get_formatted_name() elif obj.email: @@ -275,6 +279,8 @@ class ContactAdmin(ListHeaderAdmin): else: return "" + contact.admin_order_field = "first_name" # type: ignore + class WebsiteAdmin(ListHeaderAdmin): """Custom website admin class.""" diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 739e3578d..eadf32522 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -163,6 +163,7 @@ table > caption > span { .delete-confirmation form .cancel-link, .submit-row a.closelink { height: auto!important; + font-size: 14px; } // Keep th from collapsing From 16f69deda928dd5585ae0ad51008fd70515592b8 Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Mon, 11 Sep 2023 17:56:15 -0400 Subject: [PATCH 7/7] lighten hover color --- src/registrar/assets/sass/_theme/_admin.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index eadf32522..9b8ed1e11 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -31,7 +31,7 @@ html[data-theme="light"] { // #{$theme-link-color} would interpolate to 'primary', so we use the source value instead --link-fg: #{$theme-color-primary}; - --link-hover-color: #{$theme-color-primary-darker}; + --link-hover-color: #{$theme-color-primary}; // $theme-link-visited-color - violet-70v --link-selected-fg: #54278f;
- {{ app.name }} + {{ app.name }}
Model