Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎛️ Replace base ExpandingFormset functionality with Stimulus FormsetController w-formset inc. initial adoption #11633

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

lb-
Copy link
Member

@lb- lb- commented Feb 11, 2024

First stage of #7915

Overview

  • Introduces a new Stimulus class FormsetController with the identifier w-formset with the longer term plan for this to be used for the InlinePanel JS functionality also.
  • Introduces a refactor of our common code for Django's formsets that streamlines how we set the delete input widget and prepares some of the Stimulus data attributes for use in the templates. This is a new base mixin wagtail.admin.forms.formsets.BaseFormSetMixin (happy for a different name to be suggested).
  • Replaces only the basic expanding formset usage in Group edit/create views, Workflow edit/create (Page selection only) with the Stimulus usage. No changes to InlinePanel at all.
  • Most importantly, this new approach is CSP compliant, has validation error messaging feedback for developers and does not rely on any complex id string wrangling, with fully tested support for complex nested usage.
    • Stimulus does most of this for us through the Stimulus Scopes feature.
    • I've left all nested IDs in place in the templates as there is no major need to remove these for now, but they're no longer used for any JS behaviour.

Additional notes

  • Introduces event dispatching for the expanding formsets to align with the InlinePanel https://docs.wagtail.org/en/stable/reference/pages/panels.html#inline-panel-events (have not documented, I thought release notes would be enough for this as it's not really used by customised code).
  • Removes the reliance on jQuery animations by introducing a function (which we can share later) that uses a promise callback for 'hiding' after an animation/transition is completed on an element without having to hard-code how long we expect the animation to take. For example, we can change the selected class to be ...-200 and the hidden attribute will be set after 200ms instead of the current 300. This reduces a common issue where we get the animation timing and the attribute updating out of sync causing chunky animations or confusing delays.
  • Commits are broken up to be a step by step creation and adoption of this new code, hopefully making reviewing easier.
  • instead of style display none, now using hidden for when a child form is deleted. This is more appropriate for the UI as the element is essentially meant to be removed.
  • There will be a subtle change in behaviour between the current, if you add 1001 children in any of the usage below. Currently, this would fail on server submit, however, with this change the add button will simply not add any more. I can change this to introduce a new option to ignore min/max but it seemed to make sense to keep this initial adoption simpler even with that edge case behaviour difference.
  • Naming of 'formset' vs 'form_set'
    • I have opted for FormSet in the Python class names, this is what Django uses.
    • formsets.py for the file in our admin files, again, following the Django convention.
    • FormsetController/w-formset (not FormSetController/w-form-set) in the Javascript code for brevity and alignment with our existing set up event names on the InlinePanel code (e.g. w-formset:added).
  • Naming of the 'removed' event vs (delete/deleted action/code).

Checklist

  • Do the tests still pass?
  • Does the code comply with the style guide?
  • For Python changes: Have you added tests to cover the new/fixed behaviour?
  • For front-end changes: Did you test on all of Wagtail’s supported environments? Chrome, Safari, Firefox all manually tested
  • For new features: Has the documentation been updated accordingly? (Upgrade considerations added)

How to test

  1. Workflow edit, workflow create - validate that the pages sections all update correctly when adding/removing.
  2. Workflow edit for a disabled workflow, check the console has no errors and the content is not visible for page selection as per current code.
  3. User group create/edit - validate the page permissions and other non-page permissions changes.
  4. For the above, check things still work as expected on Save with a POST form failure.

Copy link

squash-labs bot commented Feb 11, 2024

Manage this branch in Squash

Test this branch here: https://lb-featureformset-controller-i-hijkj.squash.io

@lb- lb- force-pushed the feature/formset-controller-initial-adoption branch from fc9c794 to 4fa1a29 Compare February 11, 2024 08:58
@lb- lb- changed the title 🎛️ Migrate base ExpandingFormset functionality to Stimulus FormsetController w-formset inc. initial adoption 🎛️ Replace base ExpandingFormset functionality with Stimulus FormsetController w-formset inc. initial adoption Feb 11, 2024
target.contains(input),
);

if (!deleteInput) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note. I could not easily write a unit test for this error case due to Stimulus not catching these errors.

hotwired/stimulus#711

I have manually tested this scenario though and it does correctly throw in the console without breaking the whole Controller behaviour.

{% include "wagtailadmin/permissions/includes/collection_member_permissions_form.html" with form=formset.empty_form only %}
</tr>
</template>

<p class="add">
<button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" value="Add" type="button">{% icon name="plus" wrapped=1 %}{% block add_button_label %}{% endblock %}</button>
<button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" type="button" data-action="w-formset#add">{% icon name="plus" wrapped=1 %}{% block add_button_label %}{% endblock %}</button>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" type="button" data-action="w-formset#add">{% icon name="plus" wrapped=1 %}{% block add_button_label %}{% endblock %}</button>
<button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" value="Add" type="button" data-action="w-formset#add">{% icon name="plus" wrapped=1 %}{% block add_button_label %}{% endblock %}</button>

Accidentally removed value="Add". I actually think we should not be setting the value on these buttons as it's not used visually and I'm pretty sure it's not used by the server.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#value

Probably an investigation for a different issue.

@lb-
Copy link
Member Author

lb- commented Feb 29, 2024

Rebased after #11620 - we can now remove even more bespoke JS imports across the user group edit/create views. Yay.

@gasman gasman self-requested a review March 6, 2024 09:53
@lb-
Copy link
Member Author

lb- commented Mar 17, 2024

While this PR is not a fix for #11760 it's a good note that developers are expecting all features to work across ModelViewSet / Snippet views without having to think about what JS to import.

Hence, I am keen to get on the task of migrating InlinePanel once this PR is in.

@lb- lb- force-pushed the feature/formset-controller-initial-adoption branch from 371f6e9 to bbad762 Compare March 21, 2024 20:38
lb- added 6 commits March 23, 2024 14:56
Replaces the core functionality in `client/src/components/ExpandingFormset/index.js` and the Delete callbacks in other usage of the `window.buildExpandingFormset` function.

Provides limitations on add/delete once the min/max have been reached but does not set up any disabling of these buttons as this is currently in the remit of `InlinePanel`.

Includes a full test suite for error handling, updating inputs and nested usage which leverages Stimulus' scope management.

Does not rely on any id attribute structure or wrangling.

Relates to wagtail#7915
- Leverage the new Django 4.0 feature `deletion_widget` for formsets to attach data attributes and make the input a HiddenInput for existing and 'blank' forms.
- Add support for data attributes used by the new Stimulus FormsetController
- Use the Wagtail admin formset mixin to adopt new data attributes on core form parts
- Update the edit/create templates to put the attributes on the remaining elements
- Add basic unit tests for smoke testing data attributes
- Remove CSP incompatible inline scripts approach
- Remove the now unused standalone static build/imports for the group edit view as this will not be needed
- Ensure that the edit workflow form does not render any JS or attributes when the pages are not actually editable (workflow disabled)
- Use the Wagtail admin formset mixin to adopt new data attributes on core form parts
- Update the edit/create templates to put the attributes on the remaining elements
- Add basic unit tests for smoke testing data attributes
- Remove CSP incompatible inline scripts approach
- Remove the now unused standalone static build/imports for the group edit view as this will not be needed
- Update Eslint accordingly
- window.buildExpandingFormset and using the base class `ExpandingFormset` can now be deprecated.
- Move the window global setting to core.js which avoids the need to add the import in editor_js, to align with other future deprecations in core.js
- Add upgrade considerations in release notes
- `ExpandingFormset` is still needed for other existing usage (InlinePanel/MultipleChooserPanel)
- Add additional JSDoc and updates to Eslint to advise developers that this feature is not to be used for new code
@lb- lb- force-pushed the feature/formset-controller-initial-adoption branch from bbad762 to 147aa91 Compare March 23, 2024 04:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Review
Status: 👀 for review
Development

Successfully merging this pull request may close these issues.

None yet

1 participant