dashboard: Add more flexible Link Card dashboard fragment
with support for tooltips and accordions
This commit is contained in:
parent
387767204a
commit
26514e60fb
@ -1,3 +1,4 @@
|
|||||||
|
import dataclasses
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
@ -10,6 +11,16 @@ def register(fragment):
|
|||||||
return fragment
|
return fragment
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class Link:
|
||||||
|
text: str
|
||||||
|
href: str
|
||||||
|
tooltip: str | None = None
|
||||||
|
body: str | None = None
|
||||||
|
_: dataclasses.KW_ONLY
|
||||||
|
permission: str | None
|
||||||
|
|
||||||
|
|
||||||
class DashboardFragment:
|
class DashboardFragment:
|
||||||
name: str
|
name: str
|
||||||
template: str
|
template: str
|
||||||
@ -18,3 +29,12 @@ class DashboardFragment:
|
|||||||
|
|
||||||
def __init__(self, request: HttpRequest):
|
def __init__(self, request: HttpRequest):
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
|
|
||||||
|
class LinksCardDashboardFragment(DashboardFragment):
|
||||||
|
template = "dashboard/links_card.dj.html"
|
||||||
|
links: [Link] = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self):
|
||||||
|
return {"links": self.links}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">{{ app }}</h5>
|
<h5 class="card-header">{{ app }}</h5>
|
||||||
{% include app_dash.template with ctx=app_dash.context %}
|
{% include app_dash.template with app=app ctx=app_dash.context %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -24,3 +24,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block script %}
|
||||||
|
<script>
|
||||||
|
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
|
||||||
|
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
@ -1,7 +1,28 @@
|
|||||||
<ul class="list-group list-group-flush">
|
<div class="accordion accordion-flush" id="{{ app|slugify }}-dash">
|
||||||
{% for text, link in ctx.links.items %}
|
{% for link in ctx.links %}
|
||||||
<li class="list-group-item">
|
{% if link.permission is None or link.permission in perms %}
|
||||||
<a class="card-link" href="{{ link }}">{{ text }}</a>
|
<div class="accordion-item">
|
||||||
</li>
|
<div class="accordion-header d-flex align-items-center">
|
||||||
|
<a {% if link.tooltip is not None %}data-bs-toggle="tooltip" title="{{ link.tooltip }}"{% endif %}
|
||||||
|
href="{{ link.href }}"
|
||||||
|
class="text-nowrap mx-3 p-1">{{ link.text }}</a>
|
||||||
|
{% if link.body is not None %}
|
||||||
|
<button class="accordion-button collapsed bg-transparent shadow-none py-1"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#{{ app|slugify }}-{{ forloop.counter }}"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls="{{ app|slugify }}-{{ forloop.counter }}"></button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if link.body is not None %}
|
||||||
|
<div id="{{ app|slugify }}-{{ forloop.counter }}"
|
||||||
|
class="accordion-collapse collapse"
|
||||||
|
data-bs-parent="#{{ app|slugify }}-dash">
|
||||||
|
<div class="accordion-body">{{ link.body }}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</div>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
from typing import Any
|
|
||||||
|
|
||||||
import dashboard
|
import dashboard
|
||||||
|
from dashboard import Link
|
||||||
|
|
||||||
from .views import REPORTS
|
from .views import REPORTS
|
||||||
|
|
||||||
|
|
||||||
@dashboard.register
|
@dashboard.register
|
||||||
class DoorControlDashboardFragment(dashboard.DashboardFragment):
|
class DoorControlDashboardFragment(dashboard.LinksCardDashboardFragment):
|
||||||
name = "Door Controls"
|
name = "Door Controls"
|
||||||
template = "dashboard/links_card.dj.html"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def context(self) -> Any:
|
def links(self) -> list[Link]:
|
||||||
return {
|
return [
|
||||||
"links": dict(rt for report in REPORTS for rt in report._report_types())
|
Link(name, link, permission="doorcontrol.view_hidevent")
|
||||||
}
|
for report in REPORTS
|
||||||
|
for name, link in report._report_types()
|
||||||
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def visible(self) -> bool:
|
def visible(self) -> bool:
|
||||||
|
@ -1,25 +1,31 @@
|
|||||||
from typing import Any
|
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
import dashboard
|
import dashboard
|
||||||
|
from dashboard import Link
|
||||||
|
|
||||||
|
|
||||||
@dashboard.register
|
@dashboard.register
|
||||||
class MembershipworksDashboardFragment(dashboard.DashboardFragment):
|
class MembershipworksDashboardFragment(dashboard.LinksCardDashboardFragment):
|
||||||
name = "MembershipWorks"
|
name = "MembershipWorks"
|
||||||
template = "dashboard/links_card.dj.html"
|
|
||||||
|
|
||||||
@property
|
links = [
|
||||||
def context(self) -> Any:
|
Link(
|
||||||
links = {}
|
"Upcoming Events",
|
||||||
|
reverse("membershipworks:upcoming-events"),
|
||||||
if self.request.user.has_perm("membershipworks.view_event"):
|
permission="membershipworks.view_event",
|
||||||
links["Upcoming Events"] = reverse("membershipworks:upcoming-events")
|
tooltip="Generator for Wordpress posts",
|
||||||
links["Event Report"] = reverse("membershipworks:event-index-report")
|
),
|
||||||
links["Event Attendees"] = reverse("membershipworks:event-attendees")
|
Link(
|
||||||
|
"Event Report",
|
||||||
return {"links": links}
|
reverse("membershipworks:event-index-report"),
|
||||||
|
permission="membershipworks.view_event",
|
||||||
|
),
|
||||||
|
Link(
|
||||||
|
"Event Attendees",
|
||||||
|
reverse("membershipworks:event-attendees"),
|
||||||
|
permission="membershipworks.view_event",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def visible(self) -> bool:
|
def visible(self) -> bool:
|
||||||
|
@ -1,37 +1,45 @@
|
|||||||
from typing import Any
|
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
import dashboard
|
import dashboard
|
||||||
|
from dashboard import Link
|
||||||
from membershipworks.models import Member
|
from membershipworks.models import Member
|
||||||
|
|
||||||
from .models import Department
|
from .models import Department
|
||||||
|
|
||||||
|
|
||||||
@dashboard.register
|
@dashboard.register
|
||||||
class PaperworkDashboardFragment(dashboard.DashboardFragment):
|
class PaperworkDashboardFragment(dashboard.LinksCardDashboardFragment):
|
||||||
name = "Paperwork"
|
name = "Paperwork"
|
||||||
template = "dashboard/links_card.dj.html"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def context(self) -> Any:
|
def links(self) -> list[Link]:
|
||||||
links = {}
|
links = []
|
||||||
|
|
||||||
member = Member.from_user(self.request.user)
|
member = Member.from_user(self.request.user)
|
||||||
if member is not None:
|
if member is not None:
|
||||||
links["Member Certifications"] = reverse(
|
links.append(
|
||||||
|
dashboard.Link(
|
||||||
|
"Member Certifications",
|
||||||
|
reverse(
|
||||||
"paperwork:member_certifications", kwargs={"uid": member.uid}
|
"paperwork:member_certifications", kwargs={"uid": member.uid}
|
||||||
|
),
|
||||||
|
permission=None,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.request.user.is_superuser or (
|
if self.request.user.is_superuser or (
|
||||||
member is not None
|
member is not None
|
||||||
and Department.objects.filter_by_shop_lead(member).exists()
|
and Department.objects.filter_by_shop_lead(member).exists()
|
||||||
):
|
):
|
||||||
links["Department Certifications"] = reverse(
|
links.append(
|
||||||
"paperwork:department_certifications"
|
Link(
|
||||||
|
"Department Certifications",
|
||||||
|
reverse("paperwork:department_certifications"),
|
||||||
|
permission=None,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return {"links": links}
|
return links
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def visible(self) -> bool:
|
def visible(self) -> bool:
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
from typing import Any
|
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
import dashboard
|
import dashboard
|
||||||
|
from dashboard import Link
|
||||||
|
|
||||||
|
|
||||||
@dashboard.register
|
@dashboard.register
|
||||||
class RentalsDashboardFragment(dashboard.DashboardFragment):
|
class RentalsDashboardFragment(dashboard.LinksCardDashboardFragment):
|
||||||
name = "Rentals"
|
name = "Rentals"
|
||||||
template = "dashboard/links_card.dj.html"
|
template = "dashboard/links_card.dj.html"
|
||||||
|
|
||||||
@property
|
links = [Link("Locker Index", reverse("rentals:index"), permission=None)]
|
||||||
def context(self) -> Any:
|
|
||||||
return {"links": {"Locker Index": reverse("rentals:index")}}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user