Release v0.3.35
Release 0.3.35
Changelog
Added
- Dashboard tree reorder (SortableJS): dedicated page
GET .../{id}/items/reorder(routeshow_items_reorder);POST .../{id}/items/reorder-tree(items_reorder_tree, CSRF) applies parent/position from a nested list payload. Menu detail table remains onGET .../{id}with a link to the reorder view.MenuItemRepository::applyTreeLayout()persists the tree; rootpackage.jsonincludessortablejs(runnpm run buildwhen rebuilding bundledashboard.jsfrom source). dashboard_routes.show_items_reorderexposed viaMenuDashboardController::getDashboardRoutes()for apps overriding dashboard Twig.- Twig partials:
dashboard/show_items_reorder.html.twig,dashboard/_sortable_tree_macro.html.twig,dashboard/_menu_dashboard_modals.html.twig,dashboard/_dashboard_item_icon.html.twig(optional UX Icons next to item labels in dashboard lists). - Bundle logger:
announce()for always-on console lines; Sortable move diagnostics when dashboard debug is enabled (__nowoDashboardMenuConfig.debug). - Sections at root only:
MenuItemRepository::TREE_LAYOUT_SECTION_MUST_BE_ROOT; tree apply, Sortable guards, and item forms keepsectionitems at root; user-facing flash when a reorder is rejected (dashboard.reorder_tree_section_not_root). - Dashboard (menu detail): action Check parent cycles next to re-index positions — POST with CSRF — reports via flash whether the persisted parent chain forms a loop (item ids shown).
- Translations tooling: new command
nowo_dashboard_menu:translations:google-syncaudits missing keys per locale using a base locale and can auto-translate missing strings with Google Translate API (--translate-missing, optional--write). - Import: JSON import accepts a root-level array of menu blocks
[{ "menu": {...}, "items": [...] }, ...], equivalent to{ "menus": [ ... ] }.MenuImporter::normalizeImportPayload()performs the normalization; dashboard validation messages for invalid root arrays are translated (dashboard.import_format_*).
Changed
- Divider items: optional label/translations are allowed (null or empty); persistence normalizes whitespace and no longer clears user-provided names. Dashboard forms show the label fields for dividers with a hint that a name is recommended but optional.
- Dashboard menu detail (links column): no longer resolves each item’s route URL via
dashboard_menu_hrefin the table. The column showsrouteNameandrouteParamsonly, avoiding Symfony router failures that added one flash error per row when mandatory parameters were missing. - Parent selector (item config): disabled Symfony UX Autocomplete / Tom Select on the
parentEntityTypeso choices always come fromquery_builder(excludes self and subtree). Remote autocomplete rebuilt the form without the editing item and could list the item as its own parent. ValidationvalidateParentNoCircularnow treats same parent/item by numeric id as well as strict===.
Fixed
- Sortable init vs. show-page guard:
initMenuSortablePanel()runs before the__dmDashboardMenuShowBoundshort-circuit so drag-and-drop reorder still works after in-app navigation (e.g. Turbo) from the table view to the reorder page.
Full Changelog: v0.3.34...v0.3.35