0.3.25 — 2026-03-20
0.3.25 — 2026-03-20
Fixed
- Dashboard import modal: AJAX import submit now follows redirects reliably and navigates back to the dashboard index after successful imports, avoiding a stuck modal state on
302responses. - Dashboard item list: item rows are rendered in deterministic tree order (parent/children traversal with sibling sort by
position, thenid) so visual ordering matches stored positions. - Dashboard table UX: item
positionis displayed under the parent label to make ordering and debugging easier. - Tests: migration command integration assertion for
--dumpoutput is now robust to Symfony console note line-wrapping.
Changed
- Performance (N+1 reduction):
- Menu copy now clones items from a preloaded flat list in two passes (no recursive
getChildren()lazy traversal) - Descendant id resolution for item edit uses preloaded menu items + in-memory BFS
- Import post-processing clears link fields for parents with children using an in-memory
hasChildrenmap (no per-item lazychildren->count()) - Export-all loads items for all menus in a single repository query and groups in memory
- Menu copy now clones items from a preloaded flat list in two passes (no recursive
0.3.24 — 2026-03-20
0.3.24 — 2026-03-20
Fixed
- Dashboard UI: menu item labels are rendered using locale-resolved
MenuItem::getLabelForLocale()(avoids empty baselabelwhen text is stored in per-locale translations). - Dashboard item forms: “Add child” modal hides
type,iconandpositioninputs and shows onlylabel+ per-locale translations (item type is fixed to Link). - Dashboard item forms: the icon section is rendered with a normal Symfony form (not LiveComponent) so the icon-selector widget refreshes reliably when the modal content changes.
- Dashboard item forms: label validation accepts either a non-empty base label or at least one non-empty translation; empty
positionvalues are normalized to0to preventnullmapping issues.
Changed
- Docs/UX: item form rendering and documentation were aligned for section-based partial submissions (
section/_section,section_focus).
0.3.23 — 2026-03-20
0.3.23 — 2026-03-20
Fixed
- LiveComponent: prevent Symfony “submitted form data” exceptions when saving items, and stabilize hydration of per-locale
label_{locale}fields in the item modal. - Dashboard UI: item modal icon field prefill is normalized; when the optional icon-selector bundle is installed it uses
IconSelectorType, otherwise it falls back to a plain text input.
Changed
- Demos: dashboard asset builds (
make assets/make ts-assets) run inside the demo Docker container to avoid hostpnpm/permission issues.
0.3.22 — 2026-03-20
0.3.22 — 2026-03-20
0.3.21 — 2026-03-20
0.3.21 — 2026-03-20
Added
- Config/UI: wrapper
<span>for non-section menu items controlled bydashboard.item_span_active, with wrapper class configurable viadashboard.css_class_options.span.
0.3.20 — 2026-03-20
0.3.20 — 2026-03-20
Added
- Config:
dashboard.id_options— list of HTML id values for the root<ul>of each rendered menu. Drives the dashboard fieldulId(dropdown vs plain text). - Menu entity: new nullable property
Menu.ulId(DB columnul_id). - Dashboard UI: menu configuration includes
ulId; the frontend template setsid="..."on the root<ul>when configured. - Import/export: menu export/import now includes
ulId. - Migration generator:
nowo_dashboard_menu:generate-migration --updatecan add the missingul_idcolumn.
0.3.17 — 2026-03-19
0.3.17 — 2026-03-19
Added
- UX Autocomplete detection: new Twig global
nowo_dashboard_ux_autocomplete_availablecomputed from the presence ofSymfony\UX\Autocomplete\AutocompleteBundle. Dashboard item form templates apply the autocomplete form theme only when available. - CSRF consistency: dashboard menu item forms set
csrf_token_idtosubmit(controller + LiveComponent) to keep CSRF behaviour aligned across Symfony versions.
Changed
- MenuDashboardController: when creating a child item, uses
_queryto includeparentid in the generated URL. - Templates: wraps
{% form_theme '@SymfonyUXAutocomplete/autocomplete_form_theme.html.twig' %}in the new availability guard.
Fixed
- Avoid warnings/errors when Symfony UX Autocomplete is not installed.
- Demo Symfony 7: enable sessions, CSRF support, and
framework.property_infofor older Symfony configs.
0.3.16 — 2026-03-20
0.3.16 — 2026-03-20
Added
- Config:
dashboard.permission_key_choices— optional list of permission keys for the menu item form. When set, the field becomes a select with autocomplete. - Dashboard item form: route name selector and (when configured) permission key selector use Symfony UX Autocomplete.
- Dashboard: “Add child” passes parent ID in the form action URL; “Add child” button disabled for section and divider items.
- Permission checkers:
AllowAllMenuPermissionCheckerandPermissionKeyAwareMenuPermissionCheckerare explicitly tagged withnowo_dashboard_menu.permission_checker. - MenuItem:
itemTypeis now nullable (DB column nullable).
0.3.15 — 2026-03-16
0.3.15 — 2026-03-16
Added
- Dashboard menu form: split into definition (code, base, name, context, icon) and configuration (permission checker, depth, collapsible, CSS classes).
- Dashboard item form: same definition/configuration split; partial and LiveComponent support
section_focus. - Redirect to referer: after any successful form submission the controller redirects to the same-origin referer URL; otherwise to the usual route.
- Import in modal: import form is loaded and submitted via AJAX; on success redirects to referer or index.
- Translations:
dashboard.edit_identity,dashboard.edit_config(en, es, fr). - Dockerfile: added Node.js, npm, and pnpm for building dashboard assets inside the container.
Changed
- MenuItem:
labelproperty is now nullable (for divider items); getter returns''when null. - Twig:
_menu_form_partialand_item_form_partialno longer usefield.vars.rendered(removed in Symfony 6.3+).
0.3.13 — 2026-03-18
0.3.13 — 2026-03-18
Added
- Menu option:
nestedCollapsibleSections— when disabled, section-type items do not show a collapse toggle. - Dependency:
symfony/mimerequired for theFilevalidator used in the import form.
Changed
- Export/import: now includes
classSectionLabelandnestedCollapsibleSections. - ImportMenuType: constraints use named arguments for Symfony 7/8 compatibility.
Deprecated
- Config:
dashboard.path_prefixis deprecated. Set the dashboard URL prefix in your app routing when importing@NowoDashboardMenuBundle/Resources/config/routes_dashboard.yaml.
0.3.7 — 2026-03-18
0.3.7 — 2026-03-18
Added
- Security: CSRF validation in
deleteMenu()anddeleteItem(); invalid or missing token returns 403. - Security: move up/down actions now use POST with CSRF tokens.
- Security: import size limit via
dashboard.import_max_bytes(default 2 MiB). - Security: optional
dashboard.required_role(e.g.ROLE_ADMIN) anddashboard.import_export_rate_limit(returns 429 when exceeded).
0.3.5 — 2026-03-18
0.3.5 — 2026-03-18
Added
- Translation domain: bundle uses domain NowoDashboardMenuBundle for all UI strings. Constant
NowoDashboardMenuBundle::TRANSLATION_DOMAINavailable in code.
Changed
- Translations (breaking for overrides): bundle translation files are now
NowoDashboardMenuBundle.{locale}.yaml(replacingmessages.*andvalidators.*). To override strings in your app, createtranslations/NowoDashboardMenuBundle.{locale}.yamlwith the same keys.
0.3.4 — 2026-03-18
0.3.4 — 2026-03-18
Added
- Dashboard export/import: export one or all menus as JSON (config + item tree, no internal IDs). Import from JSON with strategy Skip existing or Replace.
- Config:
dashboard.layout_template— Twig template that dashboard views extend. - MenuUrlResolver: fills missing path parameters from the current request’s route params.
0.3.0 — 2026-03-17
0.3.0 — 2026-03-17
Added
- Symfony 6.4 LTS: bundle now supports Symfony
^6.4 || ^7.0 || ^8.0; CI tests PHP 8.2–8.5 × Symfony 6.4, 7.0 and 8.0.
Changed
nowo-tech/icon-selector-bundleis now optional (moved fromrequiretosuggest). The dashboard item form usesIconSelectorTypewhen installed; otherwise the icon field is a plain text input.
0.2.0 — 2026-03-18 (breaking)
0.2.0 — 2026-03-18 (breaking)
Changed (breaking)
- PHP: minimum version raised to 8.4 (8.2 and 8.3 no longer supported).
- Symfony: bundle requires Symfony ^8.0 only; Symfony 7 support dropped.
- Doctrine: requires
doctrine/doctrine-bundle ^3.0anddoctrine/orm ^3.0(2.x no longer supported).
Fixed
- Doctrine config: removed deprecated
auto_generate_proxy_classesfrom test and demo configs.
0.1.0 — 2026-03-17
0.1.0 — 2026-03-17
Added
- Cache: configurable tree cache (
cache.ttlmin 60 s,cache.pool) to avoid N+1 and repeated DB hits. - Icon prefix map:
icon_library_prefix_map(e.g.bootstrap-icons: bi) so icon identifiers are converted before rendering. - Menu loading: two-query SQL path in
MenuRepository::findMenuAndItemsRaw(); optional PSR-6 cache. - Web Profiler: “Dashboard menus” panel with Menus tab (query count, item tree) and Configuration tab.
- Doctrine: table name quoting via
Platform::quoteSingleIdentifier().
0.0.1 — 2026-03-10 (initial release)
0.0.1 — 2026-03-10 (initial release)
Added
- Entities:
MenuandMenuItemwith Doctrine ORM (no Gedmo/Stof). Tree via parent + position; labels with optional JSON translations per locale. - Config:
project,locales,default_locale,defaults,menus.{code}overrides,api(enabled, path_prefix), dashboard options. - MenuTreeLoader: single-query load; labels resolved by request locale; optional permission filter via
MenuPermissionCheckerInterface. - Twig:
dashboard_menu_tree(),dashboard_menu_href(),dashboard_menu_config()functions;@NowoDashboardMenuBundle/menu.html.twig(Bootstrap 5, collapsible). - JSON API:
GET /api/menu/{code}with optional_localeand_context_sets. - Dashboard: CRUD at configurable path (default
/admin/menus). - Context resolution: menus with same
codecan have different JSONcontext; resolved by ordered context sets. - Translations: dashboard and form messages in English, Spanish and French.
- Demos: Symfony 7 and Symfony 8 with FrankenPHP + Caddy, MySQL, fixtures.
- CI: GitHub Actions (PHP 8.2–8.5 × Symfony 7.0/8.0, code style, coverage, release workflow).
- Recipe: Symfony Flex recipe for config and routes.
For the complete history including all patch releases, see the GitHub releases page or the full CHANGELOG in the repository.