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

Sorting #1906

Merged
merged 6 commits into from
Jul 16, 2024
Merged

Sorting #1906

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
5 changes: 0 additions & 5 deletions liiweb/views/legislation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ class LegislationListView(FilteredDocumentListView):
latest_expression_only = True
extra_context = {"doc_table_citations": True, "legislation_list_sort": "title"}

def get_template_names(self):
if self.request.htmx:
return ["peachjam/faceted_doc_table.html"]
return ["liiweb/legislation_list.html"]

def filter_queryset(self, qs):
if self.variant == "all":
pass
Expand Down
16 changes: 12 additions & 4 deletions peachjam/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ class BaseDocumentFilterForm(forms.Form):
attorneys = forms.CharField(required=False)
outcomes = forms.CharField(required=False)

sort = forms.ChoiceField(
required=False,
choices=[
("title", _("Title") + " (A - Z)"),
("-title", _("Title") + " (Z - A)"),
("-date", _("Date") + " " + _("(Newest first)")),
("date", _("Date") + " " + _("(Oldest first)")),
],
)

def __init__(self, data, *args, **kwargs):
self.params = QueryDict(mutable=True)
self.params.update(data)
Expand Down Expand Up @@ -147,10 +157,8 @@ def filter_queryset(self, queryset, exclude=None):
return queryset

def order_queryset(self, queryset, exclude=None):
if self.cleaned_data.get("alphabet") and exclude != "alphabet":
queryset = queryset.order_by("title")
else:
queryset = queryset.order_by("-date", "title")
sort = self.cleaned_data.get("sort") or "-date"
queryset = queryset.order_by(sort, "title")
return queryset


Expand Down
27 changes: 27 additions & 0 deletions peachjam/js/components/document-table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class DocumentTable {
public root: HTMLElement;

constructor (root: HTMLElement) {
this.root = root;
this.setupSorting();
}

setupSorting () {
this.root.querySelectorAll('[data-sort]').forEach((el) => {
el.addEventListener('click', (e: Event) => {
this.setSort(el.getAttribute('data-sort') || '');
});
});
}

setSort (value: string) {
// find the enclosing form element and set the value of the name=sort input
const form = this.root.closest('form');
if (form && form.sort) {
form.sort.value = value;
form.sort.dispatchEvent(new Event('change'));
}
}
}

export default DocumentTable;
2 changes: 2 additions & 0 deletions peachjam/js/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CopyToClipboard } from './clipboard';
import { RelationshipEnrichments } from './RelationshipEnrichment';
import DocumentList from './document-list';
import DocumentTable from './document-table';
import DocumentContent from './DocumentContent/index';
import NavigationSelect from './navigation-select';
import { ToggleTab } from './tabs';
Expand All @@ -15,6 +16,7 @@ const components: Record<string, any> = {
// Data components
CopyToClipboard,
DocumentContent,
DocumentTable,
DocumentList,
NavigationSelect,
RelationshipEnrichments,
Expand Down
83 changes: 59 additions & 24 deletions peachjam/js/peachjam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import '@lawsafrica/law-widgets/dist/components/la-table-of-contents-controller'
import '@lawsafrica/law-widgets/dist/components/la-decorate-external-refs';
import '@lawsafrica/law-widgets/dist/components/la-decorate-internal-refs';
import '@lawsafrica/law-widgets/dist/components/la-decorate-terms';
import 'htmx.org';
// @ts-ignore
import htmx from 'htmx.org';

export interface PeachJamConfig {
appName: string;
Expand Down Expand Up @@ -43,8 +44,10 @@ class PeachJam {
this.setupConfig();
// add the current user agent to the root HTML element for use with pocketlaw
document.documentElement.setAttribute('data-user-agent', navigator.userAgent.toLowerCase());
this.setupHtmx();
this.setupSentry();
this.createComponents();
this.createComponents(document.body);
this.createVueComponents(document.body);
this.setupTooltips();
this.setupPopovers();
this.scrollNavTabs();
Expand All @@ -58,32 +61,64 @@ class PeachJam {
}
}

createComponents () {
document.querySelectorAll('[data-component]').forEach((el) => {
const name: string | null = el.getAttribute('data-component');
if (name && components[name]) {
// create the component and attached it to the HTML element
(el as any).component = new components[name](el);
this.components.push((el as any).component);
setupHtmx () {
window.htmx = htmx;
// htmx:load is fired both when the page loads (weird) and when new content is loaded. We only care about the latter
// case. See https://github.com/bigskysoftware/htmx/issues/1500
const htmxHelper = { firstLoad: true};
document.body.addEventListener('htmx:load', (e) => {
if (htmxHelper.firstLoad) {
htmxHelper.firstLoad = false;
return;
}
// mount components on new elements
this.createComponents(e.target as HTMLElement);
this.createVueComponents(e.target as HTMLElement);
});
}

createComponents (root: HTMLElement) {
if (root.getAttribute('data-component')) {
this.createComponent(root);
}
// @ts-ignore
for (const element of root.querySelectorAll('[data-component]')) {
this.createComponent(element);
}
}

createVueComponents (root: HTMLElement) {
// create vue-based components
document.querySelectorAll('[data-vue-component]').forEach((el) => {
const name = el.getAttribute('data-vue-component');
if (name && components[name]) {
const vueComp = components[name];
createAndMountApp({
component: vueComp,
// pass in the element's data attributes as props
props: { ...(el as HTMLElement).dataset },
use: [vueI18n],
mountTarget: el as HTMLElement
});
(el as any).component = vueComp;
this.components.push(vueComp);
}
});
// @ts-ignore
for (const element of root.querySelectorAll('[data-vue-component]')) {
this.createVueComponent(element);
}
}

createComponent (el: HTMLElement) {
const name: string | null = el.getAttribute('data-component');
if (name && components[name]) {
// create the component and attached it to the HTML element
(el as any).component = new components[name](el);
this.components.push((el as any).component);
}
}

createVueComponent (el: HTMLElement) {
// create vue-based components
const name = el.getAttribute('data-vue-component');
if (name && components[name]) {
const vueComp = components[name];
createAndMountApp({
component: vueComp,
// pass in the element's data attributes as props
props: { ...(el as HTMLElement).dataset },
use: [vueI18n],
mountTarget: el as HTMLElement
});
(el as any).component = vueComp;
this.components.push(vueComp);
}
}

setupSentry () {
Expand Down
2 changes: 1 addition & 1 deletion peachjam/static/js/app-prod.js

Large diffs are not rendered by default.

22 changes: 19 additions & 3 deletions peachjam/templates/peachjam/_document_table.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
{% load i18n peachjam %}
<div class="table-responsive" id="doc-table">
<div class="table-responsive"
id="doc-table"
data-component="DocumentTable">
<table class="doc-table {% if doc_table_toggle %}doc-table--toggle{% endif %} {% if doc_table_citations %}doc-table--citation{% endif %} {{ doc_table_classes }}">
<thead>
<tr>
{% if doc_table_toggle %}<th class="cell-toggle"></th>{% endif %}
<th scope="col" class="cell-title">{% trans 'Title' %}</th>
<th scope="col" class="cell-title">
<div class="align-items-center"
role="button"
data-sort="{% if form.sort.value == "title" %}-title{% else %}title{% endif %}">
{% trans 'Title' %}
<i class="bi ms-2 {% if form.sort.value == "title" %}bi-sort-up{% endif %} {% if form.sort.value == "-title" %}bi-sort-down{% endif %}"></i>
</div>
</th>
{% if doc_table_citations %}<th scope="col" class="cell-citation"></th>{% endif %}
{% if doc_table_show_jurisdiction %}
{% if MULTIPLE_JURISDICTIONS or MULTIPLE_LOCALITIES %}
Expand All @@ -14,7 +23,14 @@
{% if doc_table_show_author %}<th scope="col"></th>{% endif %}
{% if doc_table_show_court %}<th scope="col"></th>{% endif %}
{% if doc_table_show_doc_type %}<th scope="col"></th>{% endif %}
<th scope="col" class="cell-date">{% trans 'Date' %}</th>
<th scope="col" class="cell-date">
<div class="align-items-center"
role="button"
data-sort="{% if form.sort.value == "date" %}-date{% else %}date{% endif %}">
{% trans 'Date' %}
<i class="bi ms-2 {% if form.sort.value == "-date" %}bi-sort-up{% endif %} {% if form.sort.value == "date" %}bi-sort-down{% endif %}"></i>
</div>
</th>
</tr>
</thead>
{% for document in documents %}
Expand Down
86 changes: 44 additions & 42 deletions peachjam/templates/peachjam/faceted_doc_table.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{% load i18n %}
<div class="row" id="faceted-table">
<div class="col-lg-3 d-none d-lg-block">
<div>
{% block desktop-taxonomy-list %}{% endblock %}
</div>
<div class="pocketlaw-hidden">
<form method="get" id="filter-form">
<form method="get" id="filter-form" hx-include="#filter-form">
<div class="row" id="faceted-table">
<div class="col-lg-3 d-none d-lg-block">
<div>
{% block desktop-taxonomy-list %}{% endblock %}
</div>
<div class="pocketlaw-hidden">
<ul class="list-group">
<li class="position-relative list-group-item bg-light d-flex justify-content-between align-items-center">
<strong>{% trans 'Filters' %}</strong>
Expand Down Expand Up @@ -67,42 +67,44 @@
{% endif %}
{% endfor %}
</ul>
</form>
</div>
</div>
</div>
<div class="col-lg-9">
<div class="position-relative">
{% block content %}
{% if documents %}
{% block filter-documents %}
<div class="row">
<div class="col">
<input id="filter-input"
form="filter-form"
aria-label="Filter"
placeholder="Filter documents"
class="form-control"
type="text"
name="q"/>
</div>
<div class="col-auto ms-0 ps-0">
<button hx-get="{{ request.path }}"
hx-target="#doc-table"
hx-push-url="true"
hx-include="#facetd-table"
class="btn btn-primary"
type="submit"
value="Filter">
Filter
</button>
<div class="col-lg-9">
<div class="position-relative">
{% block content %}
{% if documents %}
{% block filter-documents %}
<div class="mb-2 d-flex" hx-target="#doc-table" hx-push-url="true">
<div class="flex-grow-1 me-3">
<input id="filter-input"
hx-get="{{ request.path }}"
hx-trigger="keyup changed delay:300ms"
aria-label="{% trans "Filter documents" %}"
placeholder="{% trans "Filter documents" %}"
class="form-control"
type="text"
name="q"/>
</div>
<div class="me-2 d-flex align-items-center">
<div class="d-none d-md-block me-2 text-nowrap">{% trans "Sort by" %}:</div>
<select class="form-control" hx-get="{{ request.path }}" name="sort">
{% for opt in form.sort %}{{ opt }}{% endfor %}
</select>
</div>
<div>
<button class="btn btn-primary"
hx-get="{{ request.path }}"
type="submit"
value="Filter">Filter</button>
</div>
</div>
</div>
{% endblock %}
{% include 'peachjam/_document_table.html' %}
{% else %}
<p>{% trans 'No documents found.' %}</p>
{% endif %}
{% endblock %}
{% endblock %}
{% include 'peachjam/_document_table.html' %}
{% else %}
<p>{% trans 'No documents found.' %}</p>
{% endif %}
{% endblock %}
</div>
</div>
</div>
</div>
</form>
2 changes: 1 addition & 1 deletion peachjam/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class BaseDocumentFilterFormTestCase(TestCase):
def test_years_filter_with_single_year(self):
response = self.client.get("/legal_instruments/?years=2007")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["facet_data"]["years"], [2007])
self.assertEqual(response.context["facet_data"]["years"]["options"], ["2007"])

def test_alphabet_filter(self):
response = self.client.get("/legal_instruments/?alphabet=a")
Expand Down
7 changes: 4 additions & 3 deletions peachjam/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ def test_legislation_listing(self):
documents,
)
self.assertEqual(
[1969, 2005, 2010, 2020], sorted(response.context["facet_data"]["years"])
["1969", "2005", "2010", "2020"],
sorted(response.context["facet_data"]["years"]["options"]),
)

def test_legislation_detail(self):
Expand All @@ -126,7 +127,7 @@ def test_legal_instrument_listing(self):
"African Charter on Democracy, Elections and Governance",
documents,
)
self.assertEqual(response.context["facet_data"]["years"], [2007])
self.assertEqual(response.context["facet_data"]["years"]["options"], ["2007"])

def test_legal_instrument_detail(self):
response = self.client.get(
Expand All @@ -150,7 +151,7 @@ def test_generic_document_listing(self):
"Activity Report of the Pan-African Parliament, July 2016 to June 2017",
documents,
)
self.assertEqual(response.context["facet_data"]["years"], [2017])
self.assertEqual(response.context["facet_data"]["years"]["options"], ["2017"])

def test_generic_document_detail(self):
response = self.client.get(
Expand Down
9 changes: 8 additions & 1 deletion peachjam/views/generic_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ def __init__(self, title):

return docs

def get_template_names(self):
if self.request.htmx:
if self.request.htmx.target == "doc-table":
return ["peachjam/_document_table.html"]
return ["peachjam/faceted_doc_table.html"]
return super().get_template_names()


class FilteredDocumentListView(DocumentListView):
"""Generic list view for filtered document lists."""
Expand Down Expand Up @@ -115,7 +122,7 @@ def filter_queryset(self, qs):
return self.form.filter_queryset(qs)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context = super().get_context_data(form=self.form, **kwargs)

self.add_facets(context)
context["doc_count"] = context["paginator"].count
Expand Down
Loading