"""
Actions represent activities within a user interface, typically with regard to a model. This module defines the standard
actions supported by SuperDjango UI.
"""
__author__ = "Shawn Davis <shawn@superdjango.com>"
__maintainer__ = "Shawn Davis <shawn@superdjango.com>"
__version__ = "0.8.0-d"
# Imports
from django.utils.translation import gettext_lazy as _
from superdjango.ui.constants import VERB
from superdjango.ui.runtime.actions import Action
# Exports
__all__ = (
"AjaxCreateAction",
"AjaxDeleteAction",
"AjaxDetailAction",
"AjaxMarkCompleteAction",
"AjaxUpdateAction",
"BaseAction",
"BaseBulkAction",
"BatchChangeAction",
"BulkCompareAction",
"BulkDeleteAction",
"BulkEditAction",
"BulkTrashAction",
"CreateAction",
"DashboardAction",
"DeleteAction",
"DetailAction",
"DividerAction",
"DuplicateAction",
"ListAction",
"MarkArchivedAction",
"MarkCompleteAction",
"MarkPublishedAction",
"MarkReviewedAction",
"MarkResolvedAction",
"SearchAction",
"TrashAction",
"UpdateAction",
)
# Base Classes
[docs]class BaseAction(object):
"""Base class for model "actions"."""
icon = None
is_ajax = False
is_divider = False
label = None
verb = None
target = None
def __repr__(self):
return "<%s>" % self.__class__.__name__
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""Load the action.
:param request: The current HTTP request instance.
:param ui: The model UI instance.
:type ui: ModelUI
:param next_url: The value of the ``next_url``, especially on form submit.
:type next_url: str
:param record: The current model instance, if any.
:rtype: Action | None
:returns: If the pattern exists and a URL is available, an Action instance is returned. Otherwise ``None`` is
returned.
"""
pattern = ui.get_pattern(self.verb)
if pattern is None:
return None
url = pattern.reverse(record=record)
if url is None:
return None
if next_url is not None:
if "?" in url:
url += "&next=%s" % next_url
else:
url += "?next=%s" % next_url
kwargs = {
'icon': self.icon,
'is_ajax': self.is_ajax,
'target': self.target,
}
return Action(self.label, url, self.verb, **kwargs)
[docs]class BaseBulkAction(BaseAction):
"""Base class for bulk actions."""
select_items_message = _("Please select one or more items.")
[docs] def as_runtime(self, request, ui, next_url=None, queryset=None):
"""Load the bulk action.
:param request: The current HTTP request instance.
:param ui: The model UI instance.
:type ui: ModelUI
:param next_url: The value of the ``next_url``, especially on form submit.
:type next_url: str
:param queryset: The current queryset instance, if any.
:rtype: Action | None
:returns: If the pattern exists and a URL is available, an Action instance is returned. Otherwise ``None`` is
returned.
.. note::
The ``queryset`` parameter is not used by default.
"""
pattern = ui.get_pattern(self.verb)
if pattern is None:
return None
url = pattern.reverse()
if url is None:
return None
if next_url is not None:
if "?" in url:
url += "&next=%s" % next_url
else:
url += "?next=%s" % next_url
return Action(self.label, url, self.verb, icon=self.icon)
# Classes
[docs]class BatchChangeAction(BaseBulkAction):
"""Definition of the batch change action."""
icon = "fas fa-edit"
label = _("Change Selected Items")
verb = VERB.BATCH_CHANGE
[docs]class BulkCompareAction(BaseBulkAction):
"""Definition of the bulk compare action."""
icon = "fas fa-th-list"
label = _("Compare Selected Items")
verb = VERB.BULK_COMPARE
[docs]class BulkDeleteAction(BaseBulkAction):
"""Definition of the bulk delete action."""
icon = "fas fa-trash-alt"
label = _("Delete Selected Items")
verb = VERB.BULK_DELETE
[docs]class BulkEditAction(BaseBulkAction):
"""Definition of the bulk edit action."""
icon = "fas fa-edit-alt"
label = _("Edit")
verb = VERB.BULK_EDIT
[docs]class BulkTrashAction(BaseBulkAction):
"""Definition of the bulk trash action."""
icon = "fas fa-trash-alt"
label = _("Move Selected Items to Trash")
verb = VERB.BULK_TRASH
[docs]class CreateAction(BaseAction):
"""Definition of the create action."""
icon = "fas fa-plus-square"
label = _("Create")
verb = VERB.CREATE
[docs]class DashboardAction(BaseAction):
"""Definition of the dashboard action."""
icon = "fas fa-tachometer-alt"
label = _("Dashboard")
verb = VERB.DASHBOARD
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""Override to ignore next URL."""
pattern = ui.get_pattern(self.verb)
if pattern is None:
return None
url = pattern.reverse()
if url is None:
return None
return Action(self.label, url, self.verb, icon=self.icon)
[docs]class DeleteAction(BaseAction):
"""Definition of the delete action."""
icon = "fas fa-trash"
label = _("Delete")
verb = VERB.DELETE
[docs]class DetailAction(BaseAction):
"""Definition of the detail action."""
icon = "fas fa-info-circle"
label = _("Detail")
verb = VERB.DETAIL
[docs]class DividerAction(BaseAction):
"""A fake action that may be used to add a divider to a model actions menu.
.. code-block:: python
class TodoUI(ui.ModelUI):
# ...
list_options = ui.ListOptions(
# ...
actions=["create", "dashboard", "divider", "search", "divider"],
)
"""
is_divider = True
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""The divider action has no pattern or URL."""
action = Action("", "", "")
action.is_divider = True
return action
[docs]class DuplicateAction(BaseAction):
"""Definition of the duplicate action."""
icon = "far fa-clone"
label = _("Duplicate")
verb = VERB.DUPLICATE
[docs]class ListAction(BaseAction):
"""Definition of the create action."""
icon = "fas fa-table"
label = _("List")
verb = VERB.LIST
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""List action never responds to specific record instance."""
pattern = ui.get_pattern(self.verb)
if pattern is None:
return None
# Don't use record because the pattern won't reverse.
url = pattern.reverse()
if url is None:
return None
return Action(self.label, url, self.verb, icon=self.icon)
[docs]class MarkArchivedAction(BaseAction):
"""Provides support for ArchivedByModel."""
icon = "fas fa-archive"
label = _("Archive")
verb = VERB.MARK_ARCHIVED
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""A record must exist and be archived."""
if record is None:
return None
if record.is_archived:
return None
return super().as_runtime(request, ui, next_url=next_url, record=record)
[docs]class MarkCompleteAction(BaseAction):
"""Provides support for CompletedByModel."""
icon = "fas fa-check-square"
label = _("Mark Complete")
verb = VERB.MARK_COMPLETE
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""A record must exist and be completed."""
if record is None:
return None
if record.is_complete:
return None
return super().as_runtime(request, ui, next_url=next_url, record=record)
[docs]class MarkPublishedAction(BaseAction):
"""Provides support for PublishedByModel."""
icon = "fas fa-upload"
label = _("Mark Published")
verb = VERB.MARK_PUBLISHED
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""A record must exist and be published."""
if record is None:
return None
if record.is_published:
return None
return super().as_runtime(request, ui, next_url=next_url, record=record)
[docs]class MarkResolvedAction(BaseAction):
"""Provides support for ReviewedByModel."""
icon = "fas fa-door-closed"
label = _("Mark Resolved")
verb = VERB.MARK_RESOLVED
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""A record must exist and be resolved."""
if record is None:
return None
if record.is_resolved:
return None
return super().as_runtime(request, ui, next_url=next_url, record=record)
[docs]class MarkReviewedAction(BaseAction):
"""Provides support for ReviewedByModel."""
icon = "far fa-eye"
label = _("Mark Reviewed")
verb = VERB.MARK_REVIEWED
[docs] def as_runtime(self, request, ui, next_url=None, record=None):
"""A record must exist and be unreviewed."""
if record is None:
return None
if record.is_reviewed:
return None
return super().as_runtime(request, ui, next_url=next_url, record=record)
[docs]class SearchAction(ListAction):
"""Definition of the search action."""
icon = "fas fa-search"
label = _("Search")
verb = VERB.SEARCH
[docs]class TrashAction(BaseAction):
"""Definition of the trash action."""
icon = "fas fa-trash-alt"
label = _("Move to Trash")
verb = VERB.TRASH
[docs]class UpdateAction(BaseAction):
"""Definition of the update action."""
icon = "fas fa-edit"
label = _("Update")
verb = VERB.UPDATE
# AJAX Classes
[docs]class AjaxCreateAction(CreateAction):
"""Definition of the AJAX create action."""
is_ajax = True
verb = VERB.AJAX_CREATE
[docs]class AjaxDeleteAction(DeleteAction):
"""Definition of the AJAX delete action."""
is_ajax = True
verb = VERB.AJAX_DELETE
[docs]class AjaxDetailAction(DetailAction):
"""Definition of the AJAX detail action."""
is_ajax = True
verb = VERB.AJAX_DETAIL
[docs]class AjaxMarkCompleteAction(MarkCompleteAction):
"""Provides support for CompletedByModel via AJAX."""
is_ajax = True
verb = VERB.AJAX_MARK_COMPLETE
[docs]class AjaxUpdateAction(UpdateAction):
"""Definition of the AJAX update action."""
is_ajax = True
verb = VERB.AJAX_UPDATE