Skip to content

Commit

Permalink
Add rudimentary notificationprofile support
Browse files Browse the repository at this point in the history
Ugly but functional.

---------

Co-authored-by: podliashanyk <[email protected]>
  • Loading branch information
hmpf and podliashanyk authored Dec 18, 2024
1 parent c259f98 commit 58f1535
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Replaced the placeholder notification profile page with a very ugly but functional one.
22 changes: 6 additions & 16 deletions src/argus/htmx/notificationprofile/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>NOTIFICATION PROFILES PLACEHOLDER</h1>
{% endblock main %}
"""
)
context = RequestContext(request)
return HttpResponse(template.render(context))
from . import views


app_name = "htmx"
urlpatterns = [
path("", placeholder, name="notificationprofile-placeholder"),
path("", views.NotificationProfileListView.as_view(), name="notificationprofile-list"),
path("create/", views.NotificationProfileCreateView.as_view(), name="notificationprofile-create"),
path("<pk>/", views.NotificationProfileDetailView.as_view(), name="notificationprofile-detail"),
path("<pk>/update/", views.NotificationProfileUpdateView.as_view(), name="notificationprofile-update"),
path("<pk>/delete/", views.NotificationProfileDeleteView.as_view(), name="notificationprofile-delete"),
]
92 changes: 92 additions & 0 deletions src/argus/htmx/notificationprofile/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Everything needed python-wise to CRUD notificationprofiles
See https://ccbv.co.uk/ to grok class-based views.
"""

from django import forms
from django.urls import reverse
from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView

from argus.notificationprofile.models import NotificationProfile, Timeslot, Filter, DestinationConfig


class NotificationProfileForm(forms.ModelForm):
class Meta:
model = NotificationProfile
fields = ["name", "timeslot", "filters", "active", "destinations"]

def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super().__init__(*args, **kwargs)
self.fields["timeslot"].queryset = Timeslot.objects.filter(user=user)
self.fields["filters"].queryset = Filter.objects.filter(user=user)
self.fields["destinations"].queryset = DestinationConfig.objects.filter(user=user)


class NotificationProfileMixin:
"Common functionality for all views"

model = NotificationProfile

def get_queryset(self):
qs = (
super()
.get_queryset()
.select_related("timeslot")
.prefetch_related(
"filters",
"destinations",
)
)
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/notificationprofile"
self.model._meta.model_name = "notificationprofile"
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:notificationprofile-list")


class ChangeMixin:
"Common functionality for create and update views"

form_class = NotificationProfileForm

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["user"] = self.request.user
return kwargs

def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)


class NotificationProfileListView(NotificationProfileMixin, ListView):
pass


class NotificationProfileDetailView(NotificationProfileMixin, DetailView):
pass


class NotificationProfileCreateView(ChangeMixin, NotificationProfileMixin, CreateView):
pass


class NotificationProfileUpdateView(ChangeMixin, NotificationProfileMixin, UpdateView):
pass


class NotificationProfileDeleteView(NotificationProfileMixin, DeleteView):
pass
114 changes: 114 additions & 0 deletions src/argus/htmx/static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,38 @@ html {
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
}

.breadcrumbs {
max-width: 100%;
overflow-x: auto;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}

.breadcrumbs > ul,
.breadcrumbs > ol {
display: flex;
align-items: center;
white-space: nowrap;
min-height: -moz-min-content;
min-height: min-content;
}

.breadcrumbs > ul > li, .breadcrumbs > ol > li {
display: flex;
align-items: center;
}

.breadcrumbs > ul > li > a, .breadcrumbs > ol > li > a {
display: flex;
cursor: pointer;
align-items: center;
}

@media (hover:hover) {
.breadcrumbs > ul > li > a:hover, .breadcrumbs > ol > li > a:hover {
text-decoration-line: underline;
}

.checkbox-primary:hover {
--tw-border-opacity: 1;
border-color: var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));
Expand Down Expand Up @@ -1304,6 +1335,16 @@ html {
opacity: 1;
}

.btm-nav > *.disabled:hover,
.btm-nav > *[disabled]:hover {
pointer-events: none;
--tw-border-opacity: 0;
background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
--tw-bg-opacity: 0.1;
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
--tw-text-opacity: 0.2;
}

.btn:hover {
--tw-border-opacity: 1;
border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity)));
Expand Down Expand Up @@ -2097,11 +2138,57 @@ input.tab:checked + .tab-content,
color: var(--fallback-a,oklch(var(--a)/var(--tw-text-opacity)));
}

.btm-nav > *:where(.active) {
border-top-width: 2px;
--tw-bg-opacity: 1;
background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));
}

.btm-nav > *.disabled,
.btm-nav > *[disabled] {
pointer-events: none;
--tw-border-opacity: 0;
background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
--tw-bg-opacity: 0.1;
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
--tw-text-opacity: 0.2;
}

.btm-nav > * .label {
font-size: 1rem;
line-height: 1.5rem;
}

.breadcrumbs > ul > li > a:focus, .breadcrumbs > ol > li > a:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}

.breadcrumbs > ul > li > a:focus-visible, .breadcrumbs > ol > li > a:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}

.breadcrumbs > ul > li + *:before, .breadcrumbs > ol > li + *:before {
content: "";
margin-left: 0.5rem;
margin-right: 0.75rem;
display: block;
height: 0.375rem;
width: 0.375rem;
--tw-rotate: 45deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
opacity: 0.4;
border-top: 1px solid;
border-right: 1px solid;
background-color: transparent;
}

[dir="rtl"] .breadcrumbs > ul > li + *:before,
[dir="rtl"] .breadcrumbs > ol > li + *:before {
--tw-rotate: -135deg;
}

@media (prefers-reduced-motion: no-preference) {
.btn {
animation: button-pop var(--animation-btn, 0.25s) ease-out;
Expand Down Expand Up @@ -3321,6 +3408,13 @@ details.collapse summary::-webkit-details-marker {
background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
}

.table-zebra tr.active,
.table-zebra tr.active:nth-child(even),
.table-zebra-zebra tbody tr:nth-child(even) {
--tw-bg-opacity: 1;
background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)));
}

.table :where(thead tr, tbody tr:not(:last-child), tbody tr:first-child:last-child) {
border-bottom-width: 1px;
--tw-border-opacity: 1;
Expand Down Expand Up @@ -3451,6 +3545,22 @@ details.collapse summary::-webkit-details-marker {
}
}

.btm-nav-xs > *:where(.active) {
border-top-width: 1px;
}

.btm-nav-sm > *:where(.active) {
border-top-width: 2px;
}

.btm-nav-md > *:where(.active) {
border-top-width: 2px;
}

.btm-nav-lg > *:where(.active) {
border-top-width: 4px;
}

.btn-xs {
height: 1.5rem;
min-height: 1.5rem;
Expand Down Expand Up @@ -4283,6 +4393,10 @@ details.collapse summary::-webkit-details-marker {
flex-grow: 1;
}

.border-collapse {
border-collapse: collapse;
}

.border-separate {
border-collapse: separate;
}
Expand Down
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 @@ -22,7 +22,7 @@
<a href="{% url 'htmx:timeslot-list' %}">Timeslots</a>
</li>
<li>
<a href="{% url 'htmx:notificationprofile-placeholder' %}">Profiles</a>
<a href="{% url 'htmx:notificationprofile-list' %}">Profiles</a>
</li>
{% endblock navlinks %}
</ul>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<section>
<h2>{{ object.name|default:object.timeslot.name }}</h2>
<div>
<p>Active? {{ object.active }}</p>
<p>Timeslot: {{ object.timeslot }}</p>
<p>
Filters:
{% for filter_obj in object.filters.all %}{{ filter_obj }}{% endfor %}
</p>
<p>
Destinations:
{% for destination in object.destinations.all %}{{ destination }}{% endfor %}
</p>
{% if show_buttons %}
<p>
<a class="btn btn-primary"
href="{% url "htmx:notificationprofile-update" pk=object.pk %}">Update</a>
</p>
<p>
<a class="btn btn-primary"
href="{% url "htmx:notificationprofile-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 %}
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 "./_notificationprofile_detail.html" %}
{% endwith %}
{% endblock main %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% extends "htmx/base.html" %}
{% block main %}
<form method="post">
{% csrf_token %}
{{ form.as_div }}
<input class="btn btn-primary" type="submit" value="Save">
</form>
{% endblock main %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{% extends "htmx/base.html" %}
{% block main %}
<p>
<a class="btn btn-primary"
href="{% url "htmx:notificationprofile-create" %}">Create</a>
</p>
{% for object in object_list %}
<div>
{% include "./_notificationprofile_detail.html" %}
<p>
<a class="btn btn-primary"
href="{% url "htmx:notificationprofile-detail" pk=object.pk %}">View</a>
</p>
<p>
<a class="btn btn-primary"
href="{% url "htmx:notificationprofile-update" pk=object.pk %}">Update</a>
</p>
<p>
<a class="btn btn-primary"
href="{% url "htmx:notificationprofile-delete" pk=object.pk %}">Delete</a>
</p>
</div>
{% endfor %}
{% endblock main %}

0 comments on commit 58f1535

Please sign in to comment.