{% extends "base.html" %} {% block title %}{{ _('Module Manager') }} — MediaForge{% endblock %} {% block styles %} {% endblock %} {% block content %}
{{ _('Restart required') }}
{%- if pending.install %}{{ _('To be installed/updated') }}: {{ pending.install|join(', ') }}{% endif %} {%- if pending.install and pending.remove %} · {% endif %} {%- if pending.remove %}{{ _('To be removed') }}: {{ pending.remove|join(', ') }}{% endif %}
{{ _('These changes are applied the next time MediaForge starts.') }}
{% if restart_supported %} {% else %} {{ _('Restart MediaForge to apply — this process cannot restart itself (debug mode).') }} {% endif %}
{# The installed view is now two panels behind a floating side menu, so modules and theme packs stop sharing one scroll. has-floating-menu makes this element the flex container -- the menu and the panels have to be its DIRECT children (see shell.css). #}
{% include "_extensions_nav.html" %}
{% if not extensions %}
{{ _('No extension folders discovered.') }}
{% endif %} {# Labels for registry.module_capabilities()'s kinds. Written as "3 × provider" so neither language needs a plural form for twelve different nouns. #} {% set CAP_LABELS = { 'menu': _('menu entry'), 'settings_card': _('settings card'), 'dashboard_widget': _('dashboard widget'), 'provider_pill': _('provider pill'), 'provider': _('content source'), 'search_source': _('search source'), 'cineinfo_source': _('CineInfo source'), 'home_feed_source': _('home feed source'), 'home_panel': _('home page panel'), 'subtitle_source': _('subtitle source'), 'hoster': _('hoster'), 'mirrors': _('mirror list'), 'monitor': _('monitor entry'), 'notification_channel': _('notification channel'), 'event_hook': _('event hook'), 'background_worker': _('background worker') } %} {# Tally + filter. Both read the cards' data-mm-state, so nothing here has to be kept in sync with the loop below. #} {% set _states = extensions|map(attribute="state")|list %} {% if extensions %}
{{ extensions|length }} {{ _('modules') }} · {{ _states|select("equalto", "ok")|list|length }} {{ _('running') }} · {{ _states|select("equalto", "off")|list|length }} {{ _('off') }} {% set _trouble = _states|select("equalto", "error")|list|length + _states|select("equalto", "skipped")|list|length %} {% if _trouble %} · {{ _states|select("equalto", "skipped")|list|length }} {{ _('skipped') }} · {{ _states|select("equalto", "error")|list|length }} {{ _('with errors') }} {% endif %}
{% if _trouble %} {% endif %}
{% endif %} {% for ext in extensions %} {# One state per card, not a row of badges. Everything the old header carried as its own pill (version, author, "Loaded", "Enabled", Registry API) is either the state itself or quiet meta text below the name -- the badges that survive are the ones that are NOT the normal case: a signature that does not check out, an unmet dependency, a pending restart. "Unsigned" deliberately gets none: that is the ordinary state of a third-party module, and labelling it trains people to ignore labels. mm-state drives the filter buttons above (data-mm-state) and the sort order (see extensions.py: problems first). #} {% set mm_state = ext.state %} {% endfor %}
{% if theme_packs %}
{{ _('Theme Packs') }} {{ theme_packs | length }}
{% endif %} {% for tp in theme_packs %} {% endfor %}
{% endblock %}