diff --git a/admin/forms.py b/admin/forms.py index e92d741c..e5962a39 100644 --- a/admin/forms.py +++ b/admin/forms.py @@ -39,7 +39,7 @@ class GroupForm(forms.ModelForm): users = forms.ModelMultipleChoiceField( widget=forms.CheckboxSelectMultiple, - queryset=User.objects.all(), + queryset=User.objects.order_by("username"), required=False, ) diff --git a/admin/templates/admin/group_form.html b/admin/templates/admin/group_form.html index fb763810..cb322ed6 100644 --- a/admin/templates/admin/group_form.html +++ b/admin/templates/admin/group_form.html @@ -1,50 +1,89 @@ {% extends "base.html" %} {% load django_bootstrap5 %} {% load i18n %} +{% load static %} {% block title %}{{ title }}{% endblock %} {% block page_heading %}{{ title }}{% endblock page_heading %} +{% block style %} + +{% endblock style %} + {% block content %} -{# as the user form: what the members may do first, then who they are #}
{% csrf_token %} {% bootstrap_form_errors form type="non_fields" %} - {% bootstrap_field form.name %} -

{% trans "What can its members do?" %}

-

{% trans "Each member has these permissions besides their own." %}

-
- {% for box, help in form.permission_rows %} -
- - +
+
+
+

{% trans "Group" %}

+

{% trans "Users who share a set of permissions." %}

+
+
+
{% bootstrap_field form.name %}
- {% endfor %} - {% for error in form.permissions.errors %}
{{ error }}
{% endfor %} -
- -
- {% trans "Members" %} -
- {% for box in form.users %} - - {% endfor %}
- {% for error in form.users.errors %}
{{ error }}
{% endfor %} -
+
-
+
+
+
+

{% trans "Permissions" %}

+

{% trans "Each member has these permissions besides their own." %}

+
+
+
+ {% for box, help in form.permission_rows %} +
+ + +
+ {% endfor %} + {% for error in form.permissions.errors %}
{{ error }}
{% endfor %} +
+
+
+
+ +
+
+
+

{% trans "Members" %}

+

{% trans "Who gets these permissions." %}

+
+
+ {% trans "Members" %} + + {# the members first, then everyone else; each by username #} +
+ {% for box in form.users %}{% if box.data.selected %}{% include "admin/group_member.html" %}{% endif %}{% endfor %} + {% for box in form.users %}{% if not box.data.selected %}{% include "admin/group_member.html" %}{% endif %}{% endfor %} +
+ + {% for error in form.users.errors %}
{{ error }}
{% endfor %} +
+
+
+ +
{% trans "Cancel" %} - +
{% endblock content %} + +{% block script %} + +{% endblock script %} diff --git a/admin/templates/admin/group_member.html b/admin/templates/admin/group_member.html new file mode 100644 index 00000000..a429e639 --- /dev/null +++ b/admin/templates/admin/group_member.html @@ -0,0 +1,7 @@ +{# one user of the group form's Members: box is a checkbox of GroupForm.users #} +{% with user=box.data.value.instance %} + +{% endwith %} diff --git a/admin/tests/test_views.py b/admin/tests/test_views.py index 741a16c0..9100753c 100644 --- a/admin/tests/test_views.py +++ b/admin/tests/test_views.py @@ -53,6 +53,23 @@ class AdminTestCase(TestCase): with self.assertRaises(ObjectDoesNotExist): Group.objects.get(id=group_id) + def test_group_form_lists_its_members_first(self): + for name in ("zed", "bob", "amy"): + User.objects.create_user(name) + User.objects.filter(username="amy").update(first_name="Amy", last_name="Adams") + group = Group.objects.create(name="Ops") + group.user_set.add(User.objects.get(username="zed")) + + page = html.fromstring(self.client.get(reverse("admin:group_update", args=[group.id])).content) + boxes = page.xpath("//div[contains(@class, 'searchable')]/label") + names = [box.text_content().split()[0] for box in boxes] + self.assertEqual(names, ["zed", "admin", "amy", "bob"]) + self.assertIn("Amy Adams", boxes[2].get("data-search")) + self.assertEqual(page.xpath("//input[@id='filter']/@data-forget"), [""]) + self.assertEqual(page.xpath("//form[@id='create-update']//button[@type='submit']/text()"), ["Save changes"]) + page = html.fromstring(self.client.get(reverse("admin:group_create")).content) + self.assertEqual(page.xpath("//form[@id='create-update']//button[@type='submit']/text()"), ["Create group"]) + def test_user_list(self): response = self.client.get(reverse("admin:user_list")) self.assertEqual(response.status_code, 200) diff --git a/locale/tr/LC_MESSAGES/django.mo b/locale/tr/LC_MESSAGES/django.mo index d5d439ca..223579b4 100644 Binary files a/locale/tr/LC_MESSAGES/django.mo and b/locale/tr/LC_MESSAGES/django.mo differ diff --git a/locale/tr/LC_MESSAGES/django.po b/locale/tr/LC_MESSAGES/django.po index f5cac007..9bcfd8d1 100644 --- a/locale/tr/LC_MESSAGES/django.po +++ b/locale/tr/LC_MESSAGES/django.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-11-04 19:19+0000\n" +"POT-Creation-Date: 2026-11-04 19:38+0000\n" "PO-Revision-Date: 2020-11-04 12:00+0000\n" "Last-Translator: catborise , 2020\n" "Language-Team: Turkish (https://www.transifex.com/catborise/teams/110663/tr/)\n" @@ -263,7 +263,7 @@ msgstr "Parola Değiştir" #: accounts/templates/accounts/change_password_form.html:25 #: accounts/templates/accounts/email_otp_form.html:25 -#: admin/templates/admin/group_form.html:46 +#: admin/templates/admin/group_form.html:81 #: admin/templates/admin/user_form.html:169 #: computes/templates/computes/form.html:45 #: console/templates/console-vnc.html:86 @@ -670,7 +670,7 @@ msgstr "Listelerde tüm sanal makineleri ve sunucuları salt okunur görme" msgid "User" msgstr "Kullanıcı" -#: admin/forms.py:80 +#: admin/forms.py:80 admin/templates/admin/group_form.html:39 msgid "Permissions" msgstr "İzinler" @@ -720,55 +720,42 @@ msgstr "Disk" msgid "No limit" msgstr "Sınır yok" -#: admin/forms.py:216 +#: admin/forms.py:218 msgid "Enter a limit or choose No limit." msgstr "Bir sınır girin ya da Sınır yok'u seçin." -#: admin/forms.py:228 +#: admin/forms.py:230 msgid "The user must change it at their next login" msgstr "Kullanıcı bir sonraki girişinde onu değiştirmek zorundadır" -#: admin/forms.py:238 +#: admin/forms.py:240 msgid "A user without a password cannot be made to change it" msgstr "Parolası olmayan bir kullanıcıya parola değiştirme zorunluluğu konamaz" -#: admin/templates/admin/group_form.html:16 -msgid "What can its members do?" -msgstr "Üyeleri neler yapabilir?" +#: admin/templates/admin/group_form.html:27 +msgid "Group" +msgstr "Grup" -#: admin/templates/admin/group_form.html:17 +#: admin/templates/admin/group_form.html:28 +msgid "Users who share a set of permissions." +msgstr "Aynı izinleri paylaşan kullanıcılar." + +#: admin/templates/admin/group_form.html:40 msgid "Each member has these permissions besides their own." msgstr "Her üye kendi izinlerine ek olarak bu izinlere sahiptir." -#: admin/templates/admin/group_form.html:33 +#: admin/templates/admin/group_form.html:63 +#: admin/templates/admin/group_form.html:67 #: interfaces/templates/interface.html:113 #: interfaces/templates/interfaces.html:52 msgid "Members" msgstr "Üyeler" -#: admin/templates/admin/group_form.html:47 -#: computes/templates/computes/form.html:46 -#: instances/templates/instances/edit_instance_volume.html:112 -#: instances/templates/instances/nic_qos_form.html:23 -#: instances/templates/instances/settings_tab.html:412 -#: instances/templates/instances/settings_tab.html:653 -#: instances/templates/instances/settings_tab.html:907 -#: networks/templates/add_network_qos.html:36 -#: networks/templates/network.html:336 networks/templates/network.html:376 -#: networks/templates/network.html:403 networks/templates/network.html:442 -#: nwfilters/templates/nwfilter.html:153 templates/common/form.html:23 -msgid "Save" -msgstr "Kaydet" - -#: admin/templates/admin/group_list.html:12 -msgid "New group" -msgstr "Yeni grup" - -#: admin/templates/admin/group_list.html:19 -#: admin/templates/admin/user_form.html:141 -msgid "There are no groups yet." -msgstr "Henüz grup yok." +#: admin/templates/admin/group_form.html:64 +msgid "Who gets these permissions." +msgstr "Bu izinleri kimlerin alacağı." +#: admin/templates/admin/group_form.html:68 #: admin/templates/admin/group_list.html:25 admin/templates/admin/logs.html:20 #: admin/templates/admin/logs.html:26 #: admin/templates/admin/tombstone_list.html:20 @@ -779,6 +766,34 @@ msgstr "Henüz grup yok." msgid "Search" msgstr "Ara" +#: admin/templates/admin/group_form.html:68 +#: admin/templates/admin/user_list.html:20 +msgid "Search users" +msgstr "Kullanıcı ara" + +#: admin/templates/admin/group_form.html:74 +#: admin/templates/admin/user_list.html:86 +msgid "No user matches the search." +msgstr "Aramayla eşleşen kullanıcı yok." + +#: admin/templates/admin/group_form.html:82 +#: admin/templates/admin/user_form.html:170 +msgid "Save changes" +msgstr "Değişiklikleri kaydet" + +#: admin/templates/admin/group_form.html:82 +msgid "Create group" +msgstr "Grup oluştur" + +#: admin/templates/admin/group_list.html:12 +msgid "New group" +msgstr "Yeni grup" + +#: admin/templates/admin/group_list.html:19 +#: admin/templates/admin/user_form.html:141 +msgid "There are no groups yet." +msgstr "Henüz grup yok." + #: admin/templates/admin/group_list.html:25 msgid "Search groups" msgstr "Grup ara" @@ -1010,10 +1025,6 @@ msgstr "" "Kapalı olması burada hiçbir şey vermez; bir grubun verdiği hiçbir şeyi de " "geri almaz." -#: admin/templates/admin/user_form.html:170 -msgid "Save changes" -msgstr "Değişiklikleri kaydet" - #: admin/templates/admin/user_form.html:170 msgid "Create user" msgstr "Kullanıcı oluştur" @@ -1027,10 +1038,6 @@ msgstr "Yeni kullanıcı" msgid "Users" msgstr "Kullanıcılar" -#: admin/templates/admin/user_list.html:20 -msgid "Search users" -msgstr "Kullanıcı ara" - #: admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:37 instances/states.py:11 #: instances/templates/instances/power_tab.html:19 @@ -1068,10 +1075,6 @@ msgstr "Engelle" msgid "Unblock" msgstr "Engeli Kaldır" -#: admin/templates/admin/user_list.html:86 -msgid "No user matches the search." -msgstr "Aramayla eşleşen kullanıcı yok." - #: admin/views.py:57 msgid "Create Group" msgstr "Grup Oluştur" @@ -1983,6 +1986,19 @@ msgstr "kayıtlı" msgid "none" msgstr "hiçbiri" +#: computes/templates/computes/form.html:46 +#: instances/templates/instances/edit_instance_volume.html:112 +#: instances/templates/instances/nic_qos_form.html:23 +#: instances/templates/instances/settings_tab.html:412 +#: instances/templates/instances/settings_tab.html:653 +#: instances/templates/instances/settings_tab.html:907 +#: networks/templates/add_network_qos.html:36 +#: networks/templates/network.html:336 networks/templates/network.html:376 +#: networks/templates/network.html:403 networks/templates/network.html:442 +#: nwfilters/templates/nwfilter.html:153 templates/common/form.html:23 +msgid "Save" +msgstr "Kaydet" + #: computes/templates/computes/host_nav.html:4 msgid "Host sections" msgstr "Sunucu bölümleri" diff --git a/locale/zh/LC_MESSAGES/django.mo b/locale/zh/LC_MESSAGES/django.mo index ae508539..32dc5f17 100644 Binary files a/locale/zh/LC_MESSAGES/django.mo and b/locale/zh/LC_MESSAGES/django.mo differ diff --git a/locale/zh/LC_MESSAGES/django.po b/locale/zh/LC_MESSAGES/django.po index e3ff8f94..4d1523f2 100644 --- a/locale/zh/LC_MESSAGES/django.po +++ b/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-11-04 19:19+0000\n" +"POT-Creation-Date: 2026-11-04 19:38+0000\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -260,7 +260,7 @@ msgstr "修改密码" #: accounts/templates/accounts/change_password_form.html:25 #: accounts/templates/accounts/email_otp_form.html:25 -#: admin/templates/admin/group_form.html:46 +#: admin/templates/admin/group_form.html:81 #: admin/templates/admin/user_form.html:169 #: computes/templates/computes/form.html:45 #: console/templates/console-vnc.html:86 @@ -653,7 +653,7 @@ msgstr "在列表中查看所有虚拟机和主机(只读)" msgid "User" msgstr "用户" -#: admin/forms.py:80 +#: admin/forms.py:80 admin/templates/admin/group_form.html:39 msgid "Permissions" msgstr "权限" @@ -702,55 +702,42 @@ msgstr "磁盘" msgid "No limit" msgstr "不限" -#: admin/forms.py:216 +#: admin/forms.py:218 msgid "Enter a limit or choose No limit." msgstr "请输入限制值,或选择“不限”。" -#: admin/forms.py:228 +#: admin/forms.py:230 msgid "The user must change it at their next login" msgstr "用户必须在下次登录时修改密码" -#: admin/forms.py:238 +#: admin/forms.py:240 msgid "A user without a password cannot be made to change it" msgstr "没有密码的用户无法被要求修改密码" -#: admin/templates/admin/group_form.html:16 -msgid "What can its members do?" -msgstr "其成员可以做什么?" +#: admin/templates/admin/group_form.html:27 +msgid "Group" +msgstr "用户组" -#: admin/templates/admin/group_form.html:17 +#: admin/templates/admin/group_form.html:28 +msgid "Users who share a set of permissions." +msgstr "共享同一组权限的用户。" + +#: admin/templates/admin/group_form.html:40 msgid "Each member has these permissions besides their own." msgstr "每个成员除自身权限外还拥有这些权限。" -#: admin/templates/admin/group_form.html:33 +#: admin/templates/admin/group_form.html:63 +#: admin/templates/admin/group_form.html:67 #: interfaces/templates/interface.html:113 #: interfaces/templates/interfaces.html:52 msgid "Members" msgstr "成员" -#: admin/templates/admin/group_form.html:47 -#: computes/templates/computes/form.html:46 -#: instances/templates/instances/edit_instance_volume.html:112 -#: instances/templates/instances/nic_qos_form.html:23 -#: instances/templates/instances/settings_tab.html:412 -#: instances/templates/instances/settings_tab.html:653 -#: instances/templates/instances/settings_tab.html:907 -#: networks/templates/add_network_qos.html:36 -#: networks/templates/network.html:336 networks/templates/network.html:376 -#: networks/templates/network.html:403 networks/templates/network.html:442 -#: nwfilters/templates/nwfilter.html:153 templates/common/form.html:23 -msgid "Save" -msgstr "保存" - -#: admin/templates/admin/group_list.html:12 -msgid "New group" -msgstr "新建用户组" - -#: admin/templates/admin/group_list.html:19 -#: admin/templates/admin/user_form.html:141 -msgid "There are no groups yet." -msgstr "还没有用户组。" +#: admin/templates/admin/group_form.html:64 +msgid "Who gets these permissions." +msgstr "获得这些权限的用户。" +#: admin/templates/admin/group_form.html:68 #: admin/templates/admin/group_list.html:25 admin/templates/admin/logs.html:20 #: admin/templates/admin/logs.html:26 #: admin/templates/admin/tombstone_list.html:20 @@ -761,6 +748,34 @@ msgstr "还没有用户组。" msgid "Search" msgstr "搜索" +#: admin/templates/admin/group_form.html:68 +#: admin/templates/admin/user_list.html:20 +msgid "Search users" +msgstr "搜索用户" + +#: admin/templates/admin/group_form.html:74 +#: admin/templates/admin/user_list.html:86 +msgid "No user matches the search." +msgstr "没有与搜索匹配的用户。" + +#: admin/templates/admin/group_form.html:82 +#: admin/templates/admin/user_form.html:170 +msgid "Save changes" +msgstr "保存更改" + +#: admin/templates/admin/group_form.html:82 +msgid "Create group" +msgstr "创建用户组" + +#: admin/templates/admin/group_list.html:12 +msgid "New group" +msgstr "新建用户组" + +#: admin/templates/admin/group_list.html:19 +#: admin/templates/admin/user_form.html:141 +msgid "There are no groups yet." +msgstr "还没有用户组。" + #: admin/templates/admin/group_list.html:25 msgid "Search groups" msgstr "搜索用户组" @@ -984,10 +999,6 @@ msgstr "自身权限" msgid "Off grants nothing here; it takes away nothing a group grants." msgstr "关闭不会在此授予任何权限,也不会撤销用户组授予的权限。" -#: admin/templates/admin/user_form.html:170 -msgid "Save changes" -msgstr "保存更改" - #: admin/templates/admin/user_form.html:170 msgid "Create user" msgstr "创建用户" @@ -1001,10 +1012,6 @@ msgstr "新建用户" msgid "Users" msgstr "用户" -#: admin/templates/admin/user_list.html:20 -msgid "Search users" -msgstr "搜索用户" - #: admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:37 instances/states.py:11 #: instances/templates/instances/power_tab.html:19 @@ -1041,10 +1048,6 @@ msgstr "禁用" msgid "Unblock" msgstr "解除禁用" -#: admin/templates/admin/user_list.html:86 -msgid "No user matches the search." -msgstr "没有与搜索匹配的用户。" - #: admin/views.py:57 msgid "Create Group" msgstr "创建用户组" @@ -1914,6 +1917,19 @@ msgstr "已保存" msgid "none" msgstr "无" +#: computes/templates/computes/form.html:46 +#: instances/templates/instances/edit_instance_volume.html:112 +#: instances/templates/instances/nic_qos_form.html:23 +#: instances/templates/instances/settings_tab.html:412 +#: instances/templates/instances/settings_tab.html:653 +#: instances/templates/instances/settings_tab.html:907 +#: networks/templates/add_network_qos.html:36 +#: networks/templates/network.html:336 networks/templates/network.html:376 +#: networks/templates/network.html:403 networks/templates/network.html:442 +#: nwfilters/templates/nwfilter.html:153 templates/common/form.html:23 +msgid "Save" +msgstr "保存" + #: computes/templates/computes/host_nav.html:4 msgid "Host sections" msgstr "主机栏目" diff --git a/static/js/table_filter.js b/static/js/table_filter.js index cfba1717..f839a170 100644 --- a/static/js/table_filter.js +++ b/static/js/table_filter.js @@ -7,7 +7,7 @@ // be the chosen state too. In a grouped list a search for a group's host // shows all of its rows, and its header row (data-group-header) shows while // any of its rows does. A page's #no-match shows while no row does. The -// search is remembered for a day, per page. +// search is remembered for a day, per page, unless its box has data-forget. // // The instance list's state pills (#state-pills) set the state; each one's // [data-count-state] counts the VMs of its state the search finds (its @@ -68,9 +68,13 @@ if (typeof module !== "undefined") { } else { var search = document.getElementById("filter"); var states = document.getElementById("state-filter"); - search.value = Cookies.get(document.title + "_filter") || ""; + // a form's search ([data-forget], the group form's members) starts empty + var remember = !search.hasAttribute("data-forget"); + search.value = remember && Cookies.get(document.title + "_filter") || ""; search.addEventListener("input", function () { - Cookies.set(document.title + "_filter", search.value, {expires: 1}); + if (remember) { + Cookies.set(document.title + "_filter", search.value, {expires: 1}); + } filterTable(document); }); if (states) {