From 7abccc5965fff4b44a12ec3d6f731a1c5bcef56b Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 6 Jan 2025 14:20:00 +0000 Subject: [PATCH 01/18] Amend breadcrumb formatting on Task delete view --- tasks/jinja2/tasks/delete.jinja | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tasks/jinja2/tasks/delete.jinja b/tasks/jinja2/tasks/delete.jinja index 574aa28a5..0de6bacb0 100644 --- a/tasks/jinja2/tasks/delete.jinja +++ b/tasks/jinja2/tasks/delete.jinja @@ -4,7 +4,14 @@ {% from "components/warning-text/macro.njk" import govukWarningText %} {% from "components/button/macro.njk" import govukButton %} -{% set page_title = "Delete my Task:" ~ object.title %} +{% block breadcrumb %} + {{ breadcrumbs(request, [ + {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, + {"text": verbose_name|capitalize ~ ": " ~ object.title, "href": url("workflow:task-ui-detail", kwargs={"pk": object.pk})}, + {"text": page_title} + ]) + }} +{% endblock %} {% block content %}
@@ -30,12 +37,3 @@ {% endblock %}
{% endblock %} - -{% block breadcrumb %} - {{ breadcrumbs(request, [ - {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, - {"text": verbose_name ~ " :" ~ object.title, "href": url("workflow:task-ui-detail", kwargs={"pk": object.pk})}, - {"text": page_title} - ]) - }} -{% endblock %} From f7dd8c9be7dfbae15604c53b566af2473ed5bee4 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 6 Jan 2025 14:32:20 +0000 Subject: [PATCH 02/18] Avoid dereferencing null category on task and workflow list views --- tasks/jinja2/tasks/detail.jinja | 2 +- tasks/jinja2/tasks/list.jinja | 2 +- tasks/jinja2/tasks/workflows/list.jinja | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tasks/jinja2/tasks/detail.jinja b/tasks/jinja2/tasks/detail.jinja index d19cd9dca..a862cb28a 100644 --- a/tasks/jinja2/tasks/detail.jinja +++ b/tasks/jinja2/tasks/detail.jinja @@ -66,7 +66,7 @@ Category
- {{ object.category }} + {{ object.category or "-" }}
Change category diff --git a/tasks/jinja2/tasks/list.jinja b/tasks/jinja2/tasks/list.jinja index f516e5ca1..9fffe407e 100644 --- a/tasks/jinja2/tasks/list.jinja +++ b/tasks/jinja2/tasks/list.jinja @@ -50,7 +50,7 @@ {{ table_rows.append([ {"text": task_linked_id}, {"text": object.title}, - {"text": object.category}, + {"text": object.category or "-"}, {"text": object.progress_state}, {"text": workbasket_linked_id}, {"text": "{:%d %b %Y}".format(object.created_at)}, diff --git a/tasks/jinja2/tasks/workflows/list.jinja b/tasks/jinja2/tasks/workflows/list.jinja index fd76656f0..0fac5a865 100644 --- a/tasks/jinja2/tasks/workflows/list.jinja +++ b/tasks/jinja2/tasks/workflows/list.jinja @@ -53,7 +53,7 @@ {{ table_rows.append([ {"text": task_linked_id}, {"text": object.title}, - {"text": object.category}, + {"text": object.category or "-"}, {"text": object.progress_state}, {"text": workbasket_linked_id}, {"text": "{:%d %b %Y}".format(object.created_at)}, From 9081e2d9ecbd322faa3e89c558b579e0b4675869 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 6 Jan 2025 16:07:20 +0000 Subject: [PATCH 03/18] Add parent task breadcrumb on subtask create view --- tasks/jinja2/tasks/create.jinja | 22 ++++++++++++++++++++++ tasks/views.py | 14 +++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 tasks/jinja2/tasks/create.jinja diff --git a/tasks/jinja2/tasks/create.jinja b/tasks/jinja2/tasks/create.jinja new file mode 100644 index 000000000..8e4f04f56 --- /dev/null +++ b/tasks/jinja2/tasks/create.jinja @@ -0,0 +1,22 @@ +{% extends 'layouts/form.jinja' %} + +{% block breadcrumb %} + {% if parent_task %} + {{ breadcrumbs(request, [ + {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, + {"text": "Task: " ~ parent_task.title, "href": parent_task.get_url("detail")}, + {"text": page_title} + ])}} + {% else %} + {{ breadcrumbs(request, [ + {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, + {"text": page_title} + ])}} + {% endif %} +{% endblock %} + +{% block form %} + {% call django_form() %} + {{ crispy(form) }} + {% endcall %} +{% endblock %} diff --git a/tasks/views.py b/tasks/views.py index 4df9a8517..cb9a25f92 100644 --- a/tasks/views.py +++ b/tasks/views.py @@ -68,7 +68,7 @@ class TaskDetailView(PermissionRequiredMixin, DetailView): class TaskCreateView(PermissionRequiredMixin, CreateView): model = Task - template_name = "layouts/create.jinja" + template_name = "tasks/create.jinja" permission_required = "tasks.add_task" form_class = TaskCreateForm @@ -163,27 +163,31 @@ def get_context_data(self, **kwargs): class SubTaskCreateView(PermissionRequiredMixin, CreateView): model = Task - template_name = "layouts/create.jinja" + template_name = "tasks/create.jinja" permission_required = "tasks.add_task" form_class = SubTaskCreateForm + @property + def parent_task(self) -> Task: + return Task.objects.get(pk=self.kwargs["parent_task_pk"]) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["page_title"] = ( f"Create a subtask for task {self.kwargs['parent_task_pk']}" ) + context["parent_task"] = self.parent_task return context def form_valid(self, form): - parent_task = Task.objects.filter(pk=self.kwargs["parent_task_pk"]).first() - if parent_task.parent_task: + if self.parent_task.parent_task: form.add_error( None, "You cannot make a subtask from a subtask.", ) return self.form_invalid(form) else: - self.object = form.save(parent_task, user=self.request.user) + self.object = form.save(self.parent_task, user=self.request.user) return HttpResponseRedirect(self.get_success_url()) def get_success_url(self): From 1d2aeb6b79d641ad6fee69b7ff4dbcbc1a7b5c97 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 6 Jan 2025 16:15:46 +0000 Subject: [PATCH 04/18] Amend workflow and worklfow template name references on their respective list views --- tasks/jinja2/tasks/workflows/list.jinja | 2 +- tasks/jinja2/tasks/workflows/template_list.jinja | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tasks/jinja2/tasks/workflows/list.jinja b/tasks/jinja2/tasks/workflows/list.jinja index 0fac5a865..6b45f249e 100644 --- a/tasks/jinja2/tasks/workflows/list.jinja +++ b/tasks/jinja2/tasks/workflows/list.jinja @@ -3,7 +3,7 @@ {% from "components/table/macro.njk" import govukTable %} {% from "components/create_sortable_anchor.jinja" import create_sortable_anchor %} -{% set page_title = "Find and view tasks workflows" %} +{% set page_title = "Find and view workflows" %} {% set base_url = url("workflow:task-workflow-ui-list") %} diff --git a/tasks/jinja2/tasks/workflows/template_list.jinja b/tasks/jinja2/tasks/workflows/template_list.jinja index 3be85f30e..65a58dfcd 100644 --- a/tasks/jinja2/tasks/workflows/template_list.jinja +++ b/tasks/jinja2/tasks/workflows/template_list.jinja @@ -3,15 +3,15 @@ {% from "components/table/macro.njk" import govukTable %} {% from "components/create_sortable_anchor.jinja" import create_sortable_anchor %} -{% set page_title = "Find and view task workflow templates" %} +{% set page_title = "Find and view workflow templates" %} {% set base_url = url("workflow:task-workflow-template-ui-list") %} {% block content %}

{{ page_title }}

- Search for task workflow templates. - Alternatively, create a new task workflow template. + Search for workflow templates. + Alternatively, create a new workflow template.

From 46b49fe02986f6342e2c49ed9dc607eaa48167e5 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 6 Jan 2025 16:23:07 +0000 Subject: [PATCH 05/18] Add a return to workflow template button on task template confirm create view --- .../jinja2/tasks/workflows/task_template_confirm_create.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/jinja2/tasks/workflows/task_template_confirm_create.jinja b/tasks/jinja2/tasks/workflows/task_template_confirm_create.jinja index 0c532419c..e3dcac8b0 100644 --- a/tasks/jinja2/tasks/workflows/task_template_confirm_create.jinja +++ b/tasks/jinja2/tasks/workflows/task_template_confirm_create.jinja @@ -42,8 +42,8 @@ "classes": "govuk-button" }) }} {{ govukButton({ - "text": "Return to homepage", - "href": url("home"), + "text": "Return to workflow template", + "href": url("workflow:task-workflow-template-ui-detail", kwargs={"pk": task_workflow_template.pk}), "classes": "govuk-button--secondary" }) }} {% endblock %} From 879a9d1f8bb0888bdfa731722a0fb80e02986750 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 6 Jan 2025 16:25:03 +0000 Subject: [PATCH 06/18] Truncate long descriptions on workflow template list view --- tasks/jinja2/tasks/workflows/template_list.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/jinja2/tasks/workflows/template_list.jinja b/tasks/jinja2/tasks/workflows/template_list.jinja index 65a58dfcd..24ce7c322 100644 --- a/tasks/jinja2/tasks/workflows/template_list.jinja +++ b/tasks/jinja2/tasks/workflows/template_list.jinja @@ -39,7 +39,7 @@ {{ table_rows.append([ {"text": workflow_template_linked_id}, {"text": object.title}, - {"text": object.description}, + {"text": object.description|truncate(75)}, {"text": object.creator.get_displayname() if object.creator else "Unknown"}, {"text": object.created_at.strftime(datetime_format)}, {"text": object.updated_at.strftime(datetime_format)}, From 227985937eddc62d94ca45baa6588b6471dadf38 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 6 Jan 2025 16:31:30 +0000 Subject: [PATCH 07/18] Use sentence case for table column headers on workflow template list view --- tasks/jinja2/tasks/workflows/template_list.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/jinja2/tasks/workflows/template_list.jinja b/tasks/jinja2/tasks/workflows/template_list.jinja index 24ce7c322..c1fed929e 100644 --- a/tasks/jinja2/tasks/workflows/template_list.jinja +++ b/tasks/jinja2/tasks/workflows/template_list.jinja @@ -53,7 +53,7 @@ {"text": "Description"}, {"text": "Created by"}, {"text": create_sortable_anchor(request, "created_at", "Created", base_url)}, - {"text": create_sortable_anchor(request, "updated_at", "Last Updated", base_url)}, + {"text": create_sortable_anchor(request, "updated_at", "Last updated", base_url)}, ], "rows": table_rows }) }} From da678ed60af07478e6fc3c0de37ffa38dce76a72 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Thu, 9 Jan 2025 15:17:42 +0000 Subject: [PATCH 08/18] Show associated workbasket on Task detail view --- tasks/jinja2/tasks/detail.jinja | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tasks/jinja2/tasks/detail.jinja b/tasks/jinja2/tasks/detail.jinja index a862cb28a..be0d52123 100644 --- a/tasks/jinja2/tasks/detail.jinja +++ b/tasks/jinja2/tasks/detail.jinja @@ -10,6 +10,17 @@ {% set edit_url = url("workflow:task-ui-update", kwargs={"pk": object.pk}) %} {% endif%} +{% set workbasket_linked_id %} + {% if object.workbasket -%} + {{ object.workbasket.pk }} + {% else %} + - + {% endif -%} +{% endset %} + {% block breadcrumb %} {{ breadcrumbs(request, [ {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, @@ -85,6 +96,18 @@
+
+
+ Workbasket +
+
+ {{ workbasket_linked_id }} +
+
+ Change status +
+
+
Created From c597eb70178c324913ee59c672d7f4ae014f9770 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Thu, 9 Jan 2025 19:14:34 +0000 Subject: [PATCH 09/18] Preserve filtering when sorting on all Task & Workflow list views --- .../components/create_sortable_anchor.jinja | 16 ++++++------ common/views/mixins.py | 9 +++++++ tasks/jinja2/tasks/list.jinja | 4 +-- tasks/jinja2/tasks/workflows/list.jinja | 4 +-- .../workflows/task-and-workflow-list.jinja | 6 ++--- .../tasks/workflows/template_list.jinja | 6 ++--- tasks/views.py | 26 +++++++++++++++++-- 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/common/jinja2/components/create_sortable_anchor.jinja b/common/jinja2/components/create_sortable_anchor.jinja index b83f591dc..fb0e251ff 100644 --- a/common/jinja2/components/create_sortable_anchor.jinja +++ b/common/jinja2/components/create_sortable_anchor.jinja @@ -1,21 +1,21 @@ {% macro create_sortable_anchor(request, sort_by, title, base_url, query_params=False, fragment="") %} - + {% set query_string_prefix = "" %} {% if query_params %} - {% set query_string_prefix = "&"%} + {% if not base_url.endswith("?") %} + {% set query_string_prefix = "&" %} + {% endif %} {% else %} {% set query_string_prefix = "?"%} {% endif %} {% if request.GET.sort_by == sort_by and request.GET.ordered == "desc" %} - - - {{ title }} - + + {{ title }} + {% else %} - + {{ title }} {% endif %} - {% endmacro %} diff --git a/common/views/mixins.py b/common/views/mixins.py index 6cfff811e..3b7169638 100644 --- a/common/views/mixins.py +++ b/common/views/mixins.py @@ -8,6 +8,7 @@ from django.db.models import Model from django.db.models import QuerySet from django.http import Http404 +from django.http import QueryDict from common.business_rules import BusinessRule from common.business_rules import BusinessRuleViolation @@ -162,3 +163,11 @@ def get_ordering(self): else: return None + + def clean_query_params(self) -> QueryDict: + """Returns a cleaned copy of query parameters having removed 'sort_by' + and 'ordered'.""" + query_params = self.request.GET.copy() + query_params.pop("sort_by", None) + query_params.pop("ordered", None) + return query_params diff --git a/tasks/jinja2/tasks/list.jinja b/tasks/jinja2/tasks/list.jinja index 9fffe407e..6fd286f4b 100644 --- a/tasks/jinja2/tasks/list.jinja +++ b/tasks/jinja2/tasks/list.jinja @@ -5,8 +5,6 @@ {% set page_title = "Find and view tasks" %} -{% set base_url = url("workflow:task-ui-list") %} - {% block content %}

{{ page_title }}

@@ -64,7 +62,7 @@ {"text": "Category"}, {"text": "Status"}, {"text": "Workbasket"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url)}, + {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, ], "rows": table_rows }) }} diff --git a/tasks/jinja2/tasks/workflows/list.jinja b/tasks/jinja2/tasks/workflows/list.jinja index 6b45f249e..2ab14299f 100644 --- a/tasks/jinja2/tasks/workflows/list.jinja +++ b/tasks/jinja2/tasks/workflows/list.jinja @@ -5,8 +5,6 @@ {% set page_title = "Find and view workflows" %} -{% set base_url = url("workflow:task-workflow-ui-list") %} - {% block content %}

{{ page_title }}

@@ -67,7 +65,7 @@ {"text": "Category"}, {"text": "Status"}, {"text": "Workbasket"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url)}, + {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, ], "rows": table_rows }) }} diff --git a/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja b/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja index e0e5339ae..c9cd7e340 100644 --- a/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja +++ b/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja @@ -5,8 +5,6 @@ {% set page_title = "Find and view tasks and workflows" %} -{% set base_url = url("workflow:task-and-workflow-ui-list") %} - {% block content %}

{{ page_title }}

@@ -20,7 +18,7 @@

Search and filter

-
+ {{ crispy(filter.form) }}
@@ -86,7 +84,7 @@ {"text": "Category"}, {"text": "Status"}, {"text": "Workbasket"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url)}, + {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, ], "rows": table_rows }) }} diff --git a/tasks/jinja2/tasks/workflows/template_list.jinja b/tasks/jinja2/tasks/workflows/template_list.jinja index c1fed929e..0df225ebd 100644 --- a/tasks/jinja2/tasks/workflows/template_list.jinja +++ b/tasks/jinja2/tasks/workflows/template_list.jinja @@ -5,8 +5,6 @@ {% set page_title = "Find and view workflow templates" %} -{% set base_url = url("workflow:task-workflow-template-ui-list") %} - {% block content %}

{{ page_title }}

@@ -52,8 +50,8 @@ {"text": "Title"}, {"text": "Description"}, {"text": "Created by"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url)}, - {"text": create_sortable_anchor(request, "updated_at", "Last updated", base_url)}, + {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, + {"text": create_sortable_anchor(request, "updated_at", "Last updated", base_url, query_params=True)}, ], "rows": table_rows }) }} diff --git a/tasks/views.py b/tasks/views.py index cb9a25f92..b41db7c28 100644 --- a/tasks/views.py +++ b/tasks/views.py @@ -59,6 +59,13 @@ def get_queryset(self): queryset = queryset.order_by(*ordering) return queryset + def get_context_data(self, *, object_list=None, **kwargs): + context = super().get_context_data(object_list=object_list, **kwargs) + context["base_url"] = ( + f"{reverse("workflow:task-ui-list")}?{self.clean_query_params().urlencode()}" + ) + return context + class TaskDetailView(PermissionRequiredMixin, DetailView): model = Task @@ -298,6 +305,13 @@ def get_queryset(self): queryset = queryset.order_by(*ordering) return queryset + def get_context_data(self, *, object_list=None, **kwargs): + context = super().get_context_data(object_list=object_list, **kwargs) + context["base_url"] = ( + f"{reverse("workflow:task-workflow-ui-list")}?{self.clean_query_params().urlencode()}" + ) + return context + class TaskAndWorkflowListView( PermissionRequiredMixin, @@ -319,6 +333,13 @@ def get_queryset(self): queryset = queryset.order_by(*ordering) return queryset + def get_context_data(self, *, object_list=None, **kwargs): + context = super().get_context_data(object_list=object_list, **kwargs) + context["base_url"] = ( + f"{reverse("workflow:task-and-workflow-ui-list")}?{self.clean_query_params().urlencode()}" + ) + return context + class TaskWorkflowTemplateListView( PermissionRequiredMixin, @@ -334,9 +355,10 @@ class TaskWorkflowTemplateListView( def get_context_data(self, **kwargs) -> dict: context_data = super().get_context_data(**kwargs) - context_data["datetime_format"] = settings.DATETIME_FORMAT - + context_data["base_url"] = ( + f"{reverse("workflow:task-workflow-template-ui-list")}?{self.clean_query_params().urlencode()}" + ) return context_data def get_queryset(self): From 624cb5c1135124e2650ff76f9606a039f637cfb7 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Fri, 10 Jan 2025 09:30:20 +0000 Subject: [PATCH 10/18] Add page caption and link to parent task for Subtask detail views --- tasks/jinja2/tasks/detail.jinja | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tasks/jinja2/tasks/detail.jinja b/tasks/jinja2/tasks/detail.jinja index be0d52123..8fc47af7b 100644 --- a/tasks/jinja2/tasks/detail.jinja +++ b/tasks/jinja2/tasks/detail.jinja @@ -4,11 +4,25 @@ {% set page_title = "Task: " ~ object.title %} -{%if object.parent_task%} +{% if object.parent_task %} {% set edit_url = url("workflow:subtask-ui-update", kwargs={"pk": object.pk}) %} + {% set title_caption = "Subtask" %} + {% set parent_linked_id %} +

+
+ Parent task +
+
+ {{ object.parent_task.pk }} +
+
+ {% endset %} {% else %} {% set edit_url = url("workflow:task-ui-update", kwargs={"pk": object.pk}) %} -{% endif%} +{% endif %} {% set workbasket_linked_id %} {% if object.workbasket -%} @@ -32,6 +46,13 @@ {% block content %}
+ {% if title_caption %} + {% block page_subtitle%} + + {{ title_caption }} + + {% endblock %} + {% endif %}

{{ page_title }}

@@ -108,6 +129,10 @@ + {% if object.parent_task %} + {{ parent_linked_id }} + {% endif %} +
Created From ee55603d8640e9206ad812b8566e3511c7a1ed82 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Fri, 10 Jan 2025 09:48:04 +0000 Subject: [PATCH 11/18] Add a return to workflow template button on task template detail view --- tasks/jinja2/tasks/workflows/task_template_detail.jinja | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tasks/jinja2/tasks/workflows/task_template_detail.jinja b/tasks/jinja2/tasks/workflows/task_template_detail.jinja index f42ff3f41..286cd9ad5 100644 --- a/tasks/jinja2/tasks/workflows/task_template_detail.jinja +++ b/tasks/jinja2/tasks/workflows/task_template_detail.jinja @@ -68,5 +68,10 @@ "classes": "govuk-button--warning" }) }} + {{ govukButton({ + "text": "Return to workflow template", + "href": url("workflow:task-workflow-template-ui-detail", kwargs={"pk": task_workflow_template.pk}), + "classes": "govuk-button--secondary" + }) }}
{% endblock %} From 4420588680bef4d94fdf06f54e75d637a2a3e73f Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Fri, 10 Jan 2025 10:54:38 +0000 Subject: [PATCH 12/18] Remove workbasket breadcrumb from task and workflow views --- tasks/jinja2/tasks/create.jinja | 18 +++++++++++------- tasks/jinja2/tasks/detail.jinja | 3 ++- tasks/jinja2/tasks/edit.jinja | 5 +++-- tasks/jinja2/tasks/list.jinja | 8 ++++++++ tasks/jinja2/tasks/workflows/list.jinja | 8 ++++++++ .../workflows/task-and-workflow-list.jinja | 8 ++++++++ .../jinja2/tasks/workflows/template_list.jinja | 8 ++++++++ 7 files changed, 48 insertions(+), 10 deletions(-) diff --git a/tasks/jinja2/tasks/create.jinja b/tasks/jinja2/tasks/create.jinja index 8e4f04f56..2e25bdbaf 100644 --- a/tasks/jinja2/tasks/create.jinja +++ b/tasks/jinja2/tasks/create.jinja @@ -3,15 +3,19 @@ {% block breadcrumb %} {% if parent_task %} {{ breadcrumbs(request, [ - {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, - {"text": "Task: " ~ parent_task.title, "href": parent_task.get_url("detail")}, - {"text": page_title} - ])}} + {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, + {"text": "Task: " ~ parent_task.title, "href": parent_task.get_url("detail")}, + {"text": page_title} + ], + with_workbasket=False, + ) }} {% else %} {{ breadcrumbs(request, [ - {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, - {"text": page_title} - ])}} + {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, + {"text": page_title} + ], + with_workbasket=False, + ) }} {% endif %} {% endblock %} diff --git a/tasks/jinja2/tasks/detail.jinja b/tasks/jinja2/tasks/detail.jinja index 8fc47af7b..5721050c7 100644 --- a/tasks/jinja2/tasks/detail.jinja +++ b/tasks/jinja2/tasks/detail.jinja @@ -39,7 +39,8 @@ {{ breadcrumbs(request, [ {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, {"text": page_title} - ] + ], + with_workbasket=False, ) }} {% endblock %} diff --git a/tasks/jinja2/tasks/edit.jinja b/tasks/jinja2/tasks/edit.jinja index d2d0bde91..0f8ebe1ee 100644 --- a/tasks/jinja2/tasks/edit.jinja +++ b/tasks/jinja2/tasks/edit.jinja @@ -7,8 +7,9 @@ {"text": "Find and view tasks", "href": url("workflow:task-ui-list")}, {"text": "Task: " ~ object.title, "href": url("workflow:task-ui-detail", kwargs={"pk": object.pk})}, {"text": page_title} - ]) - }} + ], + with_workbasket=False, + ) }} {% endblock %} {% block form %} diff --git a/tasks/jinja2/tasks/list.jinja b/tasks/jinja2/tasks/list.jinja index 6fd286f4b..9f057378e 100644 --- a/tasks/jinja2/tasks/list.jinja +++ b/tasks/jinja2/tasks/list.jinja @@ -5,6 +5,14 @@ {% set page_title = "Find and view tasks" %} +{% block breadcrumb %} + {{ breadcrumbs(request, [ + {"text": page_title} + ], + with_workbasket=False, + ) }} +{% endblock %} + {% block content %}

{{ page_title }}

diff --git a/tasks/jinja2/tasks/workflows/list.jinja b/tasks/jinja2/tasks/workflows/list.jinja index 2ab14299f..3bccce156 100644 --- a/tasks/jinja2/tasks/workflows/list.jinja +++ b/tasks/jinja2/tasks/workflows/list.jinja @@ -5,6 +5,14 @@ {% set page_title = "Find and view workflows" %} +{% block breadcrumb %} + {{ breadcrumbs(request, [ + {"text": page_title} + ], + with_workbasket=False, + ) }} +{% endblock %} + {% block content %}

{{ page_title }}

diff --git a/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja b/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja index c9cd7e340..3efa64339 100644 --- a/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja +++ b/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja @@ -5,6 +5,14 @@ {% set page_title = "Find and view tasks and workflows" %} +{% block breadcrumb %} + {{ breadcrumbs(request, [ + {"text": page_title} + ], + with_workbasket=False, + ) }} +{% endblock %} + {% block content %}

{{ page_title }}

diff --git a/tasks/jinja2/tasks/workflows/template_list.jinja b/tasks/jinja2/tasks/workflows/template_list.jinja index 0df225ebd..56276cad2 100644 --- a/tasks/jinja2/tasks/workflows/template_list.jinja +++ b/tasks/jinja2/tasks/workflows/template_list.jinja @@ -5,6 +5,14 @@ {% set page_title = "Find and view workflow templates" %} +{% block breadcrumb %} + {{ breadcrumbs(request, [ + {"text": page_title} + ], + with_workbasket=False, + ) }} +{% endblock %} + {% block content %}

{{ page_title }}

From 4fe4f89a3029d706e7af375a8169ddb914d6dca3 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Fri, 7 Feb 2025 12:39:28 +0000 Subject: [PATCH 13/18] Rename SortingMixin.clean_query_params() --- common/views/mixins.py | 6 +++--- tasks/views.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/views/mixins.py b/common/views/mixins.py index 3b7169638..81a790409 100644 --- a/common/views/mixins.py +++ b/common/views/mixins.py @@ -164,9 +164,9 @@ def get_ordering(self): else: return None - def clean_query_params(self) -> QueryDict: - """Returns a cleaned copy of query parameters having removed 'sort_by' - and 'ordered'.""" + def remove_sorting_params(self) -> QueryDict: + """Returns a cleaned copy of GET params having removed 'sort_by' and + 'ordered'.""" query_params = self.request.GET.copy() query_params.pop("sort_by", None) query_params.pop("ordered", None) diff --git a/tasks/views.py b/tasks/views.py index b41db7c28..ab450dd73 100644 --- a/tasks/views.py +++ b/tasks/views.py @@ -62,7 +62,7 @@ def get_queryset(self): def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) context["base_url"] = ( - f"{reverse("workflow:task-ui-list")}?{self.clean_query_params().urlencode()}" + f"{reverse("workflow:task-ui-list")}?{self.remove_sorting_params().urlencode()}" ) return context @@ -308,7 +308,7 @@ def get_queryset(self): def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) context["base_url"] = ( - f"{reverse("workflow:task-workflow-ui-list")}?{self.clean_query_params().urlencode()}" + f"{reverse("workflow:task-workflow-ui-list")}?{self.remove_sorting_params().urlencode()}" ) return context @@ -336,7 +336,7 @@ def get_queryset(self): def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) context["base_url"] = ( - f"{reverse("workflow:task-and-workflow-ui-list")}?{self.clean_query_params().urlencode()}" + f"{reverse("workflow:task-and-workflow-ui-list")}?{self.remove_sorting_params().urlencode()}" ) return context @@ -357,7 +357,7 @@ def get_context_data(self, **kwargs) -> dict: context_data = super().get_context_data(**kwargs) context_data["datetime_format"] = settings.DATETIME_FORMAT context_data["base_url"] = ( - f"{reverse("workflow:task-workflow-template-ui-list")}?{self.clean_query_params().urlencode()}" + f"{reverse("workflow:task-workflow-template-ui-list")}?{self.remove_sorting_params().urlencode()}" ) return context_data From e53ec9c7ff66cd100e7069285cc271989bfcf2bd Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Fri, 7 Feb 2025 12:42:32 +0000 Subject: [PATCH 14/18] Add util function to get resolved URL of current view --- common/util.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/common/util.py b/common/util.py index aef0adf8f..2f3539872 100644 --- a/common/util.py +++ b/common/util.py @@ -47,7 +47,9 @@ from django.db.models.functions.text import Lower from django.db.models.functions.text import Upper from django.db.transaction import atomic +from django.http import HttpRequest from django.template import loader +from django.urls import reverse from django.utils import timezone from lxml import etree from psycopg.types.range import DateRange @@ -809,3 +811,11 @@ def get_related_names(instance, related_model) -> list[str]: if field.one_to_many and issubclass(field.related_model, related_model): related_names.append(field.get_accessor_name()) return related_names + + +def get_current_view_url(request: HttpRequest) -> str: + """Returns the resolved URL of the current view.""" + view_name = request.resolver_match.view_name + args = request.resolver_match.args + kwargs = request.resolver_match.kwargs + return reverse(view_name, args=args, kwargs=kwargs) From 46c7b7d6c290df92451b57f802efabde731d11b5 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 10 Feb 2025 20:56:37 +0000 Subject: [PATCH 15/18] Add capability to SortingMixin to build sorting URLs --- common/views/mixins.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/common/views/mixins.py b/common/views/mixins.py index 81a790409..11581c534 100644 --- a/common/views/mixins.py +++ b/common/views/mixins.py @@ -14,6 +14,7 @@ from common.business_rules import BusinessRuleViolation from common.models import TrackedModel from common.pagination import build_pagination_list +from common.util import get_current_view_url class WithPaginationListMixin: @@ -171,3 +172,33 @@ def remove_sorting_params(self) -> QueryDict: query_params.pop("sort_by", None) query_params.pop("ordered", None) return query_params + + def build_sorting_urls(self) -> dict[str, str]: + """ + Returns a dictionary mapping a sort_by_field to its sorting URL. + + Appends `sort_by` and `ordered` query params to the current view URL for each field in `sort_by_fields`, + while keeping other query params (such as those used for filtering) in place. + """ + urls = {} + view_url = get_current_view_url(self.request) + query_params = self.remove_sorting_params().urlencode() + ordering = self.get_ordering() + + for sort_by in self.sort_by_fields: + if ordering and ordering.startswith("-"): + sorting_params = f"sort_by={sort_by}&ordered=asc" + else: + sorting_params = f"sort_by={sort_by}&ordered=desc" + urls[sort_by] = ( + f"{view_url}?{query_params}&{sorting_params}" + if query_params + else f"{view_url}?{sorting_params}" + ) + + return urls + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["sorting_urls"] = self.build_sorting_urls() + return context From 86b9702cbc6d165cbb23c6e7f962ba70923c2ebd Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Mon, 10 Feb 2025 21:05:38 +0000 Subject: [PATCH 16/18] Update usage of create_sortable_anchor --- .../includes/certificates/tabs/measures.jinja | 8 ++--- certificates/views.py | 1 + .../tabs/measures-declarable.jinja | 10 +++--- .../commodities/tabs/measures-defined.jinja | 8 ++--- .../components/create_sortable_anchor.jinja | 18 +++------- .../includes/footnotes/tabs/measures.jinja | 8 ++--- footnotes/views.py | 1 + .../includes/geo_areas/tabs/measures.jinja | 6 ++-- geo_areas/views.py | 1 + measures/jinja2/includes/measures/list.jinja | 10 +++--- measures/views/search.py | 15 +------- .../includes/quotas/tabs/measures.jinja | 4 +-- quotas/jinja2/quotas/definitions.jinja | 1 - quotas/jinja2/quotas/tables/definitions.jinja | 4 +-- quotas/views/base.py | 2 +- .../includes/regulations/tabs/measures.jinja | 8 ++--- regulations/views.py | 1 + tasks/jinja2/tasks/list.jinja | 2 +- tasks/jinja2/tasks/workflows/list.jinja | 2 +- .../workflows/task-and-workflow-list.jinja | 2 +- .../tasks/workflows/template_list.jinja | 4 +-- tasks/views.py | 12 ------- .../workbaskets/auto_end_date_measures.jinja | 8 ++--- workbaskets/jinja2/workbaskets/changes.jinja | 8 ++--- .../workbaskets/checks/missing_measures.jinja | 4 +-- .../workbaskets/summary-workbasket.jinja | 4 +-- .../jinja2/workbaskets/violations.jinja | 8 ++--- workbaskets/views/ui.py | 34 +++++++++---------- 28 files changed, 69 insertions(+), 125 deletions(-) diff --git a/certificates/jinja2/includes/certificates/tabs/measures.jinja b/certificates/jinja2/includes/certificates/tabs/measures.jinja index ddca45753..f8e2f7ea2 100644 --- a/certificates/jinja2/includes/certificates/tabs/measures.jinja +++ b/certificates/jinja2/includes/certificates/tabs/measures.jinja @@ -44,18 +44,16 @@ ]) or "" }} {% endfor %} - {% set base_url = url('certificate-ui-detail-measures', kwargs={"certificate_type__sid":object.certificate_type.sid, "sid":object.sid}) %} - {% set commodity_code %} - {{ create_sortable_anchor(request, "goods_nomenclature", "Commodity code", base_url) }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["goods_nomenclature"]) }} {% endset %} {% set geo_area %} - {{ create_sortable_anchor(request, "geo_area", "Geographical area", base_url) }} + {{ create_sortable_anchor(request, "Geographical area", sorting_urls["geo_area"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Start date", base_url) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["start_date"]) }} {% endset %} {% if paginator.count > 0 %} diff --git a/certificates/views.py b/certificates/views.py index a2caf6c4b..fb5b96409 100644 --- a/certificates/views.py +++ b/certificates/views.py @@ -168,6 +168,7 @@ class CertificateDetailMeasures(SortingMixin, WithPaginationListMixin, ListView) paginate_by = 20 sort_by_fields = ["goods_nomenclature", "geo_area", "start_date"] custom_sorting = { + "goods_nomenclature": "goods_nomenclature__item_id", "geo_area": "geographical_area__area_id", "start_date": "valid_between", } diff --git a/commodities/jinja2/includes/commodities/tabs/measures-declarable.jinja b/commodities/jinja2/includes/commodities/tabs/measures-declarable.jinja index 62a54928a..95eeda96e 100644 --- a/commodities/jinja2/includes/commodities/tabs/measures-declarable.jinja +++ b/commodities/jinja2/includes/commodities/tabs/measures-declarable.jinja @@ -62,22 +62,20 @@ ]) or "" }} {% endfor %} -{% set base_url = url('commodity-ui-detail-measures-declarable', args=[commodity.sid]) %} - {% set comm_code %} - {{ create_sortable_anchor(request, "commodity", "Commodity code", base_url) }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["commodity"]) }} {% endset %} {% set measure_type %} - {{ create_sortable_anchor(request, "measure_type", "Measure type", base_url) }} + {{ create_sortable_anchor(request, "Measure type", sorting_urls["measure_type"]) }} {% endset %} {% set geo_area %} - {{ create_sortable_anchor(request, "geo_area", "Geographical area", base_url) }} + {{ create_sortable_anchor(request, "Geographical area", sorting_urls["geo_area"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Start date", base_url) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["start_date"]) }} {% endset %} {% if paginator.count > 0 %} diff --git a/commodities/jinja2/includes/commodities/tabs/measures-defined.jinja b/commodities/jinja2/includes/commodities/tabs/measures-defined.jinja index 1b0b19ac6..41d379a62 100644 --- a/commodities/jinja2/includes/commodities/tabs/measures-defined.jinja +++ b/commodities/jinja2/includes/commodities/tabs/measures-defined.jinja @@ -56,18 +56,16 @@ ]) or "" }} {% endfor %} -{% set base_url = url('commodity-ui-detail-measures-as-defined', args=[commodity.sid]) %} - {% set measure_type %} - {{ create_sortable_anchor(request, "measure_type", "Measure type", base_url) }} + {{ create_sortable_anchor(request, "Measure type", sorting_urls["measure_type"]) }} {% endset %} {% set geo_area %} - {{ create_sortable_anchor(request, "geo_area", "Geographical area", base_url) }} + {{ create_sortable_anchor(request, "Geographical area", sorting_urls["geo_area"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Start date", base_url) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["start_date"]) }} {% endset %} {% if paginator.count > 0 %} diff --git a/common/jinja2/components/create_sortable_anchor.jinja b/common/jinja2/components/create_sortable_anchor.jinja index fb0e251ff..3db8ae818 100644 --- a/common/jinja2/components/create_sortable_anchor.jinja +++ b/common/jinja2/components/create_sortable_anchor.jinja @@ -1,20 +1,10 @@ - -{% macro create_sortable_anchor(request, sort_by, title, base_url, query_params=False, fragment="") %} - {% set query_string_prefix = "" %} - {% if query_params %} - {% if not base_url.endswith("?") %} - {% set query_string_prefix = "&" %} - {% endif %} - {% else %} - {% set query_string_prefix = "?"%} - {% endif %} - - {% if request.GET.sort_by == sort_by and request.GET.ordered == "desc" %} - +{% macro create_sortable_anchor(request, title, url, fragment="") %} + {% if request.GET.ordered == "desc" %} + {{ title }} {% else %} - + {{ title }} {% endif %} diff --git a/footnotes/jinja2/includes/footnotes/tabs/measures.jinja b/footnotes/jinja2/includes/footnotes/tabs/measures.jinja index 40d0d9e21..36b2fef14 100644 --- a/footnotes/jinja2/includes/footnotes/tabs/measures.jinja +++ b/footnotes/jinja2/includes/footnotes/tabs/measures.jinja @@ -44,18 +44,16 @@ ]) or "" }} {% endfor %} - {% set base_url = url('footnote-ui-detail-measures', kwargs={"footnote_type__footnote_type_id":object.footnote_type.footnote_type_id, "footnote_id":object.footnote_id}) %} - {% set commodity_code %} - {{ create_sortable_anchor(request, "goods_nomenclature", "Commodity code", base_url) }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["goods_nomenclature"]) }} {% endset %} {% set geo_area %} - {{ create_sortable_anchor(request, "geo_area", "Geographical area", base_url) }} + {{ create_sortable_anchor(request, "Geographical area", sorting_urls["geo_area"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Start date", base_url) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["start_date"]) }} {% endset %} {% if paginator.count > 0 %} diff --git a/footnotes/views.py b/footnotes/views.py index 5e701d8f4..add4f964a 100644 --- a/footnotes/views.py +++ b/footnotes/views.py @@ -203,6 +203,7 @@ class FootnoteDetailMeasures(SortingMixin, WithPaginationListMixin, ListView): paginate_by = 20 sort_by_fields = ["goods_nomenclature", "geo_area", "start_date"] custom_sorting = { + "goods_nomenclature": "goods_nomenclature__item_id", "geo_area": "geographical_area__area_id", "start_date": "valid_between", } diff --git a/geo_areas/jinja2/includes/geo_areas/tabs/measures.jinja b/geo_areas/jinja2/includes/geo_areas/tabs/measures.jinja index 4edd73849..c491c78c9 100644 --- a/geo_areas/jinja2/includes/geo_areas/tabs/measures.jinja +++ b/geo_areas/jinja2/includes/geo_areas/tabs/measures.jinja @@ -40,14 +40,12 @@ ]) or "" }} {% endfor %} - {% set base_url = url('geo_area-ui-detail-measures', kwargs={"sid": object.sid}) %} - {% set commodity_code %} - {{ create_sortable_anchor(request, "goods_nomenclature", "Commodity code", base_url) }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["goods_nomenclature"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Start date", base_url) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["start_date"]) }} {% endset %} {% if paginator.count > 0 %} diff --git a/geo_areas/views.py b/geo_areas/views.py index cd17b212e..546caaf78 100644 --- a/geo_areas/views.py +++ b/geo_areas/views.py @@ -148,6 +148,7 @@ class GeoAreaDetailMeasures(SortingMixin, WithPaginationListMixin, ListView): paginate_by = 20 sort_by_fields = ["goods_nomenclature", "start_date"] custom_sorting = { + "goods_nomenclature": "goods_nomenclature__item_id", "start_date": "valid_between", } diff --git a/measures/jinja2/includes/measures/list.jinja b/measures/jinja2/includes/measures/list.jinja index bbb3a31e4..37886c290 100644 --- a/measures/jinja2/includes/measures/list.jinja +++ b/measures/jinja2/includes/measures/list.jinja @@ -13,23 +13,23 @@ {%- endset %} {% set sid %} - {{ create_sortable_anchor(request, "sid", "SID", base_url, query_params) }} + {{ create_sortable_anchor(request, "SID", sorting_urls["sid"]) }} {% endset %} {% set measure_type %} - {{ create_sortable_anchor(request, "measure_type", "Type", base_url, query_params) }} + {{ create_sortable_anchor(request, "Type", sorting_urls["measure_type"]) }} {% endset %} {% set geo_area %} - {{ create_sortable_anchor(request, "geo_area", "Geographical area", base_url, query_params) }} + {{ create_sortable_anchor(request, "Geographical area", sorting_urls["geo_area"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Start date", base_url, query_params) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["start_date"]) }} {% endset %} {% set end_date %} - {{ create_sortable_anchor(request, "end_date", "End date", base_url, query_params) }} + {{ create_sortable_anchor(request, "End date", sorting_urls["end_date"]) }} {% endset %} {# sets out form #} diff --git a/measures/views/search.py b/measures/views/search.py index dec0f6ba2..eeee5bb7b 100644 --- a/measures/views/search.py +++ b/measures/views/search.py @@ -84,16 +84,6 @@ def get_form_kwargs(self): kwargs["objects"] = page.object_list return kwargs - def cleaned_query_params(self): - # Remove the sort_by and ordered params in order to stop them being duplicated in the base url - if "sort_by" and "ordered" in self.filterset.data: - cleaned_filterset = self.filterset.data.copy() - cleaned_filterset.pop("sort_by") - cleaned_filterset.pop("ordered") - return cleaned_filterset - else: - return self.filterset.data - def selected_filter_formatter(self) -> List[List[str]]: """ A function that formats the selected filter choices into nicely written @@ -242,6 +232,7 @@ def get_context_data(self, **kwargs): ), "selected_filter_lists": self.selected_filter_formatter(), "workbasket": self.workbasket, + "sorting_urls": self.build_sorting_urls(), }, ) if context["has_previous_page"]: @@ -253,10 +244,6 @@ def get_context_data(self, **kwargs): pk__in=self.measure_selections, ).values_list("sid", flat=True) - context["query_params"] = True - context["base_url"] = ( - f'{reverse("measure-ui-list")}?{urlencode(self.cleaned_query_params())}' - ) return context def get_initial(self): diff --git a/quotas/jinja2/includes/quotas/tabs/measures.jinja b/quotas/jinja2/includes/quotas/tabs/measures.jinja index 761e6a562..33fabd967 100644 --- a/quotas/jinja2/includes/quotas/tabs/measures.jinja +++ b/quotas/jinja2/includes/quotas/tabs/measures.jinja @@ -16,10 +16,8 @@ ]) or "" }} {% endfor %} -{% set base_url = url('quota-ui-detail', args=[object.sid]) %} - {% set commodity_code %} - {{ create_sortable_anchor(request, "goods_nomenclature", "Commodity code", base_url, "#measures") }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["goods_nomenclature"], "#measures") }} {% endset %}

diff --git a/quotas/jinja2/quotas/definitions.jinja b/quotas/jinja2/quotas/definitions.jinja index 614da2ec4..80974d22e 100644 --- a/quotas/jinja2/quotas/definitions.jinja +++ b/quotas/jinja2/quotas/definitions.jinja @@ -61,7 +61,6 @@ {{ fake_tabs(links) }}
- {% set base_url = url('quota_definition-ui-list', args=[quota.sid] ) %}
{% if quota_type == "blocking_periods" %} {% include "quotas/tables/blocking_periods.jinja" %} diff --git a/quotas/jinja2/quotas/tables/definitions.jinja b/quotas/jinja2/quotas/tables/definitions.jinja index 494a25dca..3f6f48aed 100644 --- a/quotas/jinja2/quotas/tables/definitions.jinja +++ b/quotas/jinja2/quotas/tables/definitions.jinja @@ -65,11 +65,11 @@ {% endfor %} {% set sid %} - {{ create_sortable_anchor(request, "sid", "Quota definition SID", base_url) }} + {{ create_sortable_anchor(request, "Quota definition SID", sorting_urls["sid"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "valid_between", "Start date", base_url) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["valid_between"]) }} {% endset %} {{ govukTable({ diff --git a/quotas/views/base.py b/quotas/views/base.py index 49519047b..0b7891f1a 100644 --- a/quotas/views/base.py +++ b/quotas/views/base.py @@ -190,7 +190,7 @@ class QuotaList(QuotaOrderNumberMixin, TamatoListView): filterset_class = QuotaFilter -class QuotaDetail(QuotaOrderNumberMixin, TrackedModelDetailView, SortingMixin): +class QuotaDetail(QuotaOrderNumberMixin, SortingMixin, TrackedModelDetailView): template_name = "quotas/detail.jinja" sort_by_fields = ["goods_nomenclature"] diff --git a/regulations/jinja2/includes/regulations/tabs/measures.jinja b/regulations/jinja2/includes/regulations/tabs/measures.jinja index 00f24c85a..ffcd52ed9 100644 --- a/regulations/jinja2/includes/regulations/tabs/measures.jinja +++ b/regulations/jinja2/includes/regulations/tabs/measures.jinja @@ -45,18 +45,16 @@ ]) or "" }} {% endfor %} - {% set base_url = url('regulation-ui-detail-measures', kwargs={"role_type": object.role_type, "regulation_id": object.regulation_id}) %} - {% set commodity_code %} - {{ create_sortable_anchor(request, "goods_nomenclature", "Commodity code", base_url) }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["goods_nomenclature"]) }} {% endset %} {% set geo_area %} - {{ create_sortable_anchor(request, "geo_area", "Geographical area", base_url) }} + {{ create_sortable_anchor(request, "Geographical area", sorting_urls["geo_area"]) }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Start date", base_url) }} + {{ create_sortable_anchor(request, "Start date", sorting_urls["start_date"]) }} {% endset %} {% if paginator.count > 0 %} diff --git a/regulations/views.py b/regulations/views.py index 0634d0d8d..0270cf8da 100644 --- a/regulations/views.py +++ b/regulations/views.py @@ -79,6 +79,7 @@ class RegulationDetailMeasures(SortingMixin, WithPaginationListMixin, ListView): paginate_by = 20 sort_by_fields = ["goods_nomenclature", "geo_area", "start_date"] custom_sorting = { + "goods_nomenclature": "goods_nomenclature__item_id", "geo_area": "geographical_area__area_id", "start_date": "valid_between", } diff --git a/tasks/jinja2/tasks/list.jinja b/tasks/jinja2/tasks/list.jinja index 9f057378e..b85fe2a7a 100644 --- a/tasks/jinja2/tasks/list.jinja +++ b/tasks/jinja2/tasks/list.jinja @@ -70,7 +70,7 @@ {"text": "Category"}, {"text": "Status"}, {"text": "Workbasket"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, + {"text": create_sortable_anchor(request, "Created", sorting_urls["created_at"])}, ], "rows": table_rows }) }} diff --git a/tasks/jinja2/tasks/workflows/list.jinja b/tasks/jinja2/tasks/workflows/list.jinja index 3bccce156..18b7a72a9 100644 --- a/tasks/jinja2/tasks/workflows/list.jinja +++ b/tasks/jinja2/tasks/workflows/list.jinja @@ -73,7 +73,7 @@ {"text": "Category"}, {"text": "Status"}, {"text": "Workbasket"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, + {"text": create_sortable_anchor(request, "Created", sorting_urls["created_at"])}, ], "rows": table_rows }) }} diff --git a/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja b/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja index 3efa64339..b9f7f8d1d 100644 --- a/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja +++ b/tasks/jinja2/tasks/workflows/task-and-workflow-list.jinja @@ -92,7 +92,7 @@ {"text": "Category"}, {"text": "Status"}, {"text": "Workbasket"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, + {"text": create_sortable_anchor(request, "Created", sorting_urls["created_at"])}, ], "rows": table_rows }) }} diff --git a/tasks/jinja2/tasks/workflows/template_list.jinja b/tasks/jinja2/tasks/workflows/template_list.jinja index 56276cad2..3900678c5 100644 --- a/tasks/jinja2/tasks/workflows/template_list.jinja +++ b/tasks/jinja2/tasks/workflows/template_list.jinja @@ -58,8 +58,8 @@ {"text": "Title"}, {"text": "Description"}, {"text": "Created by"}, - {"text": create_sortable_anchor(request, "created_at", "Created", base_url, query_params=True)}, - {"text": create_sortable_anchor(request, "updated_at", "Last updated", base_url, query_params=True)}, + {"text": create_sortable_anchor(request, "Created", sorting_urls["created_at"])}, + {"text": create_sortable_anchor(request, "Last updated", sorting_urls["updated_at"])}, ], "rows": table_rows }) }} diff --git a/tasks/views.py b/tasks/views.py index ab450dd73..dcb2a9344 100644 --- a/tasks/views.py +++ b/tasks/views.py @@ -61,9 +61,6 @@ def get_queryset(self): def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) - context["base_url"] = ( - f"{reverse("workflow:task-ui-list")}?{self.remove_sorting_params().urlencode()}" - ) return context @@ -307,9 +304,6 @@ def get_queryset(self): def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) - context["base_url"] = ( - f"{reverse("workflow:task-workflow-ui-list")}?{self.remove_sorting_params().urlencode()}" - ) return context @@ -335,9 +329,6 @@ def get_queryset(self): def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) - context["base_url"] = ( - f"{reverse("workflow:task-and-workflow-ui-list")}?{self.remove_sorting_params().urlencode()}" - ) return context @@ -356,9 +347,6 @@ class TaskWorkflowTemplateListView( def get_context_data(self, **kwargs) -> dict: context_data = super().get_context_data(**kwargs) context_data["datetime_format"] = settings.DATETIME_FORMAT - context_data["base_url"] = ( - f"{reverse("workflow:task-workflow-template-ui-list")}?{self.remove_sorting_params().urlencode()}" - ) return context_data def get_queryset(self): diff --git a/workbaskets/jinja2/includes/workbaskets/auto_end_date_measures.jinja b/workbaskets/jinja2/includes/workbaskets/auto_end_date_measures.jinja index d9e81311b..bcf27a4db 100644 --- a/workbaskets/jinja2/includes/workbaskets/auto_end_date_measures.jinja +++ b/workbaskets/jinja2/includes/workbaskets/auto_end_date_measures.jinja @@ -29,18 +29,16 @@ ]) or "" }} {% endfor %} - {% set base_url = url('workbaskets:workbasket-ui-auto-end-date-measures') %} - {% set commodity_code %} - {{ create_sortable_anchor(request, "goods_nomenclature", "Commodity code", base_url) }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["goods_nomenclature"], "#measures") }} {% endset %} {% set start_date %} - {{ create_sortable_anchor(request, "start_date", "Measure start date", base_url) }} + {{ create_sortable_anchor(request, "Measure start date", sorting_urls["start_date"], "#measures") }} {% endset %} {% set measure_sid %} - {{ create_sortable_anchor(request, "sid", "Measure SID", base_url) }} + {{ create_sortable_anchor(request, "Measure SID", sorting_urls["sid"], "#measures") }} {% endset %} {% if object_list %} diff --git a/workbaskets/jinja2/workbaskets/changes.jinja b/workbaskets/jinja2/workbaskets/changes.jinja index 96cbca35c..4fd4c401e 100644 --- a/workbaskets/jinja2/workbaskets/changes.jinja +++ b/workbaskets/jinja2/workbaskets/changes.jinja @@ -6,18 +6,16 @@ {% from "includes/workbaskets/navigation.jinja" import create_workbasket_detail_navigation with context %} {% from "macros/checkbox_item.jinja" import checkbox_item %} -{% set base_url = url("workbaskets:workbasket-ui-changes", args=[workbasket.pk]) ~ "?page=" ~ page_obj.number %} - {% set component %} - {{ create_sortable_anchor(request, "component", "Item", base_url, True) }} + {{ create_sortable_anchor(request, "Item", sorting_urls["component"]) }} {% endset %} {% set action %} - {{ create_sortable_anchor(request, "action", "Action", base_url, True) }} + {{ create_sortable_anchor(request, "Action", sorting_urls["action"]) }} {% endset %} {% set activity_date %} - {{ create_sortable_anchor(request, "activity_date", "Activity date", base_url, True) }} + {{ create_sortable_anchor(request, "Activity date", sorting_urls["activity_date"]) }} {% endset %} {% set page_title %} Workbasket {{ workbasket.id }} - {{ workbasket.status }} {% endset %} diff --git a/workbaskets/jinja2/workbaskets/checks/missing_measures.jinja b/workbaskets/jinja2/workbaskets/checks/missing_measures.jinja index ccc16843e..95abc7365 100644 --- a/workbaskets/jinja2/workbaskets/checks/missing_measures.jinja +++ b/workbaskets/jinja2/workbaskets/checks/missing_measures.jinja @@ -105,10 +105,8 @@
- {% set base_url = url("workbaskets:workbasket-ui-missing-measures-check") %} - {% set commodity_code %} - {{ create_sortable_anchor(request, "commodity", "Commodity code", base_url) }} + {{ create_sortable_anchor(request, "Commodity code", sorting_urls["commodity"]) }} {% endset %} {% set table_rows = [] %} diff --git a/workbaskets/jinja2/workbaskets/summary-workbasket.jinja b/workbaskets/jinja2/workbaskets/summary-workbasket.jinja index 8d54bf4f9..1cc5ad09f 100644 --- a/workbaskets/jinja2/workbaskets/summary-workbasket.jinja +++ b/workbaskets/jinja2/workbaskets/summary-workbasket.jinja @@ -15,8 +15,6 @@ {% set assign_users_link = url("workbaskets:workbasket-ui-assign-users", kwargs={"pk": workbasket.pk}) %} {% set unassign_users_link = url("workbaskets:workbasket-ui-unassign-users", kwargs={"pk": workbasket.pk}) %} -{% set base_url = url("workbaskets:current-workbasket") ~ "?page=" ~ page_obj.number %} - {% macro display_assigned_users(assigned_users, assignment_type) %} {% if not assigned_users and assignment_type == "workers" %} No users have been assigned to this workbasket yet. @@ -164,7 +162,7 @@ {% if comments %}
- Sort by {{ create_sortable_anchor(request, "comments", sort_by_title, base_url, query_params="True") }} + Sort by {{ create_sortable_anchor(request, sort_by_label, sorting_urls["comments"]) }}
{% endif %}
diff --git a/workbaskets/jinja2/workbaskets/violations.jinja b/workbaskets/jinja2/workbaskets/violations.jinja index b85e2a923..37c63cb85 100644 --- a/workbaskets/jinja2/workbaskets/violations.jinja +++ b/workbaskets/jinja2/workbaskets/violations.jinja @@ -33,18 +33,16 @@ ]) or "" }} {% endfor %} -{% set base_url = url('workbaskets:workbasket-ui-violations' ) %} - {% set item %} - {{ create_sortable_anchor(request, "model", "Item", base_url) }} + {{ create_sortable_anchor(request, "Item", sorting_urls["model"]) }} {% endset %} {% set violation %} - {{ create_sortable_anchor(request, "check_name", "Violation", base_url) }} + {{ create_sortable_anchor(request, "Violation", sorting_urls["check_name"]) }} {% endset %} {% set activity_date %} - {{ create_sortable_anchor(request, "date", "Activity date", base_url) }} + {{ create_sortable_anchor(request, "Activity date", sorting_urls["date"]) }} {% endset %} {{ govukTable({ diff --git a/workbaskets/views/ui.py b/workbaskets/views/ui.py index 7195ac420..23082a2af 100644 --- a/workbaskets/views/ui.py +++ b/workbaskets/views/ui.py @@ -2,7 +2,6 @@ import re from datetime import date from functools import cached_property -from typing import Tuple import boto3 import django_filters @@ -384,9 +383,11 @@ class EditWorkbasketView(PermissionRequiredMixin, TemplateView): @method_decorator(require_current_workbasket, name="dispatch") -class CurrentWorkBasket(FormView): +class CurrentWorkBasket(SortingMixin, FormView): template_name = "workbaskets/summary-workbasket.jinja" form_class = forms.WorkBasketCommentCreateForm + sort_by_fields = ["comments"] + custom_sorting = {"comments": "created_at"} @property def workbasket(self) -> WorkBasket: @@ -394,27 +395,26 @@ def workbasket(self) -> WorkBasket: @cached_property def comments(self): - ordering = self.get_comments_ordering()[0] - return Comment.objects.filter(task__workbasket=self.workbasket).order_by( - ordering, - ) + comments = Comment.objects.filter(task__workbasket=self.workbasket) + ordering = self.get_ordering() + if ordering: + comments = comments.order_by(ordering) + return comments @cached_property def paginator(self): return Paginator(self.comments, per_page=20) - def get_comments_ordering(self) -> Tuple[str, str]: - """Returns the ordering for `self.comments` based on `ordered` GET param - together with the title to use for the sort by filter (which will be the - opposite of the applied ordering).""" + def get_comments_sort_by_label(self) -> str: + """Returns the sort_by_label to use for comments based on current + ordering.""" + sort_by = self.request.GET.get("sort_by") ordered = self.request.GET.get("ordered") - if ordered == "desc": - ordering = "created_at" - new_sort_by_title = "Newest first" + if sort_by == "comments" and ordered == "desc": + sort_by_label = "Newest first" else: - ordering = "-created_at" - new_sort_by_title = "Oldest first" - return ordering, new_sort_by_title + sort_by_label = "Oldest first" + return sort_by_label def form_valid(self, form): form.save(user=self.request.user, workbasket=self.workbasket) @@ -473,7 +473,7 @@ def get_context_data(self, **kwargs): "can_add_comment": can_add_comment, "can_view_comment": can_view_comment, "comments": page.object_list, - "sort_by_title": self.get_comments_ordering()[1], + "sort_by_label": self.get_comments_sort_by_label(), "paginator": self.paginator, "page_obj": page, "page_links": page_links, From d05ded9ebd0fc7fd79a17d8d23546f95e03106e4 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Tue, 11 Feb 2025 12:21:53 +0000 Subject: [PATCH 17/18] Fix tests related to sorting changes --- certificates/tests/test_views.py | 1 + workbaskets/views/ui.py | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/certificates/tests/test_views.py b/certificates/tests/test_views.py index 8c2fe80cf..d89d8ed76 100644 --- a/certificates/tests/test_views.py +++ b/certificates/tests/test_views.py @@ -373,6 +373,7 @@ def test_certificate_detail_measures_view_sorting_commodity(valid_user_client): ) measures.append(measure) commodity_codes = [measure.goods_nomenclature.item_id for measure in measures] + commodity_codes.sort() url = reverse( "certificate-ui-detail-measures", diff --git a/workbaskets/views/ui.py b/workbaskets/views/ui.py index 23082a2af..893fe7025 100644 --- a/workbaskets/views/ui.py +++ b/workbaskets/views/ui.py @@ -396,7 +396,7 @@ def workbasket(self) -> WorkBasket: @cached_property def comments(self): comments = Comment.objects.filter(task__workbasket=self.workbasket) - ordering = self.get_ordering() + ordering = self.get_comments_ordering()[0] if ordering: comments = comments.order_by(ordering) return comments @@ -405,16 +405,18 @@ def comments(self): def paginator(self): return Paginator(self.comments, per_page=20) - def get_comments_sort_by_label(self) -> str: - """Returns the sort_by_label to use for comments based on current - ordering.""" - sort_by = self.request.GET.get("sort_by") - ordered = self.request.GET.get("ordered") - if sort_by == "comments" and ordered == "desc": + def get_comments_ordering(self) -> tuple[str, str]: + """Reverses the ordering value returned by `super().get_ordering()` to + list newest comments first by default and includes a custom label to use + as the sorting anchor's title.""" + ordering = super().get_ordering() + if ordering and ordering.startswith("-"): + ordering = "created_at" sort_by_label = "Newest first" else: + ordering = "-created_at" sort_by_label = "Oldest first" - return sort_by_label + return ordering, sort_by_label def form_valid(self, form): form.save(user=self.request.user, workbasket=self.workbasket) @@ -473,7 +475,7 @@ def get_context_data(self, **kwargs): "can_add_comment": can_add_comment, "can_view_comment": can_view_comment, "comments": page.object_list, - "sort_by_label": self.get_comments_sort_by_label(), + "sort_by_label": self.get_comments_ordering()[1], "paginator": self.paginator, "page_obj": page, "page_links": page_links, From f5b8c4f4afc9fe1b59c59bceea6d37a5773158a9 Mon Sep 17 00:00:00 2001 From: Dale Cannon Date: Tue, 11 Feb 2025 12:23:31 +0000 Subject: [PATCH 18/18] Reposition Auto end-date measures summary row out of way of comments --- .../workbaskets/summary-workbasket.jinja | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/workbaskets/jinja2/workbaskets/summary-workbasket.jinja b/workbaskets/jinja2/workbaskets/summary-workbasket.jinja index 1cc5ad09f..ddc37e738 100644 --- a/workbaskets/jinja2/workbaskets/summary-workbasket.jinja +++ b/workbaskets/jinja2/workbaskets/summary-workbasket.jinja @@ -154,6 +154,17 @@ +
+
Auto end-date measures
+
Automatically end-date or delete measures and footnote associations on commodities which have been ended in this workbasket.
+
+ Auto end-date measures +
+
+ {% if workbasket.tasks.exists() and can_add_comment %}
Activity
@@ -167,16 +178,6 @@ {% endif %}
{% endif %} -
-
Auto end-date measures
-
Automatically end-date or delete measures and footnote associations on commodities which have been ended in this workbasket.
-
- Auto end-date measures -
-
{% if comments and can_view_comment %}