Migrate lock/unlock actions to w-action controller

- Revise 'redirect' from a string to a 'continue' boolean that defaults to false
- Use 'continue=true' for cases where we do not want to create a next param on submit that takes the user back to the current page
- Fixes #9815
pull/9899/head
Lovelyfin00 2023-01-04 07:21:35 +01:00 zatwierdzone przez LB (Ben Johnston)
rodzic 9e9a84c953
commit b929694203
22 zmienionych plików z 105 dodań i 91 usunięć

Wyświetl plik

@ -119,7 +119,7 @@ Changelog
* Maintenance: Refactor userbar styles to use the same stylesheet as other components (Thibaud Colas)
* Maintenance: Add deprecation warnings for `wagtail.core` and other imports deprecated in Wagtail 3.0 (Matt Westcott)
* Maintenance: Migrate admin upgrade notification message implementation to a Stimulus controller (Loveth Omokaro)
* Maintenance: Migrate workflow and workflow tasks enable action to a Stimulus controller (Loveth Omokaro)
* Maintenance: Migrate workflow and workflow tasks enable action and lock/unlock actions to a Stimulus controller (Loveth Omokaro)
* Maintenance: Pull out icon sprite setup function from inline script to its own TypeScript file & add unit tests (Loveth Omokaro)

Wyświetl plik

@ -0,0 +1,39 @@
import React from 'react';
import { StimulusWrapper } from '../../storybook/StimulusWrapper';
import { ActionController } from './ActionController';
export default {
title: 'Shared / ActionController',
argTypes: {
debug: {
control: 'boolean',
defaultValue: false,
},
},
};
const definitions = [
{
identifier: 'w-action',
controllerConstructor: ActionController,
},
];
const Template = ({ debug = false }) => (
<StimulusWrapper debug={debug} definitions={definitions}>
<button
type="button"
className="button button-small button-secondary"
data-controller="w-action"
data-action="w-action#post"
data-w-action-url-value={window.location.href}
>
Lock
</button>
<p>Click to lock post and redirect</p>
</StimulusWrapper>
);
export const Base = Template.bind({});

Wyświetl plik

@ -16,17 +16,17 @@ describe('ActionController', () => {
Application.start().register('w-action', ActionController);
});
it('it should enable the workflow on click', () => {
it('it should enable the workflow, lock and Unlock button', () => {
const btn = document.querySelector('[data-controller="w-action"]');
const submitMock = jest.fn();
window.HTMLFormElement.prototype.submit = submitMock;
btn.click();
const form = document.querySelector('form');
expect(submitMock).toHaveBeenCalled();
expect(form.action).toBe('https://www.github.com/');
expect(new FormData(form).get('csrfmiddlewaretoken')).toBe('potato');
expect(new FormData(form).get('next')).toBe('http://localhost/');
});
});

Wyświetl plik

@ -2,20 +2,26 @@ import { Controller } from '@hotwired/stimulus';
import { WAGTAIL_CONFIG } from '../config/wagtailConfig';
/**
* <button type="submit" class="button no"
* data-controller="w-action"
* data-action="click->w-action#post"
* data-w-action-redirect-value="true"
* data-w-action-url-value = '{{ view.get_enable_url }}'>Enable</button>
*
* @example
* <button
* type="submit"
* class="button no"
* data-controller="w-action"
* data-action="w-action#post"
* data-w-action-url-value='url/to/post/to'
* >
* Enable
* </button>
*/
export class ActionController extends Controller {
static values = {
redirect: String,
continue: { type: Boolean, default: false },
url: String,
};
continueValue: boolean;
urlValue: string;
redirectValue: any;
post(event: Event) {
event.preventDefault();
@ -32,7 +38,10 @@ export class ActionController extends Controller {
csrftokenElement.value = WAGTAIL_CONFIG.CSRF_TOKEN;
formElement.appendChild(csrftokenElement);
if (this.redirectValue) {
/** If continue is false, pass the current URL as the next param
* so that the user is redirected back to the current page instead
* of continuing to the submitted page */
if (!this.continueValue) {
const nextElement = document.createElement('input');
nextElement.type = 'hidden';
nextElement.name = 'next';

Wyświetl plik

@ -10,7 +10,7 @@ import { UpgradeController } from './UpgradeController';
* Important: Only add default core controllers that should load with the base admin JS bundle.
*/
export const coreControllerDefinitions: Definition[] = [
// Keep this list alphabetized.
// Keep this list in alphabetical order
{ controllerConstructor: ActionController, identifier: 'w-action' },
{ controllerConstructor: AutoFieldController, identifier: 'w-auto-field' },
{ controllerConstructor: SkipLinkController, identifier: 'w-skip-link' },

Wyświetl plik

@ -1,37 +0,0 @@
/* When a lock/unlock action button is clicked, make a POST request to the relevant view */
function LockUnlockAction(csrfToken, next) {
const actionElements = document.querySelectorAll('[data-action-lock-unlock]');
actionElements.forEach((buttonElement) => {
buttonElement.addEventListener(
'click',
(e) => {
e.stopPropagation();
const formElement = document.createElement('form');
formElement.action = buttonElement.dataset.url;
formElement.method = 'POST';
const csrftokenElement = document.createElement('input');
csrftokenElement.type = 'hidden';
csrftokenElement.name = 'csrfmiddlewaretoken';
csrftokenElement.value = csrfToken;
formElement.appendChild(csrftokenElement);
if (typeof next !== 'undefined') {
const nextElement = document.createElement('input');
nextElement.type = 'hidden';
nextElement.name = 'next';
nextElement.value = next;
formElement.appendChild(nextElement);
}
document.body.appendChild(formElement);
formElement.submit();
},
{ capture: true },
);
});
}
window.LockUnlockAction = LockUnlockAction;

Wyświetl plik

@ -41,7 +41,6 @@ module.exports = function exports(env, argv) {
'expanding-formset',
'filtered-select',
'icons',
'lock-unlock-action',
'modal-workflow',
'page-chooser-modal',
'page-chooser',

Wyświetl plik

@ -158,7 +158,7 @@ Thank you to all who provided feedback, participants to our usability testing se
* Refactor userbar styles to use the same stylesheet as other components (Thibaud Colas)
* Add deprecation warnings for `wagtail.core` and other imports deprecated in Wagtail 3.0 (Matt Westcott)
* Migrate admin upgrade notification message implementation to a Stimulus controller (Loveth Omokaro)
* Migrate workflow and workflow tasks enable action to a Stimulus controller (Loveth Omokaro)
* Migrate workflow and workflow tasks enable action and lock/unlock actions to a Stimulus controller (Loveth Omokaro)
* Pull out icon sprite setup function from inline script to its own TypeScript file & add unit tests (Loveth Omokaro)
## Upgrade considerations

Wyświetl plik

@ -31,7 +31,17 @@
</div>
<ul class="actions">
{% if can_remove_locks %}
<li><button data-action-lock-unlock data-url="{% url 'wagtailadmin_pages:unlock' page.id %}" class="button button-small button-secondary">{% trans "Unlock" %}</button></li>
<li>
<button
class="button button-small button-secondary"
data-controller="w-action"
data-action="w-action#post"
data-w-action-next-value="{% url 'wagtailadmin_home' %}"
data-w-action-url-value="{% url 'wagtailadmin_pages:unlock' page.id %}"
>
{% trans "Unlock" %}
</button>
</li>
{% endif %}
<li><a href="{% url 'wagtailadmin_pages:edit' page.id %}" class="button button-small button-secondary">{% trans "Edit" %}</a></li>
{% if page.has_unpublished_changes and page.is_previewable %}
@ -53,8 +63,4 @@
</tbody>
</table>
{% endpanel %}
<script src="{% versioned_static 'wagtailadmin/js/lock-unlock-action.js' %}"></script>
<script>
document.addEventListener('DOMContentLoaded', () => LockUnlockAction('{{ csrf_token|escapejs }}', '{% url 'wagtailadmin_home' %}'));
</script>
{% endif %}

Wyświetl plik

@ -28,6 +28,5 @@
<script src="{% versioned_static 'wagtailadmin/js/vendor/urlify.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/workflow-action.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/workflow-status.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/lock-unlock-action.js' %}"></script>
<script src="{% versioned_static 'wagtailadmin/js/vendor/bootstrap-tooltip.js' %}"></script>
{% hook_output 'insert_editor_js' %}

Wyświetl plik

@ -130,7 +130,6 @@
});
ActivateWorkflowActionsForEditView('#page-edit-form');
LockUnlockAction('{{ csrf_token|escapejs }}', '{% url 'wagtailadmin_pages:edit' page.id %}');
{% get_comments_enabled as comments_enabled %}
{% if comments_enabled %}

Wyświetl plik

@ -25,10 +25,6 @@
{% block extra_js %}
{{ block.super }}
<script src="{% versioned_static 'wagtailadmin/js/lock-unlock-action.js' %}"></script>
<script>
document.addEventListener('DOMContentLoaded', () => LockUnlockAction('{{ csrf_token|escapejs }}', '{% url 'wagtailadmin_home' %}'));
</script>
{% comment %} modal-workflow is required by the view restrictions interface {% endcomment %}
<script src="{% versioned_static 'wagtailadmin/js/modal-workflow.js' %}"></script>

Wyświetl plik

@ -9,7 +9,7 @@
attr - custom attributes for the button
{% endcomment %}
{% if text %}
<button type="button" class="{{ 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" {% if data_url %}data-url="{{ data_url }}" {% endif %}{% if has_toggle %}data-button-with-dropdown-toggle {% endif %}{{ attr }}>
<button type="button" class="{{ 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" {% if data_url %}data-controller="w-action" data-action="w-action#post" data-w-action-url-value="{{ data_url }}" {% endif %}{% if has_toggle %}data-button-with-dropdown-toggle {% endif %}{{ attr }}>
{{ text }}
{% if has_toggle %}
{% icon name='arrow-down' class_name='w-w-4 w-h-4 w-transition motion-reduce:w-transition-none' %}

Wyświetl plik

@ -78,10 +78,10 @@
{% block action %}
{% if user_can_unlock and lock %}
{% trans 'Unlock' as unlock_text %}
{% include 'wagtailadmin/shared/side_panels/includes/side_panel_button.html' with attr='data-action-lock-unlock' data_url=unlock_url text=unlock_text %}
{% include 'wagtailadmin/shared/side_panels/includes/side_panel_button.html' with data_url=unlock_url text=unlock_text %}
{% endif %}
{% if user_can_lock and not lock %}
{% trans 'Lock' as lock_text %}
{% include 'wagtailadmin/shared/side_panels/includes/side_panel_button.html' with attr='data-action-lock-unlock' data_url=lock_url text=lock_text %}
{% include 'wagtailadmin/shared/side_panels/includes/side_panel_button.html' with data_url=lock_url text=lock_text %}
{% endif %}
{% endblock %}

Wyświetl plik

@ -58,11 +58,15 @@
<ul>
{% if can_enable %}
<li>
<button class="button no"
data-action="w-action#post"
<button
class="button no"
data-controller="w-action"
data-w-action-url-value="{{ view.get_enable_url }}"
type="submit">{{ view.enable_item_label }}
data-action="w-action#post"
data-w-action-continue-value="true"
data-w-action-url-value='{{ view.get_enable_url }}'
type="submit"
>
{{ view.enable_item_label }}
</button>
</li>
{% elif can_disable %}

Wyświetl plik

@ -49,11 +49,15 @@
<ul>
{% if can_enable %}
<li>
<button class="button no"
data-action="w-action#post"
<button
class="button no"
data-controller="w-action"
data-w-action-url-value="{{ view.get_enable_url }}"
type="submit">{{ view.enable_item_label }}
data-action="w-action#post"
data-w-action-continue-value="true"
data-w-action-url-value = '{{ view.get_enable_url }}'
type="submit"
>
{{ view.enable_item_label }}
</button>
</li>
{% elif can_disable %}

Wyświetl plik

@ -154,11 +154,8 @@ class TestLocking(TestCase, WagtailTestUtils):
self.child_page.save()
response = self.client.get(reverse("wagtailadmin_home"))
self.assertContains(response, "Your locked pages")
# check that LockUnlockAction is present and passes a valid csrf token
self.assertRegex(
response.content.decode("utf-8"),
r"LockUnlockAction\(\'\w+\'\, \'\/admin\/'\)",
)
# check that Unlock button is present
self.assertContains(response, "Unlock")
def test_unlock_post(self):
# Lock the page

Wyświetl plik

@ -433,7 +433,7 @@ class CreateEditViewOptionalFeaturesMixin:
if lock_message:
if user_can_unlock:
lock_message = format_html(
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action-lock-unlock data-url="{}">{}</button></span>',
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{}">{}</button></span>',
lock_message,
self.get_unlock_url(),
_("Unlock"),
@ -441,7 +441,7 @@ class CreateEditViewOptionalFeaturesMixin:
if user_can_unschedule:
lock_message = format_html(
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action-lock-unlock data-url="{}">{}</button></span>',
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{}">{}</button></span>',
lock_message,
reverse(
self.revisions_unschedule_url_name,

Wyświetl plik

@ -391,7 +391,7 @@ class EditView(TemplateResponseMixin, ContextMixin, HookResponseMixin, View):
if lock_message:
if isinstance(self.lock, BasicLock) and self.page_perms.can_unlock():
lock_message = format_html(
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action-lock-unlock data-url="{}">{}</button></span>',
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{}">{}</button></span>',
lock_message,
reverse("wagtailadmin_pages:unlock", args=(self.page.id,)),
_("Unlock"),
@ -402,7 +402,7 @@ class EditView(TemplateResponseMixin, ContextMixin, HookResponseMixin, View):
and self.page_perms.can_unschedule()
):
lock_message = format_html(
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action-lock-unlock data-url="{}">{}</button></span>',
'{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{}">{}</button></span>',
lock_message,
reverse(
"wagtailadmin_pages:revisions_unschedule",

Wyświetl plik

@ -61,7 +61,6 @@
placement: 'bottom',
});
LockUnlockAction('{{ csrf_token|escapejs }}', '{{ action_url }}');
});
</script>
{% endblock %}

Wyświetl plik

@ -441,7 +441,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
# Should show unlock buttons, one in the message and one in the side panel
self.assertTagInHTML(
f'<button type="button" data-url="{unlock_url}" data-action-lock-unlock>Unlock</button>',
f'<button type="button" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{unlock_url}">Unlock</button>',
html,
count=2,
allow_extra_attrs=True,
@ -490,7 +490,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
# Should show unlock buttons, one in the message and one in the side panel
self.assertTagInHTML(
f'<button type="button" data-url="{unlock_url}" data-action-lock-unlock>Unlock</button>',
f'<button type="button" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{unlock_url}">Unlock</button>',
html,
count=2,
allow_extra_attrs=True,
@ -544,7 +544,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
# Should not show unlock buttons
self.assertTagInHTML(
f'<button type="button" data-url="{unlock_url}" data-action-lock-unlock>Unlock</button>',
f'<button type="button" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{unlock_url}">Unlock</button>',
html,
count=0,
allow_extra_attrs=True,
@ -595,7 +595,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
# Should not show the lock button
self.assertTagInHTML(
f'<button type="button" data-url="{lock_url}" data-action-lock-unlock>Lock</button>',
f'<button type="button" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{lock_url}">Lock</button>',
html,
count=0,
allow_extra_attrs=True,
@ -640,7 +640,7 @@ class TestEditLockedSnippet(BaseLockingTestCase):
# Should show the lock button
self.assertTagInHTML(
f'<button type="button" data-url="{lock_url}" data-action-lock-unlock>Lock</button>',
f'<button type="button" data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{lock_url}">Lock</button>',
html,
count=1,
allow_extra_attrs=True,

Wyświetl plik

@ -3049,7 +3049,7 @@ class TestScheduledForPublishLock(BaseTestSnippetEditView):
args=[self.test_snippet.pk, self.latest_revision.pk],
)
self.assertTagInHTML(
f'<button data-action-lock-unlock data-url="{unschedule_url}">Cancel scheduled publish</button>',
f'<button data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{unschedule_url}">Cancel scheduled publish</button>',
html,
count=1,
allow_extra_attrs=True,
@ -3115,7 +3115,7 @@ class TestScheduledForPublishLock(BaseTestSnippetEditView):
args=[self.test_snippet.pk, self.latest_revision.pk],
)
self.assertTagInHTML(
f'<button data-action-lock-unlock data-url="{unschedule_url}">Cancel scheduled publish</button>',
f'<button data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{unschedule_url}">Cancel scheduled publish</button>',
html,
count=0,
allow_extra_attrs=True,
@ -3177,7 +3177,7 @@ class TestScheduledForPublishLock(BaseTestSnippetEditView):
args=[self.test_snippet.pk, self.latest_revision.pk],
)
self.assertTagInHTML(
f'<button data-action-lock-unlock data-url="{unschedule_url}">Cancel scheduled publish</button>',
f'<button data-action="w-action#post" data-controller="w-action" data-w-action-url-value="{unschedule_url}">Cancel scheduled publish</button>',
html,
count=1,
allow_extra_attrs=True,