Skip to content

Commit

Permalink
star on UI
Browse files Browse the repository at this point in the history
  • Loading branch information
shapiromatron committed May 3, 2024
1 parent a46ded4 commit 600bd93
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 5 deletions.
6 changes: 3 additions & 3 deletions bmds_server/analysis/templates/analysis/desktop_home.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ <h3>Analyses</h3>
</colgroup>
<tbody>
{% for object in objects %}
<tr class="stretched-link-parent" >
<td class="text-center"><span class="starred bi {{object.starred|yesno:'bi-star-fill,bi-star'}}"></span></td>
<td>
<tr>
{% include 'analysis/fragments/td_star.html' with object=object %}
<td class="stretched-link-parent">
{% for collection in object.collections.all %}<span class="mr-1 badge badge-info">{{collection}}</span>{% endfor %}
<a class="text-dark stretched-link" href="{{object.get_edit_url}}">{{object}}</a>
</td>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<td class="text-center px-2 pointer" hx-get="{% url 'actions' action='toggle_star' %}?id={{object.id}}"
hx-swap="outerHTML" hx-on="click">
<span class="starred bi {{object.starred|yesno:'bi-star-fill,bi-star'}}"></span>
</td>
22 changes: 21 additions & 1 deletion bmds_server/analysis/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from django.conf import settings
from django.contrib.admin.views.decorators import staff_member_required
from django.db.models.query import QuerySet
from django.http import HttpRequest
from django.middleware.csrf import get_token
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, render
from django.template import RequestContext, Template
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
Expand All @@ -19,6 +20,7 @@
UpdateView,
)

from ..common.views import HtmxView, action
from . import forms, models
from .reporting.analytics import get_cached_analytics
from .utils import get_citation
Expand Down Expand Up @@ -77,6 +79,24 @@ def get_context_data(self, **kwargs):
return context


class DesktopActions(HtmxView):
actions: ClassVar = {
"toggle_star",
}

@action()
def toggle_star(self, request: HttpRequest, **kw):
id = request.GET.get("id", "")
object = get_object_or_404(models.Analysis, id=id)
object.starred = not object.starred
models.Analysis.objects.bulk_update([object], ["starred"])
return render(
request,
"analysis/fragments/td_star.html",
{"object": object},
)


class AnalysisCreate(CreateView):
model = models.Analysis
form_class = forms.CreateAnalysisForm
Expand Down
63 changes: 62 additions & 1 deletion bmds_server/common/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import logging
from collections.abc import Iterable
from functools import wraps
from pprint import pformat
from textwrap import dedent
from typing import Any
Expand All @@ -9,7 +11,12 @@
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.views import LoginView, LogoutView
from django.core.mail import mail_admins
from django.http import HttpResponseRedirect
from django.http import (
HttpRequest,
HttpResponseBadRequest,
HttpResponseNotAllowed,
HttpResponseRedirect,
)
from django.shortcuts import resolve_url
from django.template.response import TemplateResponse
from django.urls import reverse
Expand Down Expand Up @@ -133,3 +140,57 @@ def get(self, request, *args, **kwargs):
@method_decorator(staff_member_required, name="dispatch")
class Swagger(TemplateView):
template_name = "common/swagger.html"


def is_htmx(request: HttpRequest) -> bool:
"""Was this request initiated by HTMX?"""
return request.headers.get("HX-Request", "") == "true"


def action(htmx_only: bool = True, methods: Iterable[str] = ("get",)):
"""Decorator for an HtmxViewSet action method
Influenced by django-rest framework's ViewSet action decorator; permissions checking that
the user making the request can make this request, and the request is valid.
Args:
htmx_only (bool, optional, default True): Accept only htmx requests
methods (Iterable[str]): Accepted http methods; defaults to ("get",)
"""

def actual_decorator(func):
@wraps(func)
def wrapper(view, request, *args, **kwargs):
# check if htmx is required
if htmx_only and not is_htmx(request):
return HttpResponseBadRequest("An HTMX request is required")
# check valid view method
if request.method.lower() not in methods:
return HttpResponseNotAllowed("Invalid HTTP method")
return func(view, request, *args, **kwargs)

return wrapper

return actual_decorator


class HtmxView(View):
"""Build a generic HtmxView which returns a index full page and multiple fragments.
If a valid "action" is specified via a GET parameter, a partial is returned, otherwise
the default_action ("index") is returned. It is generally assumed that the default_action
is a full page, while all other pages are fragments.
"""

actions: set[str]
default_action: str = "index"

def get_handler(self, request: HttpRequest):
request.action = self.kwargs.get("action", "")
if request.action not in self.actions:
request.action = self.default_action
return getattr(self, request.action, self.http_method_not_allowed)

def dispatch(self, request, *args, **kwargs):
handler = self.get_handler(request)
return handler(request, *args, **kwargs)
1 change: 1 addition & 0 deletions bmds_server/main/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@

if settings.IS_DESKTOP:
urlpatterns += [
path("actions/<slug:action>/", views.DesktopActions.as_view(), name="actions"),
path("collection/", views.CollectionList.as_view(), name="collection_list"),
path("collection/create/", views.CollectionCreate.as_view(), name="collection_create"),
path(
Expand Down
4 changes: 4 additions & 0 deletions bmds_server/static/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,7 @@ input[type=number] {
.text-sm {
font-size: 0.9rem;
}

.pointer {
cursor: pointer;
}
1 change: 1 addition & 0 deletions bmds_server/static/vendor/htmx/htmx.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions bmds_server/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
{% endif %}
<script src="{% static 'vendor/jquery/3.6.1/jquery.min.js' %}"></script>
<script src="{% static 'vendor/bootstrap/4.6.2/js/bootstrap.bundle.min.js' %}"></script>
<script src="{% static 'vendor/htmx/htmx.min.js' %}"></script>
{% endcache footer %}
{% render_bundle 'main' %}
{% block extra-js %}
Expand Down

0 comments on commit 600bd93

Please sign in to comment.