feat: Implemented single and multiselect autocomplete

This commit is contained in:
musanaeem
2025-04-23 21:03:24 +05:00
committed by awais qureshi
parent 755f757bc3
commit 2522bc6ff9
5 changed files with 118 additions and 2 deletions

View File

@@ -2,6 +2,7 @@
from functools import wraps
from dal import autocomplete
from config_models.admin import ConfigurationModelAdmin
from django import forms
@@ -16,7 +17,7 @@ from django.contrib.auth.forms import UserChangeForm as BaseUserChangeForm
from django.db import models, router, transaction
from django.http import HttpResponseRedirect
from django.http.request import QueryDict
from django.urls import reverse
from django.urls import reverse, path
from django.utils.translation import ngettext
from django.utils.translation import gettext_lazy as _
from opaque_keys import InvalidKeyError
@@ -45,6 +46,7 @@ from common.djangoapps.student.models import (
UserProfile,
UserTestGroup
)
from common.djangoapps.student.constants import LANGUAGE_CHOICES
from common.djangoapps.student.roles import REGISTERED_ACCESS_ROLES
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
@@ -309,9 +311,25 @@ class CourseEnrollmentAdmin(DisableEnrollmentAdminMixin, admin.ModelAdmin):
return super().get_queryset(request).select_related('user') # lint-amnesty, pylint: disable=no-member, super-with-arguments
class LanguageAutocomplete(autocomplete.Select2ListView):
def get_list(self):
return [lang for lang in LANGUAGE_CHOICES if self.q.lower() in lang.lower()]
class UserProfileInlineForm(forms.ModelForm):
language = forms.CharField(
required=False,
widget=autocomplete.ListSelect2(url='admin:language-autocomplete')
)
class Meta:
model = UserProfile
fields = '__all__'
class UserProfileInline(admin.StackedInline):
""" Inline admin interface for UserProfile model. """
model = UserProfile
form = UserProfileInlineForm
can_delete = False
verbose_name_plural = _('User profile')
@@ -359,6 +377,17 @@ class UserAdmin(BaseUserAdmin):
return django_readonly + ('username',)
return django_readonly
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path(
'language-autocomplete/',
LanguageAutocomplete.as_view(),
name='language-autocomplete'
),
]
return custom_urls + urls
@admin.register(UserAttribute)
class UserAttributeAdmin(admin.ModelAdmin):

View File

@@ -0,0 +1,3 @@
import pycountry
LANGUAGE_CHOICES = sorted({lang.name for lang in pycountry.languages if hasattr(lang, 'alpha_2')})

View File

@@ -3042,6 +3042,9 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.sites',
'dal',
'dal_select2',
# Tweaked version of django.contrib.staticfiles
'openedx.core.djangoapps.staticfiles.apps.EdxPlatformStaticFilesConfig',

View File

@@ -1,17 +1,81 @@
"""
Django admin page for Site Configuration models
"""
from dal import autocomplete
from django import forms
from django.urls import path
from django.utils.translation import gettext_lazy as _
from django.contrib import admin
from .constants import FEATURE_FLAGS
from .models import SiteConfiguration, SiteConfigurationHistory
class FeatureFlagAutocomplete(autocomplete.Select2ListView):
def get_list(self):
return list(FEATURE_FLAGS.keys())
def get_result_label(self, item):
return item
def get_result_value(self, item):
return item
class SiteConfigurationForm(forms.ModelForm):
feature_flags = forms.Field(
required=False,
widget=autocomplete.Select2Multiple(
url='admin:feature-flag-autocomplete',
attrs={
'multiple': 'multiple',
'data-tags': 'true',
'data-placeholder': 'Select features'
}
),
label="Enabled Features",
)
class Meta:
model = SiteConfiguration
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['site_values'].widget = forms.HiddenInput()
current_values = self.instance.site_values or {}
selected_labels = []
for label, mapping in FEATURE_FLAGS.items():
if all(current_values.get(k) == v for k, v in mapping.items()):
selected_labels.append(label)
self.fields['feature_flags'].initial = selected_labels
self.fields['feature_flags'].widget.choices = [(v, v) for v in selected_labels]
def clean(self):
cleaned = super().clean()
selected_flags = self.data.getlist('feature_flags')
if not isinstance(selected_flags, list):
selected_flags = [selected_flags] if selected_flags else []
site_values = {}
for label in selected_flags:
site_values.update(FEATURE_FLAGS.get(label, {}))
cleaned['feature_flags'] = selected_flags
cleaned['site_values'] = site_values
# self.selected_flags = selected_flags
# self.site_values = site_values
return cleaned
class SiteConfigurationAdmin(admin.ModelAdmin):
"""
Admin interface for the SiteConfiguration object.
"""
form = SiteConfigurationForm
list_display = ('site', 'enabled', 'site_values')
search_fields = ('site__domain', 'site_values')
@@ -21,6 +85,17 @@ class SiteConfigurationAdmin(admin.ModelAdmin):
"""
model = SiteConfiguration
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path(
'feature-flag-autocomplete/',
FeatureFlagAutocomplete.as_view(),
name='feature-flag-autocomplete'
),
]
return custom_urls + urls
admin.site.register(SiteConfiguration, SiteConfigurationAdmin)

View File

@@ -0,0 +1,6 @@
# TODO: Dummy Tags to be replaced by real values
FEATURE_FLAGS = {
'Forum Notifications': {'enable_forum_notifications': True},
'Live Chat': {'enable_live_chat': True},
'Dark Mode': {'enable_dark_mode': True},
}