kopia lustrzana https://github.com/wagtail/wagtail
Co-authored-by: Thibaud Colas <thibaudcolas@gmail.com>pull/8008/head
rodzic
0012c344d9
commit
910844eb30
|
@ -21,6 +21,7 @@ Changelog
|
|||
* Add ability to select multiple items at once within bulk actions selections when holding shift on subsequent clicks (Hitansh Shah)
|
||||
* Upgrade notification, shown to admins on the dashboard if Wagtail is out of date, will now link to the release notes for the closest minor branch instead of the latest patch (Tibor Leupold)
|
||||
* Upgrade notification can now be configured to only show updates when there is a new LTS available via `WAGTAIL_ENABLE_UPDATE_CHECK = 'lts'` (Tibor Leupold)
|
||||
* Implement redesign of the Workflow Status dialog, fixing accessibility issues (Steven Steinwand)
|
||||
* Fix: Typo in `ResumeWorkflowActionFormatter` message (Stefan Hammer)
|
||||
* Fix: Throw a meaningful error when saving an image to an unrecognised image format (Christian Franke)
|
||||
* Fix: Remove extra padding for headers with breadcrumbs on mobile viewport (Steven Steinwand)
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
.workflow-timeline {
|
||||
@apply w-label-3;
|
||||
padding: 0;
|
||||
margin-top: theme('spacing.8');
|
||||
margin-bottom: theme('spacing.3');
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-top: theme('spacing.10');
|
||||
margin-bottom: theme('spacing.10');
|
||||
}
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding-bottom: theme('spacing.5');
|
||||
|
||||
&--rejected {
|
||||
color: theme('colors.critical.200');
|
||||
}
|
||||
|
||||
&--approved {
|
||||
color: theme('colors.positive.100');
|
||||
}
|
||||
|
||||
&--in_progress {
|
||||
@apply w-label-1;
|
||||
}
|
||||
|
||||
&--pending {
|
||||
color: theme('colors.grey.400');
|
||||
|
||||
.icon {
|
||||
color: theme('colors.grey.200');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
background: theme('colors.white.DEFAULT');
|
||||
margin-inline-end: theme('spacing.[2.5]');
|
||||
width: theme('spacing.5');
|
||||
height: theme('spacing.5');
|
||||
z-index: theme('zIndex.10');
|
||||
}
|
||||
|
||||
&__line {
|
||||
position: absolute;
|
||||
margin-inline-start: -1px;
|
||||
height: 100%;
|
||||
top: theme('spacing.4');
|
||||
inset-inline-start: theme('spacing.[2.5]');
|
||||
border-inline-start: theme('borderWidth.DEFAULT') dashed
|
||||
theme('colors.grey.200');
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: theme('spacing.4');
|
||||
}
|
||||
|
||||
&__footer-link {
|
||||
@include transition(color 0.15s ease);
|
||||
font-size: theme('fontSize.14');
|
||||
color: theme('colors.teal.200');
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: theme('colors.teal.600');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -134,6 +134,7 @@ These are classes for components.
|
|||
@import 'components/button-select';
|
||||
@import 'components/skiplink';
|
||||
@import 'components/workflow-tasks';
|
||||
@import 'components/workflow-timeline';
|
||||
@import 'components/switch';
|
||||
@import 'components/bulk_actions';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ export const dialog = (
|
|||
) => {
|
||||
dialogs.forEach((template) => {
|
||||
const html = document.documentElement;
|
||||
const templateContent = template.content.firstElementChild.cloneNode(true);
|
||||
const templateContent = template.content.firstElementChild;
|
||||
document.body.appendChild(templateContent);
|
||||
const dialogTemplate = new A11yDialog(templateContent);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ depth: 1
|
|||
* Add ability to select multiple items at once within bulk actions selections when holding shift on subsequent clicks (Hitansh Shah)
|
||||
* Upgrade notification, shown to admins on the dashboard if Wagtail is out of date, will now link to the release notes for the closest minor branch instead of the latest patch (Tibor Leupold)
|
||||
* Upgrade notification can now be configured to only show updates when there is a new LTS available via `WAGTAIL_ENABLE_UPDATE_CHECK = 'lts'` (Tibor Leupold)
|
||||
* Implement redesign of the Workflow Status dialog, fixing accessibility issues (Steven Steinwand)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
|
|
@ -625,54 +625,7 @@ footer .preview {
|
|||
}
|
||||
}
|
||||
|
||||
.workflow-timeline {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
margin-bottom: 1.25em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
li:not(:last-child)::after {
|
||||
content: '';
|
||||
color: $color-grey-3;
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
inset-inline-start: calc(0.75em - 1px);
|
||||
height: 100%;
|
||||
border-inline-start: 2px dotted;
|
||||
}
|
||||
|
||||
.icon {
|
||||
fill: $color-grey-3;
|
||||
padding-inline-end: 0.5em;
|
||||
}
|
||||
|
||||
.in_progress {
|
||||
font-weight: 700;
|
||||
|
||||
.icon {
|
||||
fill: $color-text-base;
|
||||
}
|
||||
}
|
||||
|
||||
.approved .icon {
|
||||
fill: $color-teal;
|
||||
}
|
||||
|
||||
.needs_changes .icon,
|
||||
.rejected .icon {
|
||||
fill: $color-orange;
|
||||
}
|
||||
|
||||
.cancelled .icon {
|
||||
fill: $color-red-dark;
|
||||
}
|
||||
}
|
||||
|
||||
// Media for Windows High Contrast
|
||||
|
||||
@media (forced-colors: $media-forced-colours) {
|
||||
.object {
|
||||
border-top: 1px solid GrayText;
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
{% if workflow_state.created_at %}
|
||||
{% timesince_last_update workflow_state.created_at user_display_name=workflow_state.requested_by|user_display_name use_shorthand=True as help_text %}
|
||||
{% endif %}
|
||||
{% url 'wagtailadmin_pages:workflow_status' page.id as action_url %}
|
||||
{% trans 'View details' as action_text %}
|
||||
|
||||
{# Icon #}
|
||||
|
@ -63,8 +62,24 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block action %}
|
||||
{% if workflow_state %}
|
||||
{% include 'wagtailadmin/pages/side_panels/includes/side_panel_button.html' with attr='data-action-workflow-status' data_url=action_url text=action_text %}
|
||||
{% if workflow_state and not hide_action %}
|
||||
{% trans 'Moderators approval' as workflow_dialog_title %}
|
||||
{% dialog_toggle class_name='w-bg-transparent w-text-14 w-p-0 w-text-teal-200 hover:w-text-teal-600 w-inline-flex w-justify-center w-transition' dialog_id="workflow-status-dialog" text=action_text %}
|
||||
|
||||
{# info subtitle #}
|
||||
{% if page.get_latest_revision %}
|
||||
{% workflow_status_with_date workflow_state as message_heading %}
|
||||
{% if workflow_state.requested_by %}
|
||||
{% blocktrans trimmed with user=workflow_state.requested_by|user_display_name asvar modified_by %}by {{ user }}{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% dialog id="workflow-status-dialog" icon_name="list-ul" title=workflow_dialog_title message_status='info' message_heading=message_heading|add:' '|add:modified_by %}
|
||||
{% include 'wagtailadmin/workflows/workflow_status.html' %}
|
||||
{% enddialog %}
|
||||
{% else %}
|
||||
{% dialog id="workflow-status-dialog" icon_name="list-ul" title=workflow_dialog_title %}
|
||||
{% include 'wagtailadmin/workflows/workflow_status.html' %}
|
||||
{% enddialog %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% url 'wagtailadmin_pages:history' page.id as action_url %}
|
||||
{% trans 'View history' as action_text %}
|
||||
|
@ -79,22 +94,7 @@
|
|||
<div class="w-flex w-space-x-3 w-mt-3">
|
||||
{% icon name='info-circle' class_name='w-w-4 w-h-4 w-text-info-100 w-shrink-0' %}
|
||||
<div class="w-label-3 w-flex-1">
|
||||
{% if workflow_state.status == 'needs_changes' %}
|
||||
{% blocktrans trimmed with time_ago=workflow_state.current_task_state.finished_at|naturaltime %}
|
||||
Changes requested {{ time_ago }}
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% with time_ago=workflow_state.current_task_state.started_at|naturaltime workflow_task=workflow_state.current_task_state.task.name %}
|
||||
{% if workflow_state.status == "in_progress" %}
|
||||
{% blocktrans trimmed %}Sent to {{ workflow_task }} {{ time_ago }}{% endblocktrans %}
|
||||
{% else %}
|
||||
{{ workflow_state.get_status_display }} {{ workflow_task }} {{ time_ago }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% if workflow_state.requested_by %}
|
||||
{% blocktrans trimmed with modified_by=workflow_state.requested_by|user_display_name %}by {{ modified_by }}{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% workflow_status_with_date workflow_state %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,67 +1,84 @@
|
|||
{% load wagtailadmin_tags i18n %}
|
||||
|
||||
{% include "wagtailadmin/shared/header.html" with title=workflow_state.workflow.name icon="tasks" %}
|
||||
<ol class="workflow-timeline">
|
||||
|
||||
<div class="nice-padding">
|
||||
{% if page.get_latest_revision %}
|
||||
<p>
|
||||
{% blocktrans trimmed with workflow_name=workflow_state.workflow.name started_at=workflow_state.created_at %}
|
||||
Submitted to <em>{{ workflow_name }}</em> at {{ started_at }}
|
||||
{% endblocktrans %}
|
||||
{% if workflow_state.requested_by %}
|
||||
{% blocktrans trimmed with modified_by=workflow_state.requested_by|user_display_name %}by {{ modified_by }}{% endblocktrans %}
|
||||
<span class="avatar small"><img src="{% avatar_url page.get_latest_revision.user size=25 %}" alt="" /></span>
|
||||
{% endif %}
|
||||
</p>
|
||||
<li class="workflow-timeline__item workflow-timeline__item--approved">
|
||||
<div class="workflow-timeline__line"></div>
|
||||
{% icon name="circle-check" class_name="workflow-timeline__icon" %}
|
||||
{% trans "Submitted" %}
|
||||
</li>
|
||||
|
||||
{# Workflow tasks #}
|
||||
{% trans "Not started" as not_started_text %}
|
||||
{% if workflow_state %}
|
||||
{% for task in workflow_state.all_tasks_with_state %}
|
||||
{% with status=task.task_state.status status_display=task.task_state.get_status_display|default:not_started_text %}
|
||||
<li class="workflow-timeline__item workflow-timeline__item--{{ status|default:"pending" }}">
|
||||
<div class="workflow-timeline__line"></div>
|
||||
{% if status == "rejected" %}
|
||||
<div class="w-flex">
|
||||
{% icon name="warning" class_name="workflow-timeline__icon" title=status_display %}
|
||||
<div class="w-flex w-flex-col">
|
||||
<strong>{{ task.name }}</strong>
|
||||
{% if task.task_state.finished_by %}
|
||||
{% blocktrans trimmed with requested_by=task.task_state.finished_by|user_display_name %}
|
||||
Changes requested by {{ requested_by }}
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% trans "Changes requested" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% icon name="circle-check" class_name="workflow-timeline__icon" title=status_display %}
|
||||
{{ task.name }}
|
||||
{% if task.task_state.finished_by %}
|
||||
{% blocktrans trimmed with approved_by=task.task_state.finished_by|user_display_name %}
|
||||
Approved by {{ approved_by }}
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if task.task_state and task.task_state.get_comment %}
|
||||
<div class="w-ml-[1.875rem] w-w-full">
|
||||
{% trans "with comment:" %} <em>"{{ task.task_state.get_comment }}"</em>
|
||||
</div>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<ul class="workflow-timeline">
|
||||
<li class="approved">{% icon name="success" class_name="default" %}{% trans "Submitted" %}</li>
|
||||
{% trans "Not started" as not_started_text %}
|
||||
{% for task in workflow_tasks %}
|
||||
<li data-wagtail-tooltip="{{ task.name }}: {{ task.task_state.get_status_display|default:not_started_text }}" {% if task.task_state and task.task_state.status %}class="{{ task.task_state.status }}"{% endif %}>
|
||||
{% if task.task_state.status == "rejected" %}
|
||||
{% icon name="warning" class_name="default" %}<strong>{{ task.name }}</strong>
|
||||
{# Published status #}
|
||||
<li class="workflow-timeline__item workflow-timeline__item--pending">
|
||||
{% icon name="circle-check" class_name="workflow-timeline__icon" %}{% trans "Published" %}
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
{% if task.task_state.finished_by %}
|
||||
{% blocktrans trimmed with requested_by=task.task_state.finished_by|user_display_name %}
|
||||
Changes requested by {{ requested_by }}
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% trans "Changes requested" %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% icon name="success" class_name="default" %}{{ task.name }}
|
||||
{% if task.task_state.finished_by %}
|
||||
{% blocktrans trimmed with approved_by=task.task_state.finished_by|user_display_name %}
|
||||
Approved by {{ approved_by }}
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if task.task_state and task.task_state.get_comment %}
|
||||
{% trans "with comment:" %} <em>"{{ task.task_state.get_comment }}"</em>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li>{% icon name="success" class_name="default" %}{% trans "Published" %}</li>
|
||||
</ul>
|
||||
{# Footer Actions #}
|
||||
<div class="workflow-timeline__footer">
|
||||
<a href="{% url 'wagtailadmin_pages:history' page.id %}" class="button">
|
||||
{% trans "See full history" %}
|
||||
</a>
|
||||
|
||||
<p>
|
||||
<a href="{% url 'wagtailadmin_pages:history' page.id %}" class="button button-small">
|
||||
{% trans "See full history" %}
|
||||
</a>
|
||||
{% with page.get_latest_revision as latest_revision %}
|
||||
{% with page.get_latest_revision as latest_revision %}
|
||||
<div class="w-flex">
|
||||
{% if page.live_revision %}
|
||||
<a href="{% url 'wagtailadmin_pages:revisions_compare' page.id 'live' latest_revision.id %}" class="button button-small button-secondary">
|
||||
<a href="{% url 'wagtailadmin_pages:revisions_compare' page.id 'live' latest_revision.id %}" class="workflow-timeline__footer-link">
|
||||
{% trans "Compare with live version" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% with latest_revision.get_previous as previous_revision %}
|
||||
{% if previous_revision %}
|
||||
<a href="{% url 'wagtailadmin_pages:revisions_compare' page.id previous_revision.id latest_revision.id %}" class="button button-small button-secondary">{% trans 'Compare with previous version' %}</a>
|
||||
{# Only show the separator if there are two links. #}
|
||||
{% if page.live_revision %}
|
||||
<div class="w-mx-2" aria-hidden="true">|</div>
|
||||
{% endif %}
|
||||
<a href="{% url 'wagtailadmin_pages:revisions_compare' page.id previous_revision.id latest_revision.id %}"
|
||||
class="workflow-timeline__footer-link">{% trans 'Compare with previous version' %}</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
</p>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -963,3 +963,21 @@ def dialog_toggle(dialog_id, class_name="", text=None):
|
|||
# dialog_id must match the ID of the dialog you are toggling
|
||||
"dialog_id": dialog_id,
|
||||
}
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def workflow_status_with_date(workflow_state):
|
||||
translation_context = {
|
||||
"finished_at": naturaltime(workflow_state.current_task_state.finished_at),
|
||||
"started_at": naturaltime(workflow_state.current_task_state.started_at),
|
||||
"task_name": workflow_state.current_task_state.task.name,
|
||||
"status_display": workflow_state.get_status_display,
|
||||
}
|
||||
|
||||
if workflow_state.status == "needs_changes":
|
||||
return _("Changes requested %(finished_at)s") % translation_context
|
||||
|
||||
if workflow_state.status == "in_progress":
|
||||
return _("Sent to %(task_name)s %(started_at)s") % translation_context
|
||||
|
||||
return _("%(status_display)s %(task_name)s %(started_at)s") % translation_context
|
||||
|
|
|
@ -915,10 +915,6 @@ class TestSubmitToWorkflow(TestCase, WagtailTestUtils):
|
|||
self.submit()
|
||||
|
||||
response = self.client.get(edit_url)
|
||||
workflow_status_url = reverse(
|
||||
"wagtailadmin_pages:workflow_status", args=(self.page.id,)
|
||||
)
|
||||
self.assertContains(response, workflow_status_url)
|
||||
self.assertRegex(
|
||||
response.content.decode("utf-8"),
|
||||
r"Sent to[\s|\n]+{}".format(self.page.current_workflow_task.name),
|
||||
|
@ -2334,28 +2330,30 @@ class TestWorkflowStatus(TestCase, WagtailTestUtils):
|
|||
)
|
||||
|
||||
def test_workflow_status_modal(self):
|
||||
workflow_status_url = reverse(
|
||||
"wagtailadmin_pages:workflow_status", args=(self.page.id,)
|
||||
)
|
||||
|
||||
# The page workflow status view should return permission denied when the page is but a draft
|
||||
response = self.client.get(workflow_status_url)
|
||||
self.assertRedirects(response, "/admin/")
|
||||
response = self.client.get(self.edit_url)
|
||||
html = response.content.decode("utf-8")
|
||||
self.assertNotIn('id="workflow-status-dialog"', html)
|
||||
|
||||
# Submit for moderation
|
||||
self.submit()
|
||||
|
||||
response = self.client.get(workflow_status_url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
html = response.json().get("html")
|
||||
self.assertIn(self.task_1.name, html)
|
||||
self.assertIn("{}: In progress".format(self.task_1.name), html)
|
||||
self.assertIn(self.task_2.name, html)
|
||||
self.assertIn("{}: Not started".format(self.task_2.name), html)
|
||||
response = self.client.get(self.edit_url)
|
||||
html = response.content.decode("utf-8")
|
||||
self.assertIn(
|
||||
"In progress\n </span>\n {}".format(
|
||||
self.task_1.name
|
||||
),
|
||||
html,
|
||||
)
|
||||
self.assertIn(
|
||||
"Not started\n </span>\n {}".format(
|
||||
self.task_2.name
|
||||
),
|
||||
html,
|
||||
)
|
||||
self.assertIn(reverse("wagtailadmin_pages:history", args=(self.page.id,)), html)
|
||||
|
||||
self.assertTemplateUsed(response, "wagtailadmin/workflows/workflow_status.html")
|
||||
|
||||
def test_status_through_workflow_cycle(self):
|
||||
self.login(self.superuser)
|
||||
response = self.client.get(self.edit_url)
|
||||
|
@ -2415,20 +2413,16 @@ class TestWorkflowStatus(TestCase, WagtailTestUtils):
|
|||
)
|
||||
|
||||
def test_workflow_status_modal_task_comments(self):
|
||||
workflow_status_url = reverse(
|
||||
"wagtailadmin_pages:workflow_status", args=(self.page.id,)
|
||||
)
|
||||
|
||||
self.submit()
|
||||
self.workflow_action("reject")
|
||||
|
||||
response = self.client.get(workflow_status_url)
|
||||
self.assertIn("needs some changes", response.json().get("html"))
|
||||
response = self.client.get(self.edit_url)
|
||||
self.assertIn("needs some changes", response.content.decode("utf-8"))
|
||||
|
||||
self.submit()
|
||||
self.workflow_action("approve")
|
||||
response = self.client.get(workflow_status_url)
|
||||
self.assertIn("good work", response.json().get("html"))
|
||||
response = self.client.get(self.edit_url)
|
||||
self.assertIn("good work", response.content.decode("utf-8"))
|
||||
|
||||
def test_workflow_edit_locked_message(self):
|
||||
self.submit()
|
||||
|
|
Ładowanie…
Reference in New Issue