From d7b2e06ece479d3df9360ea6b379bee05ee052b3 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 13 Feb 2020 11:27:57 +0000 Subject: [PATCH] Implemented WorkflowState.all_tasks_with_status --- .../templates/wagtailadmin/pages/edit.html | 4 +-- .../wagtailadmin/shared/workflow_status.html | 8 ++--- wagtail/admin/views/pages.py | 34 +++++++------------ wagtail/core/models.py | 19 +++++++++++ 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/wagtail/admin/templates/wagtailadmin/pages/edit.html b/wagtail/admin/templates/wagtailadmin/pages/edit.html index a8e07c2055..b40c035024 100644 --- a/wagtail/admin/templates/wagtailadmin/pages/edit.html +++ b/wagtail/admin/templates/wagtailadmin/pages/edit.html @@ -17,12 +17,12 @@ {% blocktrans with title=page.get_admin_display_title page_type=content_type.model_class.get_verbose_name %}Editing {{ page_type }} {{ title }}{% endblocktrans %} - {% if task_statuses %} + {% if workflow_tasks %}
{% include "wagtailadmin/shared/workflow_status.html" with page=page_for_status %}
{% endif %} -
+
{% trans "Status" %} {% include "wagtailadmin/shared/page_status_tag.html" with page=page_for_status %} diff --git a/wagtail/admin/templates/wagtailadmin/shared/workflow_status.html b/wagtail/admin/templates/wagtailadmin/shared/workflow_status.html index 8b0ec5f10c..e3b775c92e 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/workflow_status.html +++ b/wagtail/admin/templates/wagtailadmin/shared/workflow_status.html @@ -1,16 +1,16 @@ {% load wagtailui_tags i18n %} -{% if task_statuses %} +{% if workflow_tasks %}

{{ workflow_name }}

{% if current_task_number %} - {% blocktrans %} Task {{ current_task_number }} of {{ total_tasks }}{% endblocktrans %}: {{ task_name }} + {% blocktrans %} Task {{ current_task_number }} of {{ workflow_tasks.count }}{% endblocktrans %}: {{ task_name }} {% else %} {% trans 'Task' %}: {{ task_name }} {% endif %}
{% trans 'Approved task' as approved_title %} {% trans 'Incomplete task' as incomplete_title %} - {% for status in task_statuses %} - {% if status == 'approved' %} + {% for task in workflow_tasks %} + {% if task.status == 'approved' %} {% wagtail_icon name="success" title=approved_title %} {% else %} {% wagtail_icon name="radio-empty" title=incomplete_title %} diff --git a/wagtail/admin/views/pages.py b/wagtail/admin/views/pages.py index 0acc2c1be6..56f90b9fb8 100644 --- a/wagtail/admin/views/pages.py +++ b/wagtail/admin/views/pages.py @@ -411,37 +411,26 @@ def edit(request, page_id): messages.warning(request, _("This page is currently awaiting moderation"), buttons=buttons) - task_statuses = [] + workflow_tasks = [] workflow_state = page.current_workflow_state workflow_name = '' task_name = '' - total_tasks = 0 current_task_number = None if workflow_state: workflow = workflow_state.workflow task = workflow_state.current_task_state.task - workflow_tasks = WorkflowTask.objects.filter(workflow=workflow) try: - current_task_number = workflow_tasks.get(task=task).sort_order + 1 + current_task_number = WorkflowTask.objects.get(workflow=workflow, task=task).sort_order + 1 except WorkflowTask.DoesNotExist: # The Task has been removed from the Workflow pass task_name = task.name workflow_name = workflow.name - states = TaskState.objects.filter(workflow_state=workflow_state, page_revision=page.get_latest_revision()).values('task', 'status') - total_tasks = len(workflow_tasks) # len used as queryset is to be iterated over - - # create a list of task statuses to be passed into the template to show workflow progress - for workflow_task in workflow_tasks: - try: - status = states.get(task=workflow_task.task)['status'] - except TaskState.DoesNotExist: - status = 'not_started' - task_statuses.append(status) + workflow_tasks = workflow_state.all_tasks_with_status() # add a warning message if tasks have been approved and may need to be re-approved - approved_task = True if 'approved' in task_statuses else False + task_has_been_approved = workflow_tasks.filter(status='approved').exists() # TODO: add icon to message when we have added a workflows icon if request.method == 'GET': @@ -452,15 +441,17 @@ def edit(request, page_id): reverse('wagtailadmin_pages:revisions_compare', args=(page.id, 'live', latest_revision.id)), _('Compare with live version') )) - # Check for revisions still undergoing moderation and warn - if total_tasks == 1: + + # Check for revisions still undergoing moderation and warn + if workflow_tasks.count() == 1: # If only one task in workflow, show simple message workflow_info = _("This page is currently awaiting moderation") elif current_task_number: - workflow_info = format_html(_("Page '{}' is on Task {} of {}: '{}' in Workflow '{}'. "), page.get_admin_display_title(), current_task_number, total_tasks, task_name, workflow_name) + workflow_info = format_html(_("Page '{}' is on Task {} of {}: '{}' in Workflow '{}'. "), page.get_admin_display_title(), current_task_number, workflow_tasks.count(), task_name, workflow_name) else: - workflow_info = format_html(_("Page '{}' is on Task '{}' in Workflow '{}'. "), page.get_admin_display_title(), current_task_number, total_tasks, task_name, workflow_name) - if approved_task and getattr(settings, 'WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT', True): + workflow_info = format_html(_("Page '{}' is on Task '{}' in Workflow '{}'. "), page.get_admin_display_title(), current_task_number, workflow_tasks.count(), task_name, workflow_name) + + if task_has_been_approved and getattr(settings, 'WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT', True): messages.warning(request, mark_safe(workflow_info + _("Editing this Page will cause completed Tasks to need re-approval.")), buttons=buttons, extra_tags="workflow") else: messages.success(request, workflow_info, buttons=buttons, extra_tags="workflow") @@ -679,11 +670,10 @@ def edit(request, page_id): 'page_locked': page_perms.page_locked(), 'workflow_actions': page.current_workflow_task.get_actions(page, request.user) if page.current_workflow_task else [], 'current_task_state': page.current_workflow_task_state, - 'task_statuses': task_statuses, + 'workflow_tasks': workflow_tasks, 'current_task_number': current_task_number, 'task_name': task_name, 'workflow_name': workflow_name, - 'total_tasks': total_tasks }) diff --git a/wagtail/core/models.py b/wagtail/core/models.py index f56bcf8143..db73043dfa 100644 --- a/wagtail/core/models.py +++ b/wagtail/core/models.py @@ -14,6 +14,7 @@ from django.core.handlers.base import BaseHandler from django.core.handlers.wsgi import WSGIRequest from django.db import models, transaction from django.db.models import Case, Q, Value, When +from django.db.models.expressions import OuterRef, Subquery from django.db.models.functions import Concat, Lower, Substr from django.http import Http404 from django.http.request import split_domain_port @@ -2843,6 +2844,24 @@ class WorkflowState(models.Model): for state in approved_states: state.copy(update_attrs={'page_revision': revision}) + def all_tasks_with_status(self): + """ + Returns a queryset of Task objects that are linked with this workflow state's + workflow. The status of that task in this workflow state is annotated in the + `.status` field. + + This is different to querying TaskState as it also returns tasks that haven't + been started yet (so won't have a TaskState). + """ + return self.workflow.tasks.annotate( + status=Subquery( + TaskState.objects.filter( + task_id=OuterRef('id'), + workflow_state_id=self.id, + ).values('status') + ) + ) + class Meta: verbose_name = _('Workflow state') verbose_name_plural = _('Workflow states')