kopia lustrzana https://github.com/wagtail/wagtail
Rework how lock information is displayed in status side panel
rodzic
2b0bdd66ff
commit
9ea12d42b4
wagtail
admin
templates/wagtailadmin/shared/side_panels/includes/status
snippets/tests
tests
|
@ -5,27 +5,7 @@
|
|||
{% trans 'Locking: ' as screen_reader_title_prefix %}
|
||||
|
||||
{% if lock %}
|
||||
{% trans 'Locked' as title %}
|
||||
|
||||
{% if not locked_for_user and user_can_unlock %}
|
||||
{% blocktrans trimmed with model_name=base_model_name|lower asvar help_text %}
|
||||
You can edit this {{ model_name }}, but others may not. Unlock it to allow others to edit.
|
||||
{% endblocktrans %}
|
||||
{% elif not locked_for_user %}
|
||||
{% blocktrans trimmed with model_name=base_model_name|lower asvar help_text %}
|
||||
You can edit this {{ model_name }}, but others may not.
|
||||
{% endblocktrans %}
|
||||
{% elif user_can_unlock %}
|
||||
{% blocktrans trimmed with model_name=base_model_name|lower asvar help_text %}
|
||||
You cannot edit this {{ model_name }}. Unlock it to edit.
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans trimmed with model_name=base_model_name|lower asvar help_text %}
|
||||
You cannot edit this {{ model_name }}.
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
|
||||
{% with icon_name='lock' %}
|
||||
{% with icon_name=lock_context.icon title=lock_context.locked_by help_text=lock_context.description %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
|
@ -33,11 +13,11 @@
|
|||
|
||||
{% if user_can_lock %}
|
||||
{% blocktrans trimmed with model_name=base_model_name|lower asvar help_text %}
|
||||
Anyone can edit this {{ model_name }}. Lock it to prevent others from editing.
|
||||
Anyone can edit this {{ model_name }} – lock it to prevent others from editing
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans trimmed with model_name=base_model_name|lower asvar help_text %}
|
||||
Anyone can edit this {{ model_name }}.
|
||||
Anyone can edit this {{ model_name }}
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
{{ live_expire_at }}
|
||||
</div>
|
||||
</div>
|
||||
{% if show_schedule_publishing_toggle and not has_draft_publishing_schedule and not locked_for_user %}
|
||||
{% if show_schedule_publishing_toggle and not has_draft_publishing_schedule and not lock_context.locked %}
|
||||
{% trans 'Edit schedule' as edit_schedule_text %}
|
||||
{% dialog_toggle classname='w-bg-transparent w-text-14 w-p-0 w-text-secondary hover:w-text-secondary-600 w-inline-flex w-justify-center w-transition' dialog_id="schedule-publishing-dialog" text=edit_schedule_text %}
|
||||
{% endif %}
|
||||
|
@ -157,7 +157,7 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if show_schedule_publishing_toggle and not locked_for_user %}
|
||||
{% if show_schedule_publishing_toggle and not lock_context.locked %}
|
||||
{% trans 'Edit schedule' as edit_schedule_text %}
|
||||
{% dialog_toggle classname='w-bg-transparent w-text-14 w-p-0 w-text-secondary hover:w-text-secondary-600 w-inline-flex w-justify-center w-transition' dialog_id="schedule-publishing-dialog" text=edit_schedule_text %}
|
||||
{% endif %}
|
||||
|
@ -166,7 +166,7 @@
|
|||
{% elif draftstate_enabled and not has_live_publishing_schedule %}
|
||||
<div class="w-flex w-justify-between w-items-center w-w-full">
|
||||
<div class="w-ml-8 w-pr-4 w-label-3">{% trans 'No publishing schedule set' %}</div>
|
||||
{% if show_schedule_publishing_toggle and not locked_for_user %}
|
||||
{% if show_schedule_publishing_toggle and not lock_context.locked %}
|
||||
{% trans 'Set schedule' as set_schedule_text %}
|
||||
{% dialog_toggle classname='w-bg-transparent w-text-14 w-p-0 w-text-secondary hover:w-text-secondary-600 w-inline-flex w-justify-center w-transition' dialog_id="schedule-publishing-dialog" text=set_schedule_text %}
|
||||
{% endif %}
|
||||
|
|
|
@ -154,15 +154,14 @@ class BaseStatusSidePanel(BaseSidePanel):
|
|||
|
||||
def get_lock_context(self):
|
||||
self.lock = None
|
||||
self.locked_for_user = False
|
||||
lock_context = {}
|
||||
if self.locking_enabled:
|
||||
self.lock = self.object.get_lock()
|
||||
self.locked_for_user = self.lock and self.lock.for_user(self.request.user)
|
||||
|
||||
if self.lock:
|
||||
lock_context = self.lock.get_context_for_user(self.request.user)
|
||||
return {
|
||||
"lock": self.lock,
|
||||
"locked_for_user": self.locked_for_user,
|
||||
"locking_enabled": self.locking_enabled,
|
||||
"lock_context": lock_context,
|
||||
}
|
||||
|
||||
def get_usage_context(self):
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.utils.safestring import mark_safe
|
|||
from django.utils.text import capfirst
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from wagtail.admin.utils import get_latest_str
|
||||
from wagtail.admin.utils import get_latest_str, get_user_display_name
|
||||
from wagtail.utils.deprecation import RemovedInWagtail60Warning
|
||||
|
||||
|
||||
|
@ -37,6 +37,36 @@ class BaseLock:
|
|||
"""
|
||||
return None
|
||||
|
||||
def get_icon(self, user):
|
||||
"""
|
||||
Returns the name of the icon to use for the lock.
|
||||
"""
|
||||
return "lock"
|
||||
|
||||
def get_locked_by(self, user):
|
||||
"""
|
||||
Returns a string that represents the user or mechanism that locked the object.
|
||||
"""
|
||||
return _("Locked")
|
||||
|
||||
def get_description(self, user):
|
||||
"""
|
||||
Returns a description of the lock to display to the given user.
|
||||
"""
|
||||
return capfirst(_("No one can make changes while the %(model_name)s is locked"))
|
||||
|
||||
def get_context_for_user(self, user):
|
||||
"""
|
||||
Returns a context dictionary to use in templates for the given user.
|
||||
"""
|
||||
return {
|
||||
"locked": self.for_user(user),
|
||||
"message": self.get_message(user),
|
||||
"icon": self.get_icon(user),
|
||||
"locked_by": self.get_locked_by(user),
|
||||
"description": self.get_description(user),
|
||||
}
|
||||
|
||||
|
||||
class BasicLock(BaseLock):
|
||||
"""
|
||||
|
@ -88,7 +118,7 @@ class BasicLock(BaseLock):
|
|||
"<b>'{title}' was locked</b> by <b>{user}</b> on <b>{datetime}</b>."
|
||||
),
|
||||
title=title,
|
||||
user=str(self.object.locked_by),
|
||||
user=get_user_display_name(self.object.locked_by),
|
||||
datetime=self.object.locked_at.strftime("%d %b %Y %H:%M"),
|
||||
)
|
||||
else:
|
||||
|
@ -99,6 +129,29 @@ class BasicLock(BaseLock):
|
|||
title=title,
|
||||
)
|
||||
|
||||
def get_locked_by(self, user):
|
||||
if self.object.locked_by_id == user.pk:
|
||||
return _("Locked by you")
|
||||
if self.object.locked_by_id:
|
||||
return _("Locked by another user")
|
||||
return super().get_locked_by(user)
|
||||
|
||||
def get_description(self, user):
|
||||
if self.object.locked_by_id == user.pk:
|
||||
return capfirst(
|
||||
_("Only you can make changes while the %(model_name)s is locked")
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
if self.object.locked_by_id:
|
||||
return capfirst(
|
||||
_("Only %(user)s can make changes while the %(model_name)s is locked")
|
||||
% {
|
||||
"user": get_user_display_name(self.object.locked_by),
|
||||
"model_name": self.model_name,
|
||||
}
|
||||
)
|
||||
return super().get_description(user)
|
||||
|
||||
|
||||
class WorkflowLock(BaseLock):
|
||||
"""
|
||||
|
@ -145,6 +198,18 @@ class WorkflowLock(BaseLock):
|
|||
|
||||
return mark_safe(workflow_info + " " + reviewers_info)
|
||||
|
||||
def get_icon(self, user):
|
||||
return super().get_icon(user)
|
||||
|
||||
def get_locked_by(self, user):
|
||||
return _("Locked by workflow")
|
||||
|
||||
def get_description(self, user):
|
||||
return capfirst(
|
||||
_("Only reviewers can edit and approve the %(model_name)s")
|
||||
% {"model_name": self.model_name}
|
||||
)
|
||||
|
||||
|
||||
class ScheduledForPublishLock(BaseLock):
|
||||
"""
|
||||
|
@ -170,3 +235,9 @@ class ScheduledForPublishLock(BaseLock):
|
|||
datetime=scheduled_revision.approved_go_live_at.strftime("%d %b %Y %H:%M"),
|
||||
)
|
||||
return mark_safe(capfirst(message))
|
||||
|
||||
def get_locked_by(self, user):
|
||||
return _("Locked by schedule")
|
||||
|
||||
def get_description(self, user):
|
||||
return _("Currently locked and will go live on the scheduled date")
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.test import TestCase, override_settings
|
|||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from wagtail.admin.utils import get_user_display_name
|
||||
from wagtail.locks import WorkflowLock
|
||||
from wagtail.models import GroupApprovalTask, Workflow, WorkflowTask
|
||||
from wagtail.test.testapp.models import (
|
||||
|
@ -443,10 +444,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
|
|||
# Should show lock information in the side panel
|
||||
self.assertContains(
|
||||
response,
|
||||
(
|
||||
f"You can edit this {self.model_name}, but others may not. "
|
||||
"Unlock it to allow others to edit."
|
||||
),
|
||||
f"Only you can make changes while the {self.model_name} is locked",
|
||||
)
|
||||
|
||||
# Should show unlock buttons, one in the message and one in the side panel
|
||||
|
@ -470,6 +468,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
|
|||
response = self.client.get(self.get_url("edit"))
|
||||
html = response.content.decode()
|
||||
unlock_url = self.get_url("unlock")
|
||||
display_name = get_user_display_name(user)
|
||||
|
||||
# Should show lock message
|
||||
self.assertContains(
|
||||
|
@ -480,7 +479,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
|
|||
# Should show lock information in the side panel
|
||||
self.assertContains(
|
||||
response,
|
||||
f"You cannot edit this {self.model_name}. Unlock it to edit.",
|
||||
f"Only {display_name} can make changes while the {self.model_name} is locked",
|
||||
)
|
||||
|
||||
# Should not show Save action menu item
|
||||
|
@ -521,6 +520,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
|
|||
response = self.client.get(self.get_url("edit"))
|
||||
html = response.content.decode()
|
||||
unlock_url = self.get_url("unlock")
|
||||
display_name = get_user_display_name(user)
|
||||
|
||||
# Should show lock message
|
||||
self.assertContains(
|
||||
|
@ -531,11 +531,11 @@ class TestEditLockedSnippet(BaseLockingTestCase):
|
|||
# Should show lock information in the side panel
|
||||
self.assertContains(
|
||||
response,
|
||||
f"You cannot edit this {self.model_name}.",
|
||||
f"Only {display_name} can make changes while the {self.model_name} is locked",
|
||||
)
|
||||
|
||||
# Should not show instruction to unlock
|
||||
self.assertNotContains(response, "Unlock it to edit.")
|
||||
self.assertNotContains(response, "Unlock")
|
||||
|
||||
# Should not show Save action menu item
|
||||
self.assertNotContains(
|
||||
|
@ -579,13 +579,13 @@ class TestEditLockedSnippet(BaseLockingTestCase):
|
|||
# Should show unlocked information in the side panel
|
||||
self.assertContains(
|
||||
response,
|
||||
f"Anyone can edit this {self.model_name}.",
|
||||
f"Anyone can edit this {self.model_name}",
|
||||
)
|
||||
|
||||
# Should not show info to lock the object in the side panel
|
||||
self.assertNotContains(
|
||||
response,
|
||||
"Lock it to prevent others from editing.",
|
||||
"lock it to prevent others from editing",
|
||||
)
|
||||
|
||||
# Should show Save action menu item
|
||||
|
@ -630,7 +630,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
|
|||
# Should show unlocked information in the side panel
|
||||
self.assertContains(
|
||||
response,
|
||||
f"Anyone can edit this {self.model_name}. Lock it to prevent others from editing.",
|
||||
f"Anyone can edit this {self.model_name} – lock it to prevent others from editing",
|
||||
)
|
||||
|
||||
# Should show Save action menu item
|
||||
|
|
|
@ -3041,9 +3041,10 @@ class TestScheduledForPublishLock(BaseTestSnippetEditView):
|
|||
)
|
||||
|
||||
# Should show the lock information in the status side panel
|
||||
self.assertContains(response, "Locked by schedule")
|
||||
self.assertContains(
|
||||
response,
|
||||
'<div class="w-help-text">You cannot edit this draft state model.</div>',
|
||||
'<div class="w-help-text">Currently locked and will go live on the scheduled date</div>',
|
||||
html=True,
|
||||
count=1,
|
||||
)
|
||||
|
@ -3107,9 +3108,10 @@ class TestScheduledForPublishLock(BaseTestSnippetEditView):
|
|||
)
|
||||
|
||||
# Should show the lock information in the status side panel
|
||||
self.assertContains(response, "Locked by schedule")
|
||||
self.assertContains(
|
||||
response,
|
||||
'<div class="w-help-text">You cannot edit this draft state model.</div>',
|
||||
'<div class="w-help-text">Currently locked and will go live on the scheduled date</div>',
|
||||
html=True,
|
||||
count=1,
|
||||
)
|
||||
|
@ -3168,9 +3170,10 @@ class TestScheduledForPublishLock(BaseTestSnippetEditView):
|
|||
)
|
||||
|
||||
# Should show the lock information in the status side panel
|
||||
self.assertContains(response, "Locked by schedule")
|
||||
self.assertContains(
|
||||
response,
|
||||
'<div class="w-help-text">You cannot edit this draft state model.</div>',
|
||||
'<div class="w-help-text">Currently locked and will go live on the scheduled date</div>',
|
||||
html=True,
|
||||
count=1,
|
||||
)
|
||||
|
|
|
@ -3572,11 +3572,11 @@ class TestGetLock(TestCase):
|
|||
self.assertFalse(lock.for_user(moderator))
|
||||
self.assertEqual(
|
||||
lock.get_message(christmas_event.owner),
|
||||
f"<b>Page 'Christmas' was locked</b> by <b>{str(moderator)}</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
f"<b>'Christmas' was locked</b> by <b>{str(moderator)}</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
)
|
||||
self.assertEqual(
|
||||
lock.get_message(moderator),
|
||||
"<b>Page 'Christmas' was locked</b> by <b>you</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
"<b>'Christmas' was locked</b> by <b>you</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
)
|
||||
|
||||
def test_when_locked_without_locked_at(self):
|
||||
|
@ -3589,11 +3589,11 @@ class TestGetLock(TestCase):
|
|||
lock = christmas_event.get_lock()
|
||||
self.assertEqual(
|
||||
lock.get_message(christmas_event.owner),
|
||||
"<b>Page 'Christmas' is locked</b>.",
|
||||
"<b>'Christmas' is locked</b>.",
|
||||
)
|
||||
self.assertEqual(
|
||||
lock.get_message(moderator),
|
||||
"<b>Page 'Christmas' is locked</b> by <b>you</b>.",
|
||||
"<b>'Christmas' is locked</b> by <b>you</b>.",
|
||||
)
|
||||
|
||||
@override_settings(WAGTAILADMIN_GLOBAL_EDIT_LOCK=True)
|
||||
|
@ -3611,11 +3611,11 @@ class TestGetLock(TestCase):
|
|||
self.assertTrue(lock.for_user(moderator))
|
||||
self.assertEqual(
|
||||
lock.get_message(christmas_event.owner),
|
||||
f"<b>Page 'Christmas' was locked</b> by <b>{str(moderator)}</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
f"<b>'Christmas' was locked</b> by <b>{str(moderator)}</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
)
|
||||
self.assertEqual(
|
||||
lock.get_message(moderator),
|
||||
"<b>Page 'Christmas' was locked</b> by <b>you</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
"<b>'Christmas' was locked</b> by <b>you</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
)
|
||||
|
||||
@override_settings(WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK=True)
|
||||
|
@ -3640,11 +3640,11 @@ class TestGetLock(TestCase):
|
|||
|
||||
self.assertEqual(
|
||||
lock.get_message(christmas_event.owner),
|
||||
f"<b>Page 'Christmas' was locked</b> by <b>{str(moderator)}</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
f"<b>'Christmas' was locked</b> by <b>{str(moderator)}</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
)
|
||||
self.assertEqual(
|
||||
lock.get_message(moderator),
|
||||
"<b>Page 'Christmas' was locked</b> by <b>you</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
"<b>'Christmas' was locked</b> by <b>you</b> on <b>29 Jul 2022 12:19</b>.",
|
||||
)
|
||||
|
||||
def test_when_locked_by_workflow(self):
|
||||
|
|
Ładowanie…
Reference in New Issue