From 162f117cef019771ef6393146a0c63110e337d7f Mon Sep 17 00:00:00 2001 From: Christopher Charbonneau Wells Date: Tue, 7 Nov 2017 13:15:48 -0500 Subject: [PATCH] Move timeline code to core and integrate with Child detail view. --- core/static_src/scss/core.scss | 9 ++ .../static_src/scss/timeline.scss | 2 +- core/templates/core/child_detail.html | 56 +++++++-- {reports/graphs => core}/timeline.py | 4 +- core/views.py | 109 ++++++++++-------- .../dashboard/child_button_group.html | 1 - reports/graphs/__init__.py | 1 - reports/templates/reports/timeline.html | 42 ------- reports/tests/tests_views.py | 3 - reports/urls.py | 4 - reports/views.py | 22 +--- 11 files changed, 121 insertions(+), 132 deletions(-) rename {reports => core}/static_src/scss/timeline.scss (99%) rename {reports/graphs => core}/timeline.py (96%) delete mode 100644 reports/templates/reports/timeline.html diff --git a/core/static_src/scss/core.scss b/core/static_src/scss/core.scss index 1c6a0a6e..d6b2e132 100644 --- a/core/static_src/scss/core.scss +++ b/core/static_src/scss/core.scss @@ -3,3 +3,12 @@ max-width: 150px; } } + +@include media-breakpoint-up(md) { + #view-child { + .child-detail-column { + position: fixed; + width: 100%; + } + } +} diff --git a/reports/static_src/scss/timeline.scss b/core/static_src/scss/timeline.scss similarity index 99% rename from reports/static_src/scss/timeline.scss rename to core/static_src/scss/timeline.scss index feac627e..65ea501b 100644 --- a/reports/static_src/scss/timeline.scss +++ b/core/static_src/scss/timeline.scss @@ -118,7 +118,7 @@ $card-shadow: rgba(0, 0, 0, .175); } } -@media (max-width: 767px) { +@include media-breakpoint-down(md) { .timeline { &::before { left: 40px; diff --git a/core/templates/core/child_detail.html b/core/templates/core/child_detail.html index 7cfa5f67..ef9aa657 100644 --- a/core/templates/core/child_detail.html +++ b/core/templates/core/child_detail.html @@ -9,13 +9,53 @@ {% endblock %} {% block content %} -
- -
{{ object }}
-

- Born {{ object.birth_date }}
- Age {{ object.birth_date|timesince }} -

- {% include 'dashboard/child_button_group.html' %} +
+
+
+ +
{{ object }}
+

+ Born {{ object.birth_date }}
+ Age {{ object.birth_date|timesince }} +

+ {% include 'dashboard/child_button_group.html' %} +
+
+
+
+
+

+ {% if date_previous %} + + + Previous + + {% endif %} + {{ date|date }} + {% if date_next %} + + + Next + + {% endif %} +

+
    + {% for object in timeline_objects %} + +
    + +
    +
    +
    + {{ object.event }} +
    + +
    + + {% endfor %} +
+
{% endblock %} \ No newline at end of file diff --git a/reports/graphs/timeline.py b/core/timeline.py similarity index 96% rename from reports/graphs/timeline.py rename to core/timeline.py index ec18c3c0..68dbf543 100644 --- a/reports/graphs/timeline.py +++ b/core/timeline.py @@ -6,9 +6,9 @@ from django.utils import timezone from core.models import DiaperChange, Feeding, Sleep, TummyTime -def timeline(child, date): +def get_objects(child, date): """ - Create a time-sorted dictionary for all events for a child. + Create a time-sorted dictionary of all events for a child. :param child: an instance of a Child. :param date: a DateTime instance for the day to be summarized. :returns: a list of the day's events. diff --git a/core/views.py b/core/views.py index 0ae00811..afb7522f 100644 --- a/core/views.py +++ b/core/views.py @@ -3,19 +3,18 @@ from __future__ import unicode_literals from django.contrib.auth.mixins import PermissionRequiredMixin from django.urls import reverse +from django.utils import timezone from django.views.generic.base import RedirectView from django.views.generic.detail import DetailView from django.views.generic.edit import CreateView, UpdateView, DeleteView from django_filters.views import FilterView -from .models import Child, DiaperChange, Feeding, Note, Sleep, Timer, TummyTime -from .forms import (ChildForm, ChildDeleteForm, DiaperChangeForm, FeedingForm, - SleepForm, TimerForm, TummyTimeForm) +from core import forms, models, timeline class ChildList(PermissionRequiredMixin, FilterView): - model = Child + model = models.Child template_name = 'core/child_list.html' permission_required = ('core.view_child',) paginate_by = 10 @@ -23,34 +22,46 @@ class ChildList(PermissionRequiredMixin, FilterView): class ChildAdd(PermissionRequiredMixin, CreateView): - model = Child + model = models.Child permission_required = ('core.add_child',) - form_class = ChildForm + form_class = forms.ChildForm success_url = '/children' class ChildDetail(PermissionRequiredMixin, DetailView): - model = Child + model = models.Child permission_required = ('core.view_child',) + def get_context_data(self, **kwargs): + context = super(ChildDetail, self).get_context_data(**kwargs) + date = self.request.GET.get('date', str(timezone.localdate())) + date = timezone.datetime.strptime(date, '%Y-%m-%d') + date = timezone.localtime(timezone.make_aware(date)) + context['timeline_objects'] = timeline.get_objects(self.object, date) + context['date'] = date + context['date_previous'] = date - timezone.timedelta(days=1) + if date.date() < timezone.localdate(): + context['date_next'] = date + timezone.timedelta(days=1) + return context + class ChildUpdate(PermissionRequiredMixin, UpdateView): - model = Child + model = models.Child permission_required = ('core.change_child',) - form_class = ChildForm + form_class = forms.ChildForm success_url = '/children' class ChildDelete(PermissionRequiredMixin, UpdateView): - model = Child - form_class = ChildDeleteForm + model = models.Child + form_class = forms.ChildDeleteForm template_name = 'core/child_confirm_delete.html' permission_required = ('core.delete_child',) success_url = '/children' class DiaperChangeList(PermissionRequiredMixin, FilterView): - model = DiaperChange + model = models.DiaperChange template_name = 'core/diaperchange_list.html' permission_required = ('core.view_diaperchange',) paginate_by = 10 @@ -58,27 +69,27 @@ class DiaperChangeList(PermissionRequiredMixin, FilterView): class DiaperChangeAdd(PermissionRequiredMixin, CreateView): - model = DiaperChange + model = models.DiaperChange permission_required = ('core.add_diaperchange',) - form_class = DiaperChangeForm + form_class = forms.DiaperChangeForm success_url = '/changes' class DiaperChangeUpdate(PermissionRequiredMixin, UpdateView): - model = DiaperChange + model = models.DiaperChange permission_required = ('core.change_diaperchange',) - form_class = DiaperChangeForm + form_class = forms.DiaperChangeForm success_url = '/changes' class DiaperChangeDelete(PermissionRequiredMixin, DeleteView): - model = DiaperChange + model = models.DiaperChange permission_required = ('core.delete_diaperchange',) success_url = '/changes' class FeedingList(PermissionRequiredMixin, FilterView): - model = Feeding + model = models.Feeding template_name = 'core/feeding_list.html' permission_required = ('core.view_feeding',) paginate_by = 10 @@ -86,9 +97,9 @@ class FeedingList(PermissionRequiredMixin, FilterView): class FeedingAdd(PermissionRequiredMixin, CreateView): - model = Feeding + model = models.Feeding permission_required = ('core.add_feeding',) - form_class = FeedingForm + form_class = forms.FeedingForm success_url = '/feedings' def get_form_kwargs(self): @@ -99,20 +110,20 @@ class FeedingAdd(PermissionRequiredMixin, CreateView): class FeedingUpdate(PermissionRequiredMixin, UpdateView): - model = Feeding + model = models.Feeding permission_required = ('core.change_feeding',) - form_class = FeedingForm + form_class = forms.FeedingForm success_url = '/feedings' class FeedingDelete(PermissionRequiredMixin, DeleteView): - model = Feeding + model = models.Feeding permission_required = ('core.delete_feeding',) success_url = '/feedings' class NoteList(PermissionRequiredMixin, FilterView): - model = Note + model = models.Note template_name = 'core/note_list.html' permission_required = ('core.view_note',) paginate_by = 10 @@ -120,27 +131,27 @@ class NoteList(PermissionRequiredMixin, FilterView): class NoteAdd(PermissionRequiredMixin, CreateView): - model = Note + model = models.Note permission_required = ('core.add_note',) fields = ['child', 'note'] success_url = '/notes' class NoteUpdate(PermissionRequiredMixin, UpdateView): - model = Note + model = models.Note permission_required = ('core.change_note',) fields = ['child', 'note'] success_url = '/notes' class NoteDelete(PermissionRequiredMixin, DeleteView): - model = Note + model = models.Note permission_required = ('core.delete_note',) success_url = '/notes' class SleepList(PermissionRequiredMixin, FilterView): - model = Sleep + model = models.Sleep template_name = 'core/sleep_list.html' permission_required = ('core.view_sleep',) paginate_by = 10 @@ -148,9 +159,9 @@ class SleepList(PermissionRequiredMixin, FilterView): class SleepAdd(PermissionRequiredMixin, CreateView): - model = Sleep + model = models.Sleep permission_required = ('core.add_sleep',) - form_class = SleepForm + form_class = forms.SleepForm success_url = '/sleep' def get_form_kwargs(self): @@ -161,20 +172,20 @@ class SleepAdd(PermissionRequiredMixin, CreateView): class SleepUpdate(PermissionRequiredMixin, UpdateView): - model = Sleep + model = models.Sleep permission_required = ('core.change_sleep',) - form_class = SleepForm + form_class = forms.SleepForm success_url = '/sleep' class SleepDelete(PermissionRequiredMixin, DeleteView): - model = Sleep + model = models.Sleep permission_required = ('core.delete_sleep',) success_url = '/sleep' class TimerList(PermissionRequiredMixin, FilterView): - model = Timer + model = models.Timer template_name = 'core/timer_list.html' permission_required = ('core.view_timer',) paginate_by = 10 @@ -182,14 +193,14 @@ class TimerList(PermissionRequiredMixin, FilterView): class TimerDetail(PermissionRequiredMixin, DetailView): - model = Timer + model = models.Timer permission_required = ('core.view_timer',) class TimerAdd(PermissionRequiredMixin, CreateView): - model = Timer + model = models.Timer permission_required = ('core.add_timer',) - form_class = TimerForm + form_class = forms.TimerForm success_url = '/timers' def get_form_kwargs(self): @@ -199,9 +210,9 @@ class TimerAdd(PermissionRequiredMixin, CreateView): class TimerUpdate(PermissionRequiredMixin, UpdateView): - model = Timer + model = models.Timer permission_required = ('core.change_timer',) - form_class = TimerForm + form_class = forms.TimerForm success_url = '/timers' def get_form_kwargs(self): @@ -218,7 +229,7 @@ class TimerAddQuick(PermissionRequiredMixin, RedirectView): permission_required = ('core.add_timer',) def get(self, request, *args, **kwargs): - instance = Timer.objects.create(user=request.user) + instance = models.Timer.objects.create(user=request.user) instance.save() self.url = request.GET.get( 'next', reverse('timer-detail', args={instance.id})) @@ -229,7 +240,7 @@ class TimerRestart(PermissionRequiredMixin, RedirectView): permission_required = ('core.change_timer',) def get(self, request, *args, **kwargs): - instance = Timer.objects.get(id=kwargs['pk']) + instance = models.Timer.objects.get(id=kwargs['pk']) instance.restart() return super(TimerRestart, self).get(request, *args, **kwargs) @@ -241,7 +252,7 @@ class TimerStop(PermissionRequiredMixin, RedirectView): permission_required = ('core.change_timer',) def get(self, request, *args, **kwargs): - instance = Timer.objects.get(id=kwargs['pk']) + instance = models.Timer.objects.get(id=kwargs['pk']) instance.stop() return super(TimerStop, self).get(request, *args, **kwargs) @@ -250,13 +261,13 @@ class TimerStop(PermissionRequiredMixin, RedirectView): class TimerDelete(PermissionRequiredMixin, DeleteView): - model = Timer + model = models.Timer permission_required = ('core.delete_timer',) success_url = '/' class TummyTimeList(PermissionRequiredMixin, FilterView): - model = TummyTime + model = models.TummyTime template_name = 'core/tummytime_list.html' permission_required = ('core.view_tummytime',) paginate_by = 10 @@ -264,9 +275,9 @@ class TummyTimeList(PermissionRequiredMixin, FilterView): class TummyTimeAdd(PermissionRequiredMixin, CreateView): - model = TummyTime + model = models.TummyTime permission_required = ('core.add_tummytime',) - form_class = TummyTimeForm + form_class = forms.TummyTimeForm success_url = '/tummy-time' def get_form_kwargs(self): @@ -277,13 +288,13 @@ class TummyTimeAdd(PermissionRequiredMixin, CreateView): class TummyTimeUpdate(PermissionRequiredMixin, UpdateView): - model = TummyTime + model = models.TummyTime permission_required = ('core.change_tummytime',) - form_class = TummyTimeForm + form_class = forms.TummyTimeForm success_url = '/tummy-time' class TummyTimeDelete(PermissionRequiredMixin, DeleteView): - model = TummyTime + model = models.TummyTime permission_required = ('core.delete_tummytime',) success_url = '/tummy-time' diff --git a/dashboard/templates/dashboard/child_button_group.html b/dashboard/templates/dashboard/child_button_group.html index 8bf1815f..2e3ee7f4 100644 --- a/dashboard/templates/dashboard/child_button_group.html +++ b/dashboard/templates/dashboard/child_button_group.html @@ -18,7 +18,6 @@ Diaper Lifetimes Sleep Pattern Sleep Totals - Timeline
diff --git a/reports/graphs/__init__.py b/reports/graphs/__init__.py index 01191f82..0957cd42 100644 --- a/reports/graphs/__init__.py +++ b/reports/graphs/__init__.py @@ -2,4 +2,3 @@ from .diaperchange_lifetimes import diaperchange_lifetimes # NOQA from .diaperchange_types import diaperchange_types # NOQA from .sleep_pattern import sleep_pattern # NOQA from .sleep_totals import sleep_totals # NOQA -from .timeline import timeline # NOQA diff --git a/reports/templates/reports/timeline.html b/reports/templates/reports/timeline.html deleted file mode 100644 index 858be8e9..00000000 --- a/reports/templates/reports/timeline.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends 'reports/report_base.html' %} -{% load static %} - -{% block title %}Timeline - {{ object }}{% endblock %} - -{% block breadcrumbs %} - {{ block.super }} - -{% endblock %} - -{% block content %} -

Timeline

-

{{ object }}

-

- - - Previous - - {{ date|date }} - - - Next - -

- -{% endblock %} \ No newline at end of file diff --git a/reports/tests/tests_views.py b/reports/tests/tests_views.py index 64e11e91..abf886cc 100644 --- a/reports/tests/tests_views.py +++ b/reports/tests/tests_views.py @@ -44,6 +44,3 @@ class ViewsTestCase(TestCase): self.assertEqual(page.status_code, 200) page = self.c.get('{}/sleep/totals/'.format(base_url)) self.assertEqual(page.status_code, 200) - - page = self.c.get('{}/timeline/'.format(base_url)) - self.assertEqual(page.status_code, 200) diff --git a/reports/urls.py b/reports/urls.py index 69d96e18..ee6aeb2c 100644 --- a/reports/urls.py +++ b/reports/urls.py @@ -19,8 +19,4 @@ urlpatterns = [ url(r'^children/(?P[^/.]+)/reports/sleep/totals/$', views.SleepTotalsChildReport.as_view(), name='report-sleep-totals-child'), - - url(r'^children/(?P[^/.]+)/reports/timeline/$', - views.TimelineChildReport.as_view(), - name='report-timeline-child'), ] diff --git a/reports/views.py b/reports/views.py index 0dbbde5c..234b61f8 100644 --- a/reports/views.py +++ b/reports/views.py @@ -3,12 +3,11 @@ from __future__ import unicode_literals from django.contrib.auth.mixins import PermissionRequiredMixin from django.views.generic.detail import DetailView -from django.utils import timezone from core.models import Child, DiaperChange, Sleep from .graphs import (diaperchange_types, diaperchange_lifetimes, sleep_pattern, - sleep_totals, timeline) + sleep_totals) class DiaperChangeLifetimesChildReport(PermissionRequiredMixin, DetailView): @@ -89,22 +88,3 @@ class SleepTotalsChildReport(PermissionRequiredMixin, DetailView): if instances: context['html'], context['javascript'] = sleep_totals(instances) return context - - -class TimelineChildReport(PermissionRequiredMixin, DetailView): - """Chronological daily view of events (non-graph). - """ - model = Child - permission_required = ('core.view_child',) - template_name = 'reports/timeline.html' - - def get_context_data(self, **kwargs): - context = super(TimelineChildReport, self).get_context_data(**kwargs) - date = self.request.GET.get('date', str(timezone.localdate())) - date = timezone.datetime.strptime(date, '%Y-%m-%d') - date = timezone.localtime(timezone.make_aware(date)) - context['objects'] = timeline(self.object, date) - context['date'] = date - context['date_previous'] = date - timezone.timedelta(days=1) - context['date_next'] = date + timezone.timedelta(days=1) - return context