Dashboard layout customization: reorder + hide/show sections#68
Open
ndandan wants to merge 13 commits into
Open
Dashboard layout customization: reorder + hide/show sections#68ndandan wants to merge 13 commits into
ndandan wants to merge 13 commits into
Conversation
…variant The testResolutionIsCachedUntilReset test was a tautology that always passed because the ConfigService mock returned the same values every time. The test called resolve(), reset(), resolve() and compared the result arrays with assertSame, which would be equal regardless of whether caching worked. Rewrote the test to verify the caching invariant by counting ConfigService::get() calls: 8 on first resolve, 0 additional on second (cache hit), 8 more after reset. This ensures the test fails if caching is removed or broken. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the 7 inline dashboard sections (upcoming, requests, health, plex, watchlist, trending, recent) into per-section Twig partials under templates/dashboard/sections/. Each partial wraps its markup in a data-section-key="<key>" div and keeps its existing service-config gate inside. Requests and Health, previously sharing one .row, become two independent full-width blocks (col-12 in their own row each). DashboardController now injects DashboardLayoutService and passes dashboard_layout (resolved order + visibility) to the view; index.html.twig replaces all inline section markup with a loop over dashboard_layout, including only visible sections via their partial. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tance in test - Restore `final` keyword on DashboardLayoutService class declaration to match the design pattern established by ThemeService - In AdminSettingsControllerTest helper, replace createMock() with real instance construction using the mocked ConfigService already available as a parameter - Remove orphaned docblock before loadDashboardLayout() that was left behind during method extraction Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion Add two assertions to testDashboardLayoutEndpointPersistsOrderAndHidden: 1. Assert JSON response body equals ['ok' => true] 2. Assert config->invalidate() is called exactly once Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d removeOverlays Added idempotency guard (toolbar.dataset.layoutBound) to prevent double-init of drag/button listeners on turbo:load + immediate invocation. Removed unused removeOverlays() function (both Save/Cancel paths call window.location.reload). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A gated-out section partial (empty watchlist, unconfigured service) still emits a zero-height [data-section-key] wrapper. Edit mode was giving it a drag handle and a Hide button that floated onto the next section's header. Skip offsetHeight===0 wrappers in addOverlays() and as drag targets so only sections with rendered content are editable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Match the suite convention (AdminSettingsControllerTest) so the new DashboardLayoutServiceTest's ConfigService mocks don't emit PHPUnit "mock without expectations" notices — keeps test output pristine. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The DashboardController constructor gained a DashboardLayoutService parameter; pass it (a real instance over a mocked ConfigService, since the service is final) at all six construction sites so the full suite matches the current arity. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Lets an admin reorder the dashboard's content sections and hide/show them, with two surfaces:
The Hero stays pinned at the top; the seven content sections (
upcoming, requests, health, plex, watchlist, trending, recent) are the reorderable/hideable set.Why
Today the dashboard renders a fixed order and section visibility is driven only by which services are configured. Users with different priorities (or unconfigured services) want to tailor what shows and in what order.
How
DashboardSections— a static registry that is the single source of truth for section keys + default order.DashboardLayoutService— resolves the stored order + per-section hidden flags into an ordered{key, visible}list. Modeled onThemeService:final, implementsResetInterface, caches per request. Unknown/duplicate keys are dropped and any missing section is appended in default order, so a section added in a future release auto-appears instead of vanishing.settingtable, reusing the sidebar-visibility pattern:dashboard_section_order(comma-joined keys) +dashboard_hide_<key>('1'= hidden). No migration; a fresh install with no stored layout falls back to the default order, all visible.templates/dashboard/sections/_*.html.twigpartials and rendered in a data-driven loop; each partial keeps its existingservices_configured.*gate, so a section shows only when visible AND configured.saveSubmitted) and a small admin-gatedPOST /admin/settings/dashboard-layoutendpoint for the on-dashboard editor.#[IsGranted('ROLE_ADMIN')]; the dashboard toolbar is gated byis_granted('ROLE_ADMIN')). Reordering uses native HTML5 drag-and-drop — no new dependencies.Testing
DashboardSectionsTest— registry shape/order/validity.DashboardLayoutServiceTest— resolution: default order, custom order, unknown-key drop, dedupe, hidden flags, caching/reset.AdminSettingsControllerTest— settings save persists order + hidden flags; the new endpoint persists and returns JSON.lint:twigclean across the new partials + templates.Notes