-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Refactor generic view subclasses to better reuse the generic templates and breadcrumbs #10884
Refactor generic view subclasses to better reuse the generic templates and breadcrumbs #10884
Conversation
Manage this branch in SquashTest this branch here: https://laymonagealmost-universal-brea-dzukh.squash.io |
fd814a3
to
b8bb58b
Compare
fe212f4
to
60d9a5a
Compare
@laymonage just a note that I created an umbrella/epic issue for tracking some of the conversion to class based views a while ago. It has some notes about adoption and breaking down of tasks. Not sure if it's still a useful way to manage this but in case you have not seen it I thought I would mention it here - #8365 |
df5f1f8
to
bd3f0a6
Compare
{% block main_header %} | ||
{% include "wagtailadmin/shared/header.html" with title=page_title subtitle=page_subtitle icon=header_icon merged=1 only %} | ||
{% endblock %} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The override is only necessary to pass merged=1
to the header template. Alternatively we can set it from the view, but I don't think it's worth adding more code to the view for something that would only change one CSS class which potentially would change in the future.
{% block header %} | ||
{{ block.super }} | ||
{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is necessary because we're overriding content
instead of main_content
, and the reason for that is because we don't want to use the nice-padding
wrapper div in this template.
{% block header %} | ||
{{ block.super }} | ||
{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same reason, no nice-padding
in this template. If nice-padding
is used, this isn't necessary and we can override the main_content
block instead
@@ -12,8 +12,10 @@ | |||
</a> | |||
<a href="{% url view.add_url_name %}" class="button bicolor button--icon">{% icon name="plus" wrapped=1 %}{{ view.add_item_label }}</a> | |||
{% endfragment %} | |||
{% include "wagtailadmin/shared/header.html" with title=view.page_title icon=view.header_icon extra_actions=workflow_actions %} | |||
{% include "wagtailadmin/shared/header.html" with title=page_title icon=header_icon extra_actions=workflow_actions %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just changing from view.page_title
and view.header_icon
to the page_title
and header_icon
directly for consistency, because the former uses the variables while the latter is resolved from the corresponding get_
methods and are available via WagtailAdminTemplateMixin.get_context_data()
{% trans "View users in this group" as users_str %} | ||
{% url 'wagtailusers_groups:users' group.id as group_users_url %} | ||
{% include "wagtailadmin/shared/header.html" with title=editing_str action_icon="user" action_url=group_users_url action_text=users_str subtitle=group.name icon="group" %} | ||
{% include "wagtailadmin/shared/header.html" with title=page_title action_icon="user" action_url=group_users_url action_text=users_str subtitle=page_subtitle icon="group" %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reusing the page_title
and page_subtitle
context variables instead of redefining them ad-hoc in the template. The resolved values are the same though
{% block extra_css %} | ||
{{ block.super }} | ||
{{ form.media.css }} | ||
{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already covered in wagtailadmin/generic/form.html
{% trans "Users" as users_str %} | ||
{% trans "Add a user" as add_a_user_str %} | ||
|
||
{% url "wagtailusers_users:add" as add_link %} | ||
{% include "wagtailadmin/shared/header.html" with subtitle=group.name title=users_str action_url=add_link action_text=add_a_user_str icon="user" search_url="wagtailusers_users:index" search_results_url=index_results_url %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rely on the view code to define the variables for the header and just reuse the includes from the generic template
def get_page_title(self): | ||
return _("Editing %(object)s") % {"object": self.object.get_username()} | ||
|
||
def get_page_subtitle(self): | ||
return "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reusing the format from the generic EditView
instead for consistency, where the title is Editing
and the subtitle is str(self.object)
. By default str()
returns the username, but this means now the title will reflect whatever is returned by __str__
instead of forcing it to be the username.
def get_page_subtitle(self): | ||
return "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm retaining the behaviour of showing "Add group" as the title (without subtitle) instead of the generic view's "New" title + capfirst({model_name})
subtitle, though we probably should change this for consistency with the generic view.
One downside I see with this is that in other languages, the correct form might be the other way around (model_name
+ "New").
However, the assumption of action + model_name
has been the case with the generic views so I suppose it's alright... I think ideally we should not have a design where page_title
and page_subtitle
is shown side-by-side to form a phrase, e.g. "Editing Muddy Waters", as this is the root cause of the aforementioned issue with other languages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the capfirst stuff has caused us translation issues in the past, probably best to avoid unless there is a critical reason to add it.
Thanks @lb- yep I'm aware of that issue, I think that is still handy to track the views needed refactoring. Might be a good candidate for Outreachy/GSoC participants as well, though ideally they need to have a good level of understanding in class-based views and Django templates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@laymonage this looks great to me.
I am happy to approve this and think it's another epic win for the next release, both in UI enhancements and also a more consistent approach to our admin templates.
- Workflows and tasks
- Users
- Groups
- Sites
- Locales
- Collections
- Snippets index
Is it worth calling out the block main_content/content structure in the upgrade considerations? I think existing custom template overrides would likely work OK but I know we document overriding template paths as a feature and it may be good to add this to the upgrade considerations.
We have not historically documented all template structure changes like this but I know we did do a brief overview of changes for some of the Breadcrumb /header templates in previous releases.
No blockers for this to be merged though, release notes addition can be added when you merge or after.
If it's ok, I will let you merge, not sure if you wanted to re-work some of the commits/squash a bit.
Thibaud and I discussed this again with our designers and while we are not against the idea of showing the breadcrumbs everywhere in the admin, there are nuances around the At the moment, the edit page for the Person snippet on bakerydemo for example, looks like the following: The text "Muddy Waters" shows up three times in different parts, close to each other. We explored the idea of merging the The breadcrumbs added in #10880 were not really intentional, as the main reason for that PR was so that we have a place to put the history icon link when we add Given the original motivation of #10880 and the design decisions that are yet to be made, it's likely we won't proceed with this PR just yet, and instead we'll only enable the breadcrumbs on |
Ok. Sorry @laymonage - I had assumed that direction has been given already to have the Breadcrumbs even when we have page headers so I didn't think to ask about it. Is it possible to have a version of this PR that just does the template clean up? I think that part is still quite valuable, even if the breadcrumbs are not used universally. |
@lb- No worries, I was still kind of uncertain when I worked on this and we didn't find the time to have a proper discussion until yesterday.
I think it is possible, and given the example in #10915 I might even be able to rebase that PR on top of this as-is. I'll see what I can do and report back. |
This allows us to reuse the header parts, including breadcrumbs.
This allows us to reuse the breadcrumbs.
…use the slim header
…m_disable template
…delViewSet breadcrumbs tests
bd3f0a6
to
3b7aa24
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a quick note that Sage and I discussed this refactoring and I’m happy with the code changes. Haven’t actually tested the proposed changes myself.
base_breadcrumb_items = [{"label": "Home", "url": "/admin/"}] | ||
|
||
def assertBreadcrumbsItemsRendered( | ||
self: Union[WagtailTestUtils, SimpleTestCase], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, annoying that this doesn’t convey the need for the WagtailTestUtils
instance to also inherit from TestCase
. I wonder if there’s a better way to annotate this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah unfortunately I couldn't find a better way to do it. The WagtailTestUtils
class is basically a mixin, and it doesn't assume which TestCase
base class you're going to use it with. For example, you can use it with a SimpleTestCase
or the more featured TestCase
depending on your needs, but we can't enforce this unless we make WagtailTestUtils
extend from that (at which point it might break existing tests because they now inherit the TestCase
twice).
I just opted for the most basic class needed (SimpleTestCase
) and used Union
with WagtailTestUtils
to at least get VSCode to understand where the methods come from.
Alternatively you could define a class just for the sake of typing, e.g.
class WagtailTestUtilsTestCase(WagtailTestUtils, SimpleTestCase):
...
and use it to annotate self
, but I don't really like doing this because it would actually define the class (unlike a TypeScript interface that doesn't produce runtime code). VSCode's type shims tend to use this approach with .pyi
files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks all. We had another design review session yesterday, and made some decisions:
- The final item in the breadcrumbs should be a link for consistency and to follow the examples in https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/. If it's not a link, the last item has a different colour which looks inconsistent.
- The only place where this isn't the case (aka
trailing_breadcrumb_title
) is currently the page create view. I'll try to make it a link as well in Refactorpage_breadcrumbs
tag to use sharedbreadcrumbs.html
template #10876, though this is currently low-priority for 5.2.
- The only place where this isn't the case (aka
- We'll disable the breadcrumbs in all views other than pages, snippets, and custom
ModelViewSet
s for now. This is because we still need further rework on the designs before introducing the breadcrumbs more widely, especially with the upcoming Universal Listings work.- This will be done in Disable breadcrumbs outside of pages,
SnippetViewSet
, and customModelViewSet
#10915.
- This will be done in Disable breadcrumbs outside of pages,
I've rebased this and added another commit 84a4835 to make the final item in the breadcrumbs a link.
Merging this now, further cleanups will be done in separate PRs as I mentioned above.
Built on top of #10880.
This adds consistent breadcrumbs in index/create/edit views to:
I also added a missing breadcrumb item on the snippets model index view (
/admin/snippets/
). In #10880 before it was reviewed, the view doesn't have any breadcrumbs. After moving theHome
item to theWagtailAdminTemplateMixin
instead of thebreadcrumbs
tag, this view now has theHome
item but missing the non-linked "Snippets" item. I've fixed it in this PR and added tests for it (as well as tests for the snippets views breadcrumbs).TODO, outside of this PR as the views code needs to be refactored to extend the generic CBVs or at least the
WagtailAdminTemplateMixin
, as they're currently either FBVs or custom CBVs:When reviewing, please hide whitespace.
Please check the following:
make lint
from the Wagtail root.Footnotes
Development Testing ↩