{% extends "base.html" %} {% block title %}{{ _('Module Manager') }} — MediaForge{% endblock %} {% block styles %} {% endblock %} {% block content %}
{% if store_enabled %} {% endif %}
{{ _('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') } %} {# The tally and the state filters moved into the left rail (_extensions_nav.html): they answer the same question the Modules / Theme Packs switch does, and having them in two places meant one of the two was always scrolled away. Nothing else changed — the filter buttons still carry data-mm-filter and are still driven by extension_cards.js against each card's data-mm-state. #} {% 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 %}