Skip to content

Commit

Permalink
Add rudimentary timeslot support
Browse files Browse the repository at this point in the history
  • Loading branch information
hmpf authored Dec 17, 2024
1 parent 0f1f51d commit 8b5f8d1
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 17 deletions.
1 change: 1 addition & 0 deletions changelog.d/+add-rudimentary-timeslots-page.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Replaced the placeholder time-slots page with a very ugly but functional one.
2 changes: 1 addition & 1 deletion src/argus/htmx/templates/htmx/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<a href="{% url 'htmx:incident-list' %}">Incidents</a>
</li>
<li>
<a href="{% url 'htmx:timeslot-placeholder' %}">Timeslots</a>
<a href="{% url 'htmx:timeslot-list' %}">Timeslots</a>
</li>
<li>
<a href="{% url 'htmx:notificationprofile-placeholder' %}">Profiles</a>
Expand Down
16 changes: 16 additions & 0 deletions src/argus/htmx/templates/htmx/timeslot/_timeslot_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<section>
<h2>{{ object.name }}</h2>
<div>
{% for time_recurrence in object.time_recurrences.all %}<p>{{ time_recurrence }}</p>{% endfor %}
{% if show_buttons %}
<p>
<a class="btn btn-primary"
href="{% url "htmx:timeslot-update" pk=object.pk %}">Update</a>
</p>
<p>
<a class="btn btn-primary"
href="{% url "htmx:timeslot-delete" pk=object.pk %}">Delete</a>
</p>
{% endif %}
</div>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "htmx/base.html" %}
{% block main %}
<form method="post">
{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
{{ form }}
<input class="btn btn-primary" type="submit" value="Confirm">
</form>
{% endblock main %}
6 changes: 6 additions & 0 deletions src/argus/htmx/templates/htmx/timeslot/timeslot_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% extends "htmx/base.html" %}
{% block main %}
{% with show_buttons=True %}
{% include "./_timeslot_detail.html" %}
{% endwith %}
{% endblock main %}
9 changes: 9 additions & 0 deletions src/argus/htmx/templates/htmx/timeslot/timeslot_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "htmx/base.html" %}
{% block main %}
<form method="post">
{% csrf_token %}
{{ form.as_div }}
{{ formset.as_div }}
<input class="btn btn-primary" type="submit" value="Save">
</form>
{% endblock main %}
23 changes: 23 additions & 0 deletions src/argus/htmx/templates/htmx/timeslot/timeslot_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% extends "htmx/base.html" %}
{% block main %}
<p>
<a class="btn btn-primary" href="{% url "htmx:timeslot-create" %}">Create</a>
</p>
{% for object in object_list %}
<div>
{% include "./_timeslot_detail.html" %}
<p>
<a class="btn btn-primary"
href="{% url "htmx:timeslot-detail" pk=object.pk %}">View</a>
</p>
<p>
<a class="btn btn-primary"
href="{% url "htmx:timeslot-update" pk=object.pk %}">Update</a>
</p>
<p>
<a class="btn btn-primary"
href="{% url "htmx:timeslot-delete" pk=object.pk %}">Delete</a>
</p>
</div>
{% endfor %}
{% endblock main %}
22 changes: 6 additions & 16 deletions src/argus/htmx/timeslot/urls.py
Original file line number Diff line number Diff line change
@@ -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 %}
<h1>TIMESLOT PLACEHOLDER</h1>
{% 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("<pk>/", views.TimeslotDetailView.as_view(), name="timeslot-detail"),
path("<pk>/update/", views.TimeslotUpdateView.as_view(), name="timeslot-update"),
path("<pk>/delete/", views.TimeslotDeleteView.as_view(), name="timeslot-delete"),
]
104 changes: 104 additions & 0 deletions src/argus/htmx/timeslot/views.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 8b5f8d1

Please sign in to comment.