From 6b08a8106bc6a1a72ee55b518cd3ff5bd384914c Mon Sep 17 00:00:00 2001 From: Hanne Moa Date: Thu, 12 Dec 2024 13:52:18 +0100 Subject: [PATCH 1/2] Add rudimentary timeslot support --- src/argus/htmx/templates/htmx/base.html | 2 +- .../htmx/timeslot/_timeslot_detail.html | 16 +++ .../timeslot/timeslot_confirm_delete.html | 9 ++ .../htmx/timeslot/timeslot_detail.html | 6 + .../htmx/timeslot/timeslot_form.html | 9 ++ .../htmx/timeslot/timeslot_list.html | 23 ++++ src/argus/htmx/timeslot/urls.py | 22 +--- src/argus/htmx/timeslot/views.py | 104 ++++++++++++++++++ 8 files changed, 174 insertions(+), 17 deletions(-) create mode 100644 src/argus/htmx/templates/htmx/timeslot/_timeslot_detail.html create mode 100644 src/argus/htmx/templates/htmx/timeslot/timeslot_confirm_delete.html create mode 100644 src/argus/htmx/templates/htmx/timeslot/timeslot_detail.html create mode 100644 src/argus/htmx/templates/htmx/timeslot/timeslot_form.html create mode 100644 src/argus/htmx/templates/htmx/timeslot/timeslot_list.html create mode 100644 src/argus/htmx/timeslot/views.py diff --git a/src/argus/htmx/templates/htmx/base.html b/src/argus/htmx/templates/htmx/base.html index e93af2b02..749867cf4 100644 --- a/src/argus/htmx/templates/htmx/base.html +++ b/src/argus/htmx/templates/htmx/base.html @@ -19,7 +19,7 @@ Incidents
  • - Timeslots + Timeslots
  • Profiles diff --git a/src/argus/htmx/templates/htmx/timeslot/_timeslot_detail.html b/src/argus/htmx/templates/htmx/timeslot/_timeslot_detail.html new file mode 100644 index 000000000..cafcb6099 --- /dev/null +++ b/src/argus/htmx/templates/htmx/timeslot/_timeslot_detail.html @@ -0,0 +1,16 @@ +
    +

    {{ object.name }}

    +
    + {% for time_recurrence in object.time_recurrences.all %}

    {{ time_recurrence }}

    {% endfor %} + {% if show_buttons %} +

    + Update +

    +

    + Delete +

    + {% endif %} +
    +
    diff --git a/src/argus/htmx/templates/htmx/timeslot/timeslot_confirm_delete.html b/src/argus/htmx/templates/htmx/timeslot/timeslot_confirm_delete.html new file mode 100644 index 000000000..9e9eaba2c --- /dev/null +++ b/src/argus/htmx/templates/htmx/timeslot/timeslot_confirm_delete.html @@ -0,0 +1,9 @@ +{% extends "htmx/base.html" %} +{% block main %} +
    + {% csrf_token %} +

    Are you sure you want to delete "{{ object }}"?

    + {{ form }} + +
    +{% endblock main %} diff --git a/src/argus/htmx/templates/htmx/timeslot/timeslot_detail.html b/src/argus/htmx/templates/htmx/timeslot/timeslot_detail.html new file mode 100644 index 000000000..868c668b9 --- /dev/null +++ b/src/argus/htmx/templates/htmx/timeslot/timeslot_detail.html @@ -0,0 +1,6 @@ +{% extends "htmx/base.html" %} +{% block main %} + {% with show_buttons=True %} + {% include "./_timeslot_detail.html" %} + {% endwith %} +{% endblock main %} diff --git a/src/argus/htmx/templates/htmx/timeslot/timeslot_form.html b/src/argus/htmx/templates/htmx/timeslot/timeslot_form.html new file mode 100644 index 000000000..19b1e34d7 --- /dev/null +++ b/src/argus/htmx/templates/htmx/timeslot/timeslot_form.html @@ -0,0 +1,9 @@ +{% extends "htmx/base.html" %} +{% block main %} +
    + {% csrf_token %} + {{ form.as_div }} + {{ formset.as_div }} + +
    +{% endblock main %} diff --git a/src/argus/htmx/templates/htmx/timeslot/timeslot_list.html b/src/argus/htmx/templates/htmx/timeslot/timeslot_list.html new file mode 100644 index 000000000..f9174a2f2 --- /dev/null +++ b/src/argus/htmx/templates/htmx/timeslot/timeslot_list.html @@ -0,0 +1,23 @@ +{% extends "htmx/base.html" %} +{% block main %} +

    + Create +

    + {% for object in object_list %} +
    + {% include "./_timeslot_detail.html" %} +

    + View +

    +

    + Update +

    +

    + Delete +

    +
    + {% endfor %} +{% endblock main %} diff --git a/src/argus/htmx/timeslot/urls.py b/src/argus/htmx/timeslot/urls.py index c8d116f38..ad953136c 100644 --- a/src/argus/htmx/timeslot/urls.py +++ b/src/argus/htmx/timeslot/urls.py @@ -1,23 +1,13 @@ -from django.http import HttpResponse -from django.template import Template, RequestContext from django.urls import path -from django.views.decorators.http import require_GET - -@require_GET -def placeholder(request): - template = Template( - """{% extends "htmx/base.html" %} - {% block main %} -

    TIMESLOT PLACEHOLDER

    - {% endblock main %} - """ - ) - context = RequestContext(request) - return HttpResponse(template.render(context)) +from . import views app_name = "htmx" urlpatterns = [ - path("", placeholder, name="timeslot-placeholder"), + path("", views.TimeslotListView.as_view(), name="timeslot-list"), + path("create/", views.TimeslotCreateView.as_view(), name="timeslot-create"), + path("/", views.TimeslotDetailView.as_view(), name="timeslot-detail"), + path("/update/", views.TimeslotUpdateView.as_view(), name="timeslot-update"), + path("/delete/", views.TimeslotDeleteView.as_view(), name="timeslot-delete"), ] diff --git a/src/argus/htmx/timeslot/views.py b/src/argus/htmx/timeslot/views.py new file mode 100644 index 000000000..c391b9d3f --- /dev/null +++ b/src/argus/htmx/timeslot/views.py @@ -0,0 +1,104 @@ +from typing import Optional + +from django import forms +from django.http import HttpResponseRedirect +from django.urls import reverse +from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView + +from argus.notificationprofile.models import Timeslot, TimeRecurrence + + +class TimeRecurrenceForm(forms.ModelForm): + class Meta: + model = TimeRecurrence + exclude = ["timeslot"] + + +def make_timerecurrence_formset(data: Optional[dict] = None, timeslot: Optional[Timeslot] = None): + extra = 0 if not timeslot else 1 + TimeRecurrenceFormSet = forms.inlineformset_factory( + Timeslot, TimeRecurrence, fields="__all__", extra=extra, can_delete=False, min_num=1 + ) + return TimeRecurrenceFormSet(data=data, instance=timeslot) + + +class TimeslotMixin: + model = Timeslot + + def get_queryset(self): + qs = super().get_queryset().prefetch_related("time_recurrences") + return qs.filter(user_id=self.request.user.id) + + def get_template_names(self): + orig_app_label = self.model._meta.app_label + orig_model_name = self.model._meta.model_name + self.model._meta.app_label = "htmx/timeslot" + self.model._meta.model_name = "timeslot" + templates = super().get_template_names() + self.model._meta.app_label = orig_app_label + self.model._meta.model_name = orig_model_name + return templates + + def get_success_url(self): + return reverse("htmx:timeslot-list") + + +class FormsetMixin: + def post(self, request, *args, **kwargs): + form = self.get_form() + formset = make_timerecurrence_formset(data=request.POST, timeslot=self.object) + if form.is_valid() and formset.is_valid(): + return self.form_valid(form, formset) + else: + return self.form_invalid(form, formset) + + def form_invalid(self, form, formset): + return self.render_to_response(self.get_context_data(form=form, formset=formset)) + + def form_valid(self, form, formset): + self.object = form.save(commit=False) + self.object.user = self.request.user + self.object.save() + trs = formset.save(commit=False) + for tr in trs: + tr.timeslot = self.object + tr.save() + return HttpResponseRedirect(self.get_success_url()) + + +class TimeslotListView(TimeslotMixin, ListView): + pass + + +class TimeslotDetailView(TimeslotMixin, DetailView): + pass + + +class TimeslotCreateView(FormsetMixin, TimeslotMixin, CreateView): + fields = ["name"] + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["formset"] = make_timerecurrence_formset() + return context + + def post(self, request, *args, **kwargs): + self.object = None + return super().post(request, *args, **kwargs) + + +class TimeslotUpdateView(FormsetMixin, TimeslotMixin, UpdateView): + fields = ["name"] + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["formset"] = make_timerecurrence_formset(timeslot=self.object) + return context + + def post(self, request, *args, **kwargs): + self.object = self.get_object() + return super().post(request, *args, **kwargs) + + +class TimeslotDeleteView(TimeslotMixin, DeleteView): + pass From acfd5c57ad4ffe8bbaec01d8b93380043ae9d551 Mon Sep 17 00:00:00 2001 From: Hanne Moa Date: Thu, 12 Dec 2024 13:58:55 +0100 Subject: [PATCH 2/2] add changelog fragment --- changelog.d/+add-rudimentary-timeslots-page.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/+add-rudimentary-timeslots-page.added.md diff --git a/changelog.d/+add-rudimentary-timeslots-page.added.md b/changelog.d/+add-rudimentary-timeslots-page.added.md new file mode 100644 index 000000000..2a6e85e7f --- /dev/null +++ b/changelog.d/+add-rudimentary-timeslots-page.added.md @@ -0,0 +1 @@ +Replaced the placeholder time-slots page with a very ugly but functional one.