{# Modulmanager left rail — client-side tab switching (switchExtTab in extension_cards.js), same markup and behaviour as the Settings / Integrations / Monitoring menus, and the mobile drawer in base.html picks it up for free because it is a direct child of a .has-floating-menu element. Modules and theme packs used to be one long scroll: two different lifecycles (a module is code and may need a restart, a theme is inert CSS and never does), two different sets of questions. The state filters used to sit in a bar ABOVE the cards (.mm-bar). They moved in here for one reason: "Modules or themes?" and "which of them is broken?" are the same question asked twice, and answering them in two different places meant the answer to the second was scrolled off screen by the time you had used the first. extension_cards.js still drives them through #mmFilters / data-mm-filter, so nothing about the filtering itself changed. The counts below come from the same extensions|map('state') tally the page header used to print as prose. #} {% set _states = extensions|map(attribute="state")|list %} {% set _n_ok = _states|select("equalto", "ok")|list|length %} {% set _n_off = _states|select("equalto", "off")|list|length %} {% set _n_trouble = _states|select("equalto", "error")|list|length + _states|select("equalto", "skipped")|list|length %} {# data-no-drawer: on a phone this rail stays in the flow and stacks ABOVE the cards (see extensions.css), the same shape the Store tab's own rail already has. Behind the drawer FAB it was the one thing on this page you had to go looking for, and the two tabs of one page disagreed about where their filters live. #}
{{ _('Type') }} {# State filters — modules only. A theme pack is inert CSS: it has no "running/off/failed", so offering the filter on that tab would be offering three buttons that all do nothing. #} {% if extensions %}
{{ _('State') }} {% if _n_trouble %} {% endif %}
{# Health summary. Same numbers as the filters above, but as a statement rather than as controls — "1 failing" has to be readable without first noticing that a filter button has a count on it. #}
{{ _('Health') }}
{{ _('Running') }} {{ _n_ok }}
{{ _('Off') }}{{ _n_off }}
{{ _('Problems') }} {{ _n_trouble }}
{# Filled by module_store.js once the catalog is in — the number is only knowable after the store answered. #}
{% endif %} {# Rescan. A page-level action, so it belongs with the page-level controls rather than floating in the header next to the title -- and being a child of the rail it rides along into the mobile drawer for free, which the header button did not. Same id, so the handler in extensions.html is unchanged. #}
{{ _('Actions') }}