Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rudimentary timeslot support #1087

Merged
merged 2 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
hmpf marked this conversation as resolved.
Show resolved Hide resolved
<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
hmpf marked this conversation as resolved.
Show resolved Hide resolved
)
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):
hmpf marked this conversation as resolved.
Show resolved Hide resolved
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
Loading