Skip to content
This repository has been archived by the owner on Oct 1, 2020. It is now read-only.

Commit

Permalink
tidy up frontend
Browse files Browse the repository at this point in the history
 - remove dropdown for group members - it was broken for large numbers
   of people. nicer interface now
 - remove caching on frontend - it was displaying stale data. has been
   replaced with fetching small amounts of data before ramping up so we
   still have quick page loads
 - nicer error messages when an ajax call fails
 - add proptypes to react components
 - update js deps
 - tweak front end build
  • Loading branch information
monty5811 committed Sep 13, 2016
1 parent bb7c52e commit 31fd2df
Show file tree
Hide file tree
Showing 64 changed files with 1,622 additions and 1,361 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file.

## [Unreleased]
### Changed
- Nicer interface for managing groups (especially large ones)
- Remove frontend data caching
- Improve error messages when ajax call fails

## [v1.12.1]
- Pin Django version
Expand Down
75 changes: 56 additions & 19 deletions api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ast

from django.contrib.auth.models import User
from django.contrib.humanize.templatetags.humanize import naturaltime
from rest_framework import serializers
from django_q.models import Schedule

Expand All @@ -10,25 +11,6 @@
from elvanto.models import ElvantoGroup


class RecipientGroupSerializer(serializers.ModelSerializer):
"""Serialize apostello.models.RecipientGroup for use in table."""
cost = serializers.CharField(source='calculate_cost')
url = serializers.CharField(source='get_absolute_url')
members = serializers.ListField(source='all_recipients_names')

class Meta:
model = RecipientGroup
fields = (
'name',
'pk',
'description',
'members',
'cost',
'url',
'is_archived',
)


class ElvantoGroupSerializer(serializers.ModelSerializer):
"""Serialize apostello.models.ElvantoGroup."""
last_synced = serializers.DateTimeField(format='%d %b %H:%M')
Expand Down Expand Up @@ -149,6 +131,54 @@ class Meta:
)


class RecipientSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Recipient
fields = (
'full_name',
'pk',
)


class RecipientGroupSerializer(serializers.ModelSerializer):
"""Serialize apostello.models.RecipientGroup for use in table."""
cost = serializers.CharField(source='calculate_cost')
url = serializers.CharField(source='get_absolute_url')

class Meta:
model = RecipientGroup
fields = (
'name',
'pk',
'description',
'cost',
'url',
'is_archived',
)


class RecipientGroupSerializerMember(serializers.ModelSerializer):
"""Serialize apostello.models.RecipientGroup for use in edit page."""
cost = serializers.CharField(source='calculate_cost')
url = serializers.CharField(source='get_absolute_url')
members = RecipientSimpleSerializer(many=True, read_only=True, source='recipient_set')
nonmembers = RecipientSimpleSerializer(many=True, read_only=True, source='all_recipients_not_in_group')

class Meta:
model = RecipientGroup
fields = (
'name',
'pk',
'description',
'members',
'nonmembers',
'cost',
'url',
'is_archived',
)



class UserSerializer(serializers.ModelSerializer):
"""Serialize user model."""

Expand Down Expand Up @@ -189,6 +219,7 @@ class QScheduleSerializer(serializers.ModelSerializer):
"""

next_run = serializers.DateTimeField()
next_run_formatted = serializers.SerializerMethodField()
message_body = serializers.SerializerMethodField()
recipient = serializers.SerializerMethodField()
recipient_group = serializers.SerializerMethodField()
Expand Down Expand Up @@ -235,6 +266,11 @@ def get_queued_by(self, obj):
return None
return self._split_args(obj.args)[3]

def get_next_run_formatted(self, obj):
"""Next run time in humand friendly format."""
return naturaltime(obj.next_run)


class Meta:
model = Schedule
fields = (
Expand All @@ -244,4 +280,5 @@ class Meta:
'recipient_group',
'queued_by',
'next_run',
'next_run_formatted',
)
2 changes: 1 addition & 1 deletion api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
r'^v1/groups/(?P<pk>[0-9]+)$',
v.ApiMember.as_view(
model_class=RecipientGroup,
serializer_class=s.RecipientGroupSerializer,
serializer_class=s.RecipientGroupSerializerMember,
permission_classes=(IsAuthenticated, CanSeeGroups)
),
name='group'
Expand Down
13 changes: 12 additions & 1 deletion api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

class StandardPagination(PageNumberPagination):
"""Base class for common pagination."""
page_size = 100
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 1000

Expand Down Expand Up @@ -167,6 +167,17 @@ def post(self, request, format=None, **kwargs):
setattr(obj, x, user_profile[x])
obj.save()

is_member = request.data.get('member')
if is_member is not None:
is_member = True if is_member == 'true' else False
contact = Recipient.objects.get(pk=request.data.get('contactPk'))
if is_member:
obj.recipient_set.remove(contact)
else:
obj.recipient_set.add(contact)

obj.save()

cancel_task = request.data.get('cancel_task')
if cancel_task is not None:
r = Response({'pk': obj.pk}, status=status.HTTP_200_OK)
Expand Down
31 changes: 0 additions & 31 deletions apostello/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,37 +119,6 @@ class Meta:
model = RecipientGroup
exclude = ['is_archived']

# Representing the many to many related field in SmsGroup
members = forms.ModelMultipleChoiceField(
queryset=Recipient.objects.filter(is_archived=False),
required=False,
widget=forms.SelectMultiple(
attrs={
"class": "ui fluid search dropdown",
"multiple": "",
"id": "members_dropdown",
}
),
)

def __init__(self, *args, **kwargs):
"""Override init method to pull in existing group members."""
if 'instance' in kwargs:
initial = kwargs.setdefault('initial', {})
# The widget for a ModelMultipleChoiceField expects a list of primary key for the selected data.
initial['members'] = [
t.pk for t in kwargs['instance'].recipient_set.all()
]

forms.ModelForm.__init__(self, *args, **kwargs)

def save(self, *args, **kwargs):
"""Override save method to update group members."""
instance = forms.ModelForm.save(self)
instance.recipient_set.clear()
for recipient in self.cleaned_data['members']:
instance.recipient_set.add(recipient)


class RecipientForm(forms.ModelForm):
"""Handle Recipients."""
Expand Down
5 changes: 5 additions & 0 deletions apostello/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def all_recipients(self):
"""Returns queryset of all recipients in group."""
return self.recipient_set.all()

@cached_property
def all_recipients_not_in_group(self):
"""Returns queryset of all recipients not in group."""
return Recipient.objects.filter(is_archived=False).exclude(groups__pk=self.pk).all()

@property
def all_recipients_names(self):
"""List of the names of recipients."""
Expand Down
2 changes: 1 addition & 1 deletion apostello/static/css/apostello.min.css

Large diffs are not rendered by default.

0 comments on commit 31fd2df

Please sign in to comment.