Add autocomplete off attribute

This commit is contained in:
Rachid Mrad 2024-02-15 14:43:15 -05:00
parent 2ad8b2e2ec
commit 334b913732
No known key found for this signature in database
2 changed files with 86 additions and 33 deletions

View file

@ -6,6 +6,7 @@ from django.shortcuts import redirect
from django_fsm import get_available_FIELD_transitions from django_fsm import get_available_FIELD_transitions
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.admin.options import BaseModelAdmin
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.http.response import HttpResponseRedirect from django.http.response import HttpResponseRedirect
@ -16,6 +17,7 @@ from registrar.models.user import User
from registrar.utility import csv_export from registrar.utility import csv_export
from registrar.views.utility.mixins import OrderableFieldsMixin from registrar.views.utility.mixins import OrderableFieldsMixin
from django.contrib.admin.views.main import ORDER_VAR from django.contrib.admin.views.main import ORDER_VAR
from registrar.widgets import NoAutocompleteFilteredSelectMultiple
from . import models from . import models
from auditlog.models import LogEntry # type: ignore from auditlog.models import LogEntry # type: ignore
from auditlog.admin import LogEntryAdmin # type: ignore from auditlog.admin import LogEntryAdmin # type: ignore
@ -26,6 +28,67 @@ from django.utils.html import escape
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class MyUserAdminForm(forms.ModelForm):
class Meta:
model = models.User
fields = '__all__'
widgets = {
'groups': NoAutocompleteFilteredSelectMultiple('groups', False),
'user_permissions': NoAutocompleteFilteredSelectMultiple('user_permissions', False),
}
class DomainInformationAdminForm(forms.ModelForm):
class Meta:
model = models.DomainInformation
fields = '__all__'
widgets = {
'other_contacts': NoAutocompleteFilteredSelectMultiple('other_contacts', False),
}
class DomainInformationInlineForm(forms.ModelForm):
class Meta:
model = models.DomainInformation
fields = '__all__'
widgets = {
'other_contacts': NoAutocompleteFilteredSelectMultiple('other_contacts', False),
}
class DomainApplicationAdminForm(forms.ModelForm):
"""Custom form to limit transitions to available transitions"""
class Meta:
model = models.DomainApplication
fields = "__all__"
widgets = {
'current_websites': NoAutocompleteFilteredSelectMultiple('current_websites', False),
'alternative_domains': NoAutocompleteFilteredSelectMultiple('alternative_domains', False),
'other_contacts': NoAutocompleteFilteredSelectMultiple('other_contacts', False),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
application = kwargs.get("instance")
if application and application.pk:
current_state = application.status
# first option in status transitions is current state
available_transitions = [(current_state, application.get_status_display())]
transitions = get_available_FIELD_transitions(
application, models.DomainApplication._meta.get_field("status")
)
for transition in transitions:
available_transitions.append((transition.target, transition.target.label))
# only set the available transitions if the user is not restricted
# from editing the domain application; otherwise, the form will be
# readonly and the status field will not have a widget
if not application.creator.is_restricted():
self.fields["status"].widget.choices = available_transitions
# Based off of this excellent example: https://djangosnippets.org/snippets/10471/ # Based off of this excellent example: https://djangosnippets.org/snippets/10471/
class MultiFieldSortableChangeList(admin.views.main.ChangeList): class MultiFieldSortableChangeList(admin.views.main.ChangeList):
""" """
@ -265,6 +328,8 @@ class UserContactInline(admin.StackedInline):
class MyUserAdmin(BaseUserAdmin): class MyUserAdmin(BaseUserAdmin):
"""Custom user admin class to use our inlines.""" """Custom user admin class to use our inlines."""
form = MyUserAdminForm
inlines = [UserContactInline] inlines = [UserContactInline]
list_display = ( list_display = (
@ -603,6 +668,8 @@ class DomainInvitationAdmin(ListHeaderAdmin):
class DomainInformationAdmin(ListHeaderAdmin): class DomainInformationAdmin(ListHeaderAdmin):
"""Customize domain information admin class.""" """Customize domain information admin class."""
form = DomainInformationAdminForm
# Columns # Columns
list_display = [ list_display = [
"domain", "domain",
@ -707,41 +774,12 @@ class DomainInformationAdmin(ListHeaderAdmin):
return readonly_fields # Read-only fields for analysts return readonly_fields # Read-only fields for analysts
class DomainApplicationAdminForm(forms.ModelForm):
"""Custom form to limit transitions to available transitions"""
class Meta:
model = models.DomainApplication
fields = "__all__"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
application = kwargs.get("instance")
if application and application.pk:
current_state = application.status
# first option in status transitions is current state
available_transitions = [(current_state, application.get_status_display())]
transitions = get_available_FIELD_transitions(
application, models.DomainApplication._meta.get_field("status")
)
for transition in transitions:
available_transitions.append((transition.target, transition.target.label))
# only set the available transitions if the user is not restricted
# from editing the domain application; otherwise, the form will be
# readonly and the status field will not have a widget
if not application.creator.is_restricted():
self.fields["status"].widget.choices = available_transitions
class DomainApplicationAdmin(ListHeaderAdmin): class DomainApplicationAdmin(ListHeaderAdmin):
"""Custom domain applications admin class.""" """Custom domain applications admin class."""
form = DomainApplicationAdminForm
class InvestigatorFilter(admin.SimpleListFilter): class InvestigatorFilter(admin.SimpleListFilter):
"""Custom investigator filter that only displays users with the manager role""" """Custom investigator filter that only displays users with the manager role"""
@ -791,8 +829,6 @@ class DomainApplicationAdmin(ListHeaderAdmin):
] ]
search_help_text = "Search by domain or submitter." search_help_text = "Search by domain or submitter."
# Detail view
form = DomainApplicationAdminForm
fieldsets = [ fieldsets = [
(None, {"fields": ["status", "investigator", "creator", "approved_domain", "notes"]}), (None, {"fields": ["status", "investigator", "creator", "approved_domain", "notes"]}),
( (
@ -996,6 +1032,8 @@ class DomainInformationInline(admin.StackedInline):
classes conflict, so we'll just pull what we need classes conflict, so we'll just pull what we need
from DomainInformationAdmin""" from DomainInformationAdmin"""
form = DomainInformationInlineForm
model = models.DomainInformation model = models.DomainInformation
fieldsets = DomainInformationAdmin.fieldsets fieldsets = DomainInformationAdmin.fieldsets

15
src/registrar/widgets.py Normal file
View file

@ -0,0 +1,15 @@
# widgets.py
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.safestring import mark_safe
class NoAutocompleteFilteredSelectMultiple(FilteredSelectMultiple):
"""Firefox and Edge are unable to correctly initialize the source select in filter_horizontal
widgets. We add the attribute autocomplete=off to fix that."""
def render(self, name, value, attrs=None, renderer=None):
if attrs is None:
attrs = {}
attrs['autocomplete'] = 'off'
output = super().render(name, value, attrs=attrs, renderer=renderer)
return mark_safe(output)