From 2b8c2b23466eea7f25e59621ade13076247e17bd Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sun, 10 Mar 2019 18:06:06 +0100 Subject: [PATCH] use Django's Admin FilteredSelectMultiple for Group Membership --- passbook/admin/templates/generic/form.html | 10 + passbook/core/forms/groups.py | 6 +- ...308_1417.py => 0019_auto_20190310_1615.py} | 4 +- passbook/core/static/css/passbook.css | 174 ++++++++++++++++++ 4 files changed, 190 insertions(+), 4 deletions(-) rename passbook/core/migrations/{0017_auto_20190308_1417.py => 0019_auto_20190310_1615.py} (83%) diff --git a/passbook/admin/templates/generic/form.html b/passbook/admin/templates/generic/form.html index 88bbec856..13cd7d8df 100644 --- a/passbook/admin/templates/generic/form.html +++ b/passbook/admin/templates/generic/form.html @@ -2,10 +2,20 @@ {% load i18n %} {% load utils %} +{% load static %} {% block head %} {{ block.super }} {{ form.media.css }} + + + + + + + + + {% endblock %} {% block content %} diff --git a/passbook/core/forms/groups.py b/passbook/core/forms/groups.py index 76b10b667..4f2052623 100644 --- a/passbook/core/forms/groups.py +++ b/passbook/core/forms/groups.py @@ -2,12 +2,14 @@ from django import forms from passbook.core.models import Group, User +from django.contrib.admin.widgets import FilteredSelectMultiple class GroupForm(forms.ModelForm): """Group Form""" - members = forms.ModelMultipleChoiceField(User.objects.all(), required=False) + members = forms.ModelMultipleChoiceField( + User.objects.all(), required=False, widget=FilteredSelectMultiple('users', False)) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -18,7 +20,7 @@ class GroupForm(forms.ModelForm): instance = super().save(*args, **kwargs) if instance.pk: instance.user_set.clear() - instance.user_set.add(*self.cleaned_data['users']) + instance.user_set.add(*self.cleaned_data['members']) return instance class Meta: diff --git a/passbook/core/migrations/0017_auto_20190308_1417.py b/passbook/core/migrations/0019_auto_20190310_1615.py similarity index 83% rename from passbook/core/migrations/0017_auto_20190308_1417.py rename to passbook/core/migrations/0019_auto_20190310_1615.py index d32d6fa48..8b59ed40e 100644 --- a/passbook/core/migrations/0017_auto_20190308_1417.py +++ b/passbook/core/migrations/0019_auto_20190310_1615.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.7 on 2019-03-08 14:17 +# Generated by Django 2.1.7 on 2019-03-10 16:15 import django.contrib.postgres.fields.hstore from django.contrib.postgres.operations import HStoreExtension @@ -8,7 +8,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('passbook_core', '0016_auto_20190227_1355'), + ('passbook_core', '0018_provider_property_mappings'), ] operations = [ diff --git a/passbook/core/static/css/passbook.css b/passbook/core/static/css/passbook.css index 86711d8b1..ca643f80d 100644 --- a/passbook/core/static/css/passbook.css +++ b/passbook/core/static/css/passbook.css @@ -21,3 +21,177 @@ .dynamic-array-widget .remove:hover { cursor: pointer; } + +/* Selector */ + +.selector { + display: flex; + width: 100%; + height: 45vh; +} + +.selector .selector-filter { + display: flex; + align-items: center; +} + +.selector .selector-filter label { + margin: 0 8px 0 0; +} + +.selector .selector-filter input { + width: auto; + min-height: 0; + flex: 1 1; +} + +.selector-available, .selector-chosen { + width: auto; + flex: 1 1; + display: flex; + flex-direction: column; +} + +.selector select { + width: 100%; + flex: 1 0 auto; + margin-bottom: 5px; +} + +.selector ul.selector-chooser { + width: 26px; + height: 52px; + padding: 2px 0; + margin: auto 15px; + border-radius: 20px; + transform: translateY(-10px); + list-style: none; +} + +.selector-add, .selector-remove { + width: 20px; + height: 20px; + background-size: 20px auto; +} + +.selector-add { + background-position: 0 -120px; +} + +.selector-remove { + background-position: 0 -80px; +} + +a.selector-chooseall, a.selector-clearall { + align-self: center; +} + +.stacked { + flex-direction: column; + max-width: 480px; +} + +.stacked > * { + flex: 0 1 auto; +} + +.stacked select { + margin-bottom: 0; +} + +.stacked .selector-available, .stacked .selector-chosen { + width: auto; +} + +.stacked ul.selector-chooser { + width: 52px; + height: 26px; + padding: 0 2px; + margin: 15px auto; + transform: none; +} + +.stacked .selector-chooser li { + padding: 3px; +} + +.stacked .selector-add, .stacked .selector-remove { + background-size: 20px auto; +} + +.stacked .selector-add { + background-position: 0 -40px; +} + +.stacked .active.selector-add { + background-position: 0 -60px; +} + +.stacked .selector-remove { + background-position: 0 0; +} + +.stacked .active.selector-remove { + background-position: 0 -20px; +} + +.help-tooltip, .selector .help-icon { + display: none; +} + +form .form-row p.datetime { + width: 100%; +} + +.datetime input { + width: 50%; + max-width: 120px; +} + +.datetime span { + font-size: 13px; +} + +.datetime .timezonewarning { + display: block; + font-size: 11px; + color: #999; +} + +.datetimeshortcuts { + color: #ccc; +} + +.inline-group { + overflow: auto; +} + +.selector-add, .selector-remove { + width: 16px; + height: 16px; + display: block; + text-indent: -3000px; + overflow: hidden; + cursor: default; + opacity: 0.3; +} + +.active.selector-add, .active.selector-remove { + opacity: 1; +} + +.active.selector-add:hover, .active.selector-remove:hover { + cursor: pointer; +} + +.selector-add { + background: url(../admin/img/selector-icons.svg) 0 -96px no-repeat; +} + +.active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -112px; +} + +.selector-remove { + background: url(../admin/img/selector-icons.svg) 0 -64px no-repeat; +}