From 2764c58c5338bbba175a3324b01a76a98fc02b3b Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 24 Jul 2026 13:55:49 -0700 Subject: [PATCH] views: Add a separate page for adding new apps - It avoids confusion with two separate app sections in a single page. The sections/pages can be better titled. - In future, we can style the apps page (with more status display) differently from apps-add page (with more search and featured apps). - Move page specific parts into individual pages instead of in the common template cards.html. - Add special message when there are no apps enabled and when there are no more apps to enable. - Drop show_disabled flag in cards template that is not needed anymore. Tests: - Unit tests work. - Functional tests work on bepasty when starting with uninstalled, disabled, or enabled states. - Apps page shows special message when there are no apps enabled. It is centered. - Apps page shows 'Add new app' button with icon. Clicking it takes us to apps-add page. - Apps page does not have disabled apps list (even hidden). - Disabled and uninstalled apps are not shown on apps page. - Apps-add page shows special message when there are no more apps to be installed or enabled (test by altering view code to have empty list of apps). - Apps-add page shows list of apps that are disabled or uninstalled but not enabled apps. It shows a title 'Add New App'. Reviewed-by: James Valleroy --- plinth/templates/app-header.html | 2 +- plinth/templates/apps-add.html | 25 +++++++++++++++++ plinth/templates/apps.html | 18 ++++++++++++ plinth/templates/cards.html | 47 ++++++++++---------------------- plinth/urls.py | 3 +- plinth/views.py | 36 +++++++++++++++++++++--- 6 files changed, 93 insertions(+), 38 deletions(-) create mode 100644 plinth/templates/apps-add.html diff --git a/plinth/templates/app-header.html b/plinth/templates/app-header.html index 4e25d8096..e5c90d58b 100644 --- a/plinth/templates/app-header.html +++ b/plinth/templates/app-header.html @@ -46,7 +46,7 @@ {% if app_info.tags %}
{% for tag in app_info.tags %} - {% if not forloop.first %}•{% endif %} + {% if not forloop.first %}•{% endif %} {% trans tag %} diff --git a/plinth/templates/apps-add.html b/plinth/templates/apps-add.html new file mode 100644 index 000000000..02312290a --- /dev/null +++ b/plinth/templates/apps-add.html @@ -0,0 +1,25 @@ +{% extends 'cards.html' %} +{% comment %} +# SPDX-License-Identifier: AGPL-3.0-or-later +{% endcomment %} + +{% load static %} +{% load i18n %} + +{% block page_js %} + +{% endblock %} + +{% block body_class %}apps-add-page{% endblock %} + +{% block header-container %} +
{% trans "Add New App" %}
+{% endblock %} + +{% block cards-empty %} +

+ {% blocktrans trimmed %} + There are no more apps available to add. + {% endblocktrans %} +

+{% endblock %} diff --git a/plinth/templates/apps.html b/plinth/templates/apps.html index 5b5112706..99a57b87b 100644 --- a/plinth/templates/apps.html +++ b/plinth/templates/apps.html @@ -5,9 +5,27 @@ {% load static %} {% load i18n %} +{% load extras %} {% block page_js %} {% endblock %} {% block body_class %}apps-page{% endblock %} + +{% block toolbar-container %} +
+{% endblock %} + +{% block cards-empty %} +

+ {% blocktrans trimmed %} + There are currently no apps added. + {% endblocktrans %} +

+{% endblock %} diff --git a/plinth/templates/cards.html b/plinth/templates/cards.html index be49d25d6..6cfe29b6b 100644 --- a/plinth/templates/cards.html +++ b/plinth/templates/cards.html @@ -20,45 +20,28 @@ {% include "tags.html" %} {% endblock %} - -
-
-
- {% for item in menu_items %} - {% if not show_disabled or item.is_enabled %} + {% block header-container %} + {% endblock %} + + {% block toolbar-container %} + {% endblock %} + + {% if menu_items %} +
+
+ {% for item in menu_items %} {% if advanced_mode or not item.advanced %} {% include "card.html" %} {% endif %} - {% endif %} - {% endfor %} -
-
-
- - {% if show_disabled %} -
-
{% trans "Available for install" %}
-
-
- {% for item in menu_items %} - {% if not item.is_enabled %} - {% if advanced_mode or not item.advanced %} - {% include "card.html" %} - {% endif %} - {% endif %} {% endfor %}
-
- {% endif %} + {% else %} + {% block cards-empty %} + {% endblock %} + {% endif %} +
{% block content-container %} {% endblock %} diff --git a/plinth/urls.py b/plinth/urls.py index 59bc844d8..6fec30dfe 100644 --- a/plinth/urls.py +++ b/plinth/urls.py @@ -23,7 +23,8 @@ urlpatterns = [ re_path(r'^language-selection/$', public(views.LanguageSelectionView.as_view()), name='language-selection'), - re_path(r'^apps/$', views.AppsIndexView.as_view(), name='apps'), + re_path(r'^apps/$', views.AppsView.as_view(), name='apps'), + re_path(r'^apps/add/$', views.AppsAddView.as_view(), name='apps-add'), re_path(r'^sys/$', views.system_index, name='system'), re_path(r'', include((system_urlpatterns, 'system'))), re_path(r'^uninstall/(?P[1-9a-z\-_]+)/$', diff --git a/plinth/views.py b/plinth/views.py index 76d2c2c3f..7e1d20031 100644 --- a/plinth/views.py +++ b/plinth/views.py @@ -266,8 +266,8 @@ def _get_all_tags(menu_items: list[menu.Menu]) -> list[str]: return sorted(get_tags(menu_items), key=_) -class AppsIndexView(TemplateView): - """View for apps index. +class AppsView(TemplateView): + """View for showing installed apps. This view supports filtering apps by one or more tags. If no tags are provided, it will show all the apps. If one or more tags are provided, @@ -277,11 +277,39 @@ class AppsIndexView(TemplateView): def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) - context['show_disabled'] = True context['advanced_mode'] = get_advanced_mode() tags = self.request.GET.getlist('tag', []) - menu_items = menu.main_menu.active_item(self.request).items + menu_items = [ + item for item in menu.main_menu.active_item(self.request).items + if item.is_enabled() + ] + + context['tags'] = tags + context['all_tags'] = _get_all_tags(menu_items) + context['menu_items'] = _pick_menu_items(menu_items, tags) + + return context + + +class AppsAddView(TemplateView): + """View for showing apps that can be installed. + + This view supports filtering apps by one or more tags. If no tags are + provided, it will show all the apps. If one or more tags are provided, + it will select apps matching any of the provided tags. + """ + template_name = 'apps-add.html' + + def get_context_data(self, *args, **kwargs): + context = super().get_context_data(*args, **kwargs) + context['advanced_mode'] = get_advanced_mode() + + tags = self.request.GET.getlist('tag', []) + menu_items = [ + item for item in menu.main_menu.active_item(self.request).items + if not item.is_enabled() + ] context['tags'] = tags context['all_tags'] = _get_all_tags(menu_items)