summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/admin/static/admin/css/forms.css4
-rw-r--r--docs/releases/5.1.2.txt4
-rw-r--r--tests/admin_views/tests.py59
3 files changed, 67 insertions, 0 deletions
diff --git a/django/contrib/admin/static/admin/css/forms.css b/django/contrib/admin/static/admin/css/forms.css
index ae697cf58d..c6ce78833e 100644
--- a/django/contrib/admin/static/admin/css/forms.css
+++ b/django/contrib/admin/static/admin/css/forms.css
@@ -169,6 +169,10 @@ form .aligned select + div.help {
padding-left: 10px;
}
+form .aligned select option:checked {
+ background-color: var(--selected-row);
+}
+
form .aligned ul li {
list-style: none;
}
diff --git a/docs/releases/5.1.2.txt b/docs/releases/5.1.2.txt
index 2727b112dc..a7293654df 100644
--- a/docs/releases/5.1.2.txt
+++ b/docs/releases/5.1.2.txt
@@ -16,3 +16,7 @@ Bugfixes
* Fixed a regression in Django 5.1 that caused a crash of ``JSONObject()``
when using server-side binding with PostgreSQL 16+ (:ticket:`35734`).
+
+* Fixed a regression in Django 5.1 that made selected items in multi-select
+ widgets indistinguishable from non-selected items in the admin dark theme
+ (:ticket:`35809`).
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 16d76f5da2..f63a9ca56f 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -6176,6 +6176,65 @@ class SeleniumTests(AdminSeleniumTestCase):
self.take_screenshot("selectbox-non-collapsible")
@screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"])
+ def test_selectbox_selected_rows(self):
+ from selenium.webdriver import ActionChains
+ from selenium.webdriver.common.by import By
+ from selenium.webdriver.common.keys import Keys
+
+ self.admin_login(
+ username="super", password="secret", login_url=reverse("admin:index")
+ )
+ # Create a new user to ensure that no extra permissions have been set.
+ user = User.objects.create_user(username="new", password="newuser")
+ url = self.live_server_url + reverse("admin:auth_user_change", args=[user.id])
+ self.selenium.get(url)
+
+ # Scroll to the User permissions section.
+ user_permissions = self.selenium.find_element(
+ By.CSS_SELECTOR, "#id_user_permissions_from"
+ )
+ ActionChains(self.selenium).move_to_element(user_permissions).perform()
+ self.take_screenshot("selectbox-available-perms-none-selected")
+
+ # Select multiple permissions from the "Available" list.
+ ct = ContentType.objects.get_for_model(Permission)
+ perms = list(Permission.objects.filter(content_type=ct))
+ for perm in perms:
+ elem = self.selenium.find_element(
+ By.CSS_SELECTOR, f"#id_user_permissions_from option[value='{perm.id}']"
+ )
+ ActionChains(self.selenium).key_down(Keys.CONTROL).click(elem).key_up(
+ Keys.CONTROL
+ ).perform()
+
+ # Move focus to other element.
+ self.selenium.find_element(
+ By.CSS_SELECTOR, "#id_user_permissions_input"
+ ).click()
+ self.take_screenshot("selectbox-available-perms-some-selected")
+
+ # Move permissions to the "Chosen" list, but none is selected yet.
+ self.selenium.find_element(
+ By.CSS_SELECTOR, "#id_user_permissions_add_link"
+ ).click()
+ self.take_screenshot("selectbox-chosen-perms-none-selected")
+
+ # Select some permissions from the "Chosen" list.
+ for perm in [perms[0], perms[-1]]:
+ elem = self.selenium.find_element(
+ By.CSS_SELECTOR, f"#id_user_permissions_to option[value='{perm.id}']"
+ )
+ ActionChains(self.selenium).key_down(Keys.CONTROL).click(elem).key_up(
+ Keys.CONTROL
+ ).perform()
+
+ # Move focus to other element.
+ self.selenium.find_element(
+ By.CSS_SELECTOR, "#id_user_permissions_selected_input"
+ ).click()
+ self.take_screenshot("selectbox-chosen-perms-some-selected")
+
+ @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"])
def test_first_field_focus(self):
"""JavaScript-assisted auto-focus on first usable form field."""
from selenium.webdriver.common.by import By