Problem/Motivation

Follows #3624762: Top bar entry for the main content display: bundle display or override.

That issue removes our per-view-mode "Display: …" local tasks from canonical pages, because the Display dropdown in the top bar already lists the display the page renders. The check is on the Navigation module being installed:

if (!$this->moduleHandler->moduleExists('navigation')) { return; }

But core only builds the top bar for users with the "access navigation" permission (NavigationRenderer::buildTopBar()). A user who may edit displays without that permission therefore loses the tabs and gets no dropdown in exchange: the entity's overrides become unreachable from its page.

Steps to reproduce

  1. Install Navigation, give a display built with Display Builder an override field.
  2. Create a user with the display permissions but without "access navigation".
  3. Visit an entity page: no top bar, and no "Display: …" tab either.

Proposed resolution

Remove the tasks only when this user actually gets the top bar: check "access navigation" alongside the module, and add user.permissions to the cacheability that core hands the hook, so the local tasks are not cached across both kinds of user.

Remaining tasks

  • Test: a user without "access navigation" still sees the tabs on a canonical page.
  • Test: the existing removal still happens for a user who has it.
CommentFileSizeAuthor
#8 3625978 after.png347.84 KBcsakiistvan
#8 3625978 before.png339.83 KBcsakiistvan
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mogtofu33 created an issue. See original summary.

mogtofu33’s picture

pdureau’s picture

beta9 has been released. Changing the tag.

pdureau’s picture

I wanted to give a help by rebasing the MR, but I see it contains only the changes from #3624762: Top bar entry for the main content display: bundle display or override (with some tiny differences).

So, if I give a try, it would be in a distinct MR.

Remove the tasks only when this user actually gets the top bar: check "access navigation" alongside the module, and add user.permissions to the cacheability that core hands the hook, so the local tasks are not cached across both kinds of user.

Seems straightforward now #3624762: Top bar entry for the main content display: bundle display or override is merged.

Maybe just adding $cacheability->addCacheContexts(['user.permissions']) and a AccountInterface::currentUser->hasPermission('access navigation') check in DisplayBuilderEntityViewHook::menuLocalTasksAlter() would be enough.

pdureau’s picture

Assigned: mogtofu33 » pdureau
Status: Active » Needs review

Mr ready for review. It was a bit too "simple". I will do some manual checks before sending to someone else for review.

csakiistvan’s picture

StatusFileSize
new339.83 KB
new347.84 KB

✅ Tested and works — as a user with every permission except "access navigation", a node with overridable displays showed no top bar and no "Display: …" tabs; after applying MR !520 and rebuilding caches, the "Display: Full" and "Display: Teaser" tabs are back and open without access denied. Users without the top bar can reach the overrides again. Suggest to RTBC

Notes
  • Non-blocking: user.permissions is already a required render cache context (core.services.yml, renderer.config), so the new test still passes without addCacheContexts(['user.permissions']); its docblock claims more than it covers.
  • Non-blocking: agents/entity-view-overrides.md (line 32) still says the Display dropdown replaces the tabs on the canonical page, without the "access navigation" condition.
pdureau’s picture

Status: Needs review » Needs work

Non-blocking: user.permissions is already a required render cache context (core.services.yml, renderer.config), so the new test still passes without addCacheContexts(['user.permissions']); its docblock claims more than it covers.

Thanks you, I will remove this (and update the doc), and send back to review.

csakiistvan’s picture

Just ping me and I will review again

pdureau’s picture

Assigned: pdureau » mogtofu33
Status: Needs work » Reviewed & tested by the community

I changed my mind. I finally prefer to declare explicitly in menu_local_tasks_alter every context the renderable depends on, without depending on a default value from the Core Renderer (whcih can change, because overridable in a services.yml).

Core does the same in AccessResult::allowedIfHasPermission()

Back to RTBC.

pdureau changed the visibility of the branch 3625978-override-tabs-removed to hidden.