Browse Source

Update docs and changelog to reflect changes for #9817

Sage Abdullah 2 years ago
parent
commit
ad3ef5875d
4 changed files with 105 additions and 27 deletions
  1. 6 0
      CHANGELOG.txt
  2. 17 13
      docs/extending/custom_tasks.md
  3. 61 14
      docs/reference/pages/model_reference.md
  4. 21 0
      docs/releases/4.2.md

+ 6 - 0
CHANGELOG.txt

@@ -30,6 +30,7 @@ Changelog
  * Make the rich text block trigger and slash-commands always available regardless of where the cursor is (Thibaud Colas)
  * Adjust the size of panel labels on the "Account" form (Thibaud Colas)
  * Delay hiding the contents of the side panels when closing, so the animation is smoother (Thibaud Colas)
+ * Added ability to submit snippets for moderation with `WorkflowMixin` (Sage Abdullah)
  * Fix: Make sure workflow timeline icons are visible in high-contrast mode (Loveth Omokaro)
  * Fix: Ensure authentication forms (login, password reset) have a visible border in Windows high-contrast mode (Loveth Omokaro)
  * Fix: Ensure visual consistency between buttons and links as buttons in Windows high-contrast mode (Albina Starykova)
@@ -75,6 +76,11 @@ Changelog
  * Fix: Prevent memory exhaustion when purging a large number of revisions (Jake Howard)
  * Fix: Add right-to-left (RTL) support for the following form components: Switch, Minimap, live preview (Thibaud Colas)
  * Fix: Improve right-to-left (RTL) positioning for the following components: Page explorer, Sidebar sub-menu, rich text tooltips, rich text toolbar trigger, editor section headers (Thibaud Colas)
+ * Fix: Use the workflow name as the workflow information dialog title (Sage Abdullah)
+ * Fix: Link to workflow history view instead of page history view in the workflow information dialog (Sage Abdullah)
+ * Fix: Fix in-progress count in warning message when disabling workflows (Sage Abdullah)
+ * Fix: Show workflow name on workflow history index page (Sage Abdullah)
+ * Fix: Fix workflow history detail timeline content from showing on initial load (Sage Abdullah)
  * Docs: Add custom permissions section to permissions documentation page (Dan Hayden)
  * Docs: Add documentation for how to get started with contributing translations for the Wagtail admin (Ogunbanjo Oluwadamilare)
  * Docs: Officially recommend `fnm` over `nvm` in development documentation (LB (Ben) Johnston)

+ 17 - 13
docs/extending/custom_tasks.md

@@ -85,7 +85,7 @@ class UserApprovalTask(Task):
 ## Custom TaskState models
 
 You might also need to store custom state information for the task: for example, a rating left by an approving user.
-Normally, this is done on an instance of `TaskState`, which is created when a page starts the task. However, this can
+Normally, this is done on an instance of `TaskState`, which is created when an object starts the task. However, this can
 also be subclassed equivalently to `Task`:
 
 ```python
@@ -124,26 +124,30 @@ class UserApprovalTask(Task):
 
 Both `Task` and `TaskState` have a number of methods that can be overridden to implement custom behaviour. Here are some of the most useful:
 
-`Task.user_can_access_editor(page, user)`, `Task.user_can_lock(page, user)`, `Task.user_can_unlock(page, user)`:
+`Task.user_can_access_editor(obj, user)`, `Task.user_can_lock(obj, user)`, `Task.user_can_unlock(obj, user)`:
 
-These methods determine if users usually without permission can access the editor, and lock, or unlock the page, by returning True or False.
+These methods determine if users usually without permission can access the editor, and lock, or unlock the object, by returning True or False.
 Note that returning `False` will not prevent users who would normally be able to perform those actions. For example, for our `UserApprovalTask`:
 
 ```python
-def user_can_access_editor(self, page, user):
+def user_can_access_editor(self, obj, user):
     return user == self.user
 ```
 
-`Task.page_locked_for_user(page, user)`:
+`Task.locked_for_user(obj, user)`:
 
-This returns `True` if the page should be locked and uneditable by the user. It is used by `GroupApprovalTask` to lock the page to any users not in the approval group.
+This returns `True` if the object should be locked and uneditable by the user. It is used by `GroupApprovalTask` to lock the object to any users not in the approval group.
 
 ```python
-def page_locked_for_user(self, page, user):
+def locked_for_user(self, obj, user):
     return user != self.user
 ```
 
-`Task.get_actions(page, user)`:
+```{versionchanged} 4.2
+This method was previously named ``page_locked_for_user``, using ``page_locked_for_user`` will be removed in a future release. Along with the other similar methods, the ``obj`` parameter was previously named ``page``.
+```
+
+`Task.get_actions(obj, user)`:
 
 This returns a list of `(action_name, action_verbose_name, action_requires_additional_data_from_modal)` tuples, corresponding to the actions available for the task in the edit view menu.
 `action_requires_additional_data_from_modal` should be a boolean, returning `True` if choosing the action should open a modal for additional data input - for example, entering a comment.
@@ -151,7 +155,7 @@ This returns a list of `(action_name, action_verbose_name, action_requires_addit
 For example:
 
 ```python
-def get_actions(self, page, user):
+def get_actions(self, obj, user):
     if user == self.user:
         return [
             ('approve', "Approve", False),
@@ -172,7 +176,7 @@ Returns the name of a custom template to be used in rendering the data entry mod
 
 `Task.on_action(task_state, user, action_name, **kwargs)`:
 
-This performs the actions specified in `Task.get_actions(page, user)`: it is passed an action name, for example, `approve`, and the relevant task state. By default, it calls `approve` and `reject` methods on the task state when the corresponding action names are passed through. Any additional data entered in a modal (see `get_form_for_action` and `get_actions`) is supplied as kwargs.
+This performs the actions specified in `Task.get_actions(obj, user)`: it is passed an action name, for example, `approve`, and the relevant task state. By default, it calls `approve` and `reject` methods on the task state when the corresponding action names are passed through. Any additional data entered in a modal (see `get_form_for_action` and `get_actions`) is supplied as kwargs.
 
 For example, let's say we wanted to add an additional option: cancelling the entire workflow:
 
@@ -186,7 +190,7 @@ def on_action(self, task_state, user, action_name):
 
 `Task.get_task_states_user_can_moderate(user, **kwargs)`:
 
-This returns a QuerySet of `TaskStates` (or subclasses) the given user can moderate - this is currently used to select pages to display on the user's dashboard.
+This returns a QuerySet of `TaskStates` (or subclasses) the given user can moderate - this is currently used to select objects to display on the user's dashboard.
 
 For example:
 
@@ -237,13 +241,13 @@ class BaseUserApprovalTaskStateEmailNotifier(EmailNotificationMixin, Notifier):
 
     def can_handle(self, instance, **kwargs):
         if super().can_handle(instance, **kwargs) and isinstance(instance.task.specific, UserApprovalTask):
-            # Don't send notifications if a Task has been cancelled and then resumed - when page was updated to a new revision
+            # Don't send notifications if a Task has been cancelled and then resumed - when object was updated to a new revision
             return not TaskState.objects.filter(workflow_state=instance.workflow_state, task=instance.task, status=TaskState.STATUS_CANCELLED).exists()
         return False
 
     def get_context(self, task_state, **kwargs):
         context = super().get_context(task_state, **kwargs)
-        context['page'] = task_state.workflow_state.page
+        context['object'] = task_state.workflow_state.content_object
         context['task'] = task_state.task.specific
         return context
 

+ 61 - 14
docs/reference/pages/model_reference.md

@@ -645,10 +645,10 @@ The model is added to allow snippets to be locked. See [](wagtailsnippets_lockin
 ## `WorkflowMixin`
 
 `WorkflowMixin` is a mixin class that can be added to any non-page Django model to allow its instances to be submitted to workflows.
-This mixin requires {class}`~wagtail.models.RevisionMixin`, {class}`~wagtail.models.DraftStateMixin`, and {class}`~wagtail.models.LockableMixin` to be applied. Pages already include this mixin, so there is no need to add it.
+This mixin requires {class}`~wagtail.models.RevisionMixin` and {class}`~wagtail.models.DraftStateMixin` to be applied. Pages already include this mixin, so there is no need to add it.
 
 ```{versionadded} 4.2
-The model is added to allow snippets to be submitted to workflows. See [](wagtailsnippets_enabling_workflows) for more details.
+The model is added to allow snippets to be submitted for moderation. See [](wagtailsnippets_enabling_workflows) for more details.
 ```
 
 ### Methods and properties
@@ -873,7 +873,7 @@ The model has been renamed from ``PageRevision`` to ``Revision`` and it now refe
 
 ## `Workflow`
 
-Workflows represent sequences of tasks which much be approved for an action to be performed on a page - typically publication.
+Workflows represent sequences of tasks which must be approved for an action to be performed on an object - typically publication.
 
 ### Database fields
 
@@ -890,7 +890,7 @@ Workflows represent sequences of tasks which much be approved for an action to b
 
         (boolean)
 
-        Whether or not the workflow is active: active workflows can be added to pages, and started. Inactive workflows cannot.
+        Whether or not the workflow is active: active workflows can be added to pages and snippets, and started. Inactive workflows cannot.
 ```
 
 ### Methods and properties
@@ -910,18 +910,40 @@ Workflows represent sequences of tasks which much be approved for an action to b
 
 ## `WorkflowState`
 
-Workflow states represent the status of a started workflow on a page.
+Workflow states represent the status of a started workflow on an object.
 
 ### Database fields
 
 ```{eval-rst}
 .. class:: WorkflowState
 
-    .. attribute:: page
+    .. attribute:: content_object
+
+        (generic foreign key)
+
+        The object on which the workflow has been started. For page workflows, the object is an instance of the base ``Page`` model.
+
+        .. versionchanged:: 4.2
+
+           This field has been changed from a ``ForeignKey`` to ``Page`` into a :class:`~django.contrib.contenttypes.fields.GenericForeignKey` to any Django model instance.
+
+    .. attribute:: content_type
+
+        (foreign key to :class:`~django.contrib.contenttypes.models.ContentType`)
 
-        (foreign key to ``Page``)
+        The content type of the object this workflow state belongs to. For page workflows, this means the content type of the specific page type.
 
-        The page on which the workflow has been started
+    .. attribute:: base_content_type
+
+        (foreign key to :class:`~django.contrib.contenttypes.models.ContentType`)
+
+        The base content type of the object this workflow state belongs to. For page workflows, this means the content type of the :class:`~wagtail.models.Page` model.
+
+    .. attribute:: object_id
+
+        (string)
+
+        The primary key of the object this revision belongs to.
 
     .. attribute:: workflow
 
@@ -1056,7 +1078,7 @@ Tasks represent stages in a workflow which must be approved for the workflow to
 
 ## `TaskState`
 
-Task states store state information about the progress of a task on a particular page revision.
+Task states store state information about the progress of a task on a particular revision.
 
 ### Database fields
 
@@ -1065,19 +1087,23 @@ Task states store state information about the progress of a task on a particular
 
     .. attribute:: workflow_state
 
-        (foreign key to ``WorkflowState``)
+        (foreign key to :class:`~wagtail.models.WorkflowState`)
 
         The workflow state which started this task state.
 
     .. attribute:: revision
 
-        (foreign key to ``Revision``)
+        (foreign key to :class:`~wagtail.models.Revision`)
 
         The revision this task state was created on.
 
+        .. versionchanged:: 4.2
+
+           This field has been renamed from ``page_revision`` to ``revision``.
+
     .. attribute:: task
 
-        (foreign key to ``Task``)
+        (foreign key to :class:`~wagtail.models.Task`)
 
         The task that this task state is storing state information for.
 
@@ -1183,11 +1209,32 @@ Represents the assignment of a workflow to a page and its descendants.
 
     .. attribute:: workflow
 
-        (foreign key to ``Workflow``)
+        (foreign key to :class:`~wagtail.models.Workflow`)
 
     .. attribute:: page
 
-        (foreign key to ``Page``)
+        (foreign key to :class:`~wagtail.models.Page`)
+```
+
+## `WorkflowContentType`
+
+Represents the assignment of a workflow to a Django model.
+
+### Database fields
+
+```{eval-rst}
+.. class:: WorkflowContentType
+
+    .. attribute:: workflow
+
+        (foreign key to :class:`~wagtail.models.Workflow`)
+
+    .. attribute:: content_type
+
+        (foreign key to :class:`~django.contrib.contenttypes.models.ContentType`)
+
+        A foreign key to the ``ContentType`` object that represents the model that is assigned to the workflow.
+
 ```
 
 ## `BaseLogEntry`

+ 21 - 0
docs/releases/4.2.md

@@ -21,6 +21,12 @@ Snippets can now be locked by users to prevent other users from editing, through
 
 This feature was developed by Sage Abdullah.
 
+### Workflows for snippets
+
+Snippets can now be assigned to workflows through the use of the `WorkflowMixin`, allowing new changes to be submitted for moderation before they are published. For more details, see [](wagtailsnippets_enabling_workflows).
+
+This feature was developed by Sage Abdullah.
+
 ### `fullpageurl` template tag
 
 Wagtail now provides a `fullpageurl` template tag (for both Django templates and Jinja2) to output a page's full URL including the domain. For more details, see [](fullpageurl_tag).
@@ -245,3 +251,18 @@ If you are using the front-end cache invalidator module (`wagtail.contrib.fronte
 * For Azure Front Door: upgrade `azure-mgmt-frontdoor` to version 1 or above
 
 Support for older versions will be dropped in a future release.
+
+### Changes to `Workflow` and `Task` methods
+
+To accommodate workflows support for snippets, the `page` parameter in {meth}`Workflow.start() <wagtail.models.Workflow.start>` has been renamed to `obj`.
+
+In addition, some methods on the base {class}`~wagtail.models.Task` model have been changed. If you have {doc}`custom Task types </extending/custom_tasks>`, make sure to update the methods to reflect the following changes:
+
+- `page_locked_for_user()` is now {meth}`~wagtail.models.Task.locked_for_user`. Using `page_locked_for_user()` is deprecated and will be removed in a future release.
+- The `page` parameter in `user_can_access_editor()`, `locked_for_user()`, `user_can_lock()`, `user_can_unlock()`, `get_actions()`,  has been renamed to `obj`.
+
+### Changes to `WorkflowState` and `TaskState` models
+
+To accommodate workflows support for snippets, the `WorkflowState.page` foreign key has been replaced with a `GenericForeignKey` as `WorkflowState.content_object`. The generic foreign key is defined using a combination of the new `WorkflowState.base_content_type` and `WorkflowState.object_id` fields.
+
+The `TaskState.page_revision` foreign key has been renamed to `TaskState.revision`.