config: Add option to show advanced apps

Closes #1454.

Signed-off-by: James Valleroy <jvalleroy@mailbox.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
James Valleroy 2019-05-12 19:40:47 -04:00 committed by Sunil Mohan Adapa
parent 5fe7f4aaba
commit ff06c722bb
No known key found for this signature in database
GPG Key ID: 43EA1CFF0AA7C5F2
8 changed files with 89 additions and 33 deletions

View File

@ -27,7 +27,7 @@ class Menu(app.FollowerComponent):
def __init__(self, component_id, name=None, short_description=None, def __init__(self, component_id, name=None, short_description=None,
icon=None, url_name=None, url_args=None, url_kwargs=None, icon=None, url_name=None, url_args=None, url_kwargs=None,
parent_url_name=None, order=50): parent_url_name=None, order=50, advanced=False):
"""Initialize a new menu item with basic properties. """Initialize a new menu item with basic properties.
name is the label of the menu item. name is the label of the menu item.
@ -50,6 +50,8 @@ class Menu(app.FollowerComponent):
disregard that. If you need more granularity, don't bother renumbering disregard that. If you need more granularity, don't bother renumbering
things. Feel free to use fractional orders. things. Feel free to use fractional orders.
advanced decides whether to show the menu item only in advanced mode.
""" """
super().__init__(component_id) super().__init__(component_id)
if not url_name: if not url_name:
@ -62,6 +64,7 @@ class Menu(app.FollowerComponent):
self.icon = icon self.icon = icon
self.url = url self.url = url
self.order = order self.order = order
self.advanced = advanced
self.items = [] self.items = []
# Add self to parent menu item # Add self to parent menu item

View File

@ -45,6 +45,7 @@ APACHE_HOMEPAGE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR,
APACHE_HOMEPAGE_CONF_FILE_NAME) APACHE_HOMEPAGE_CONF_FILE_NAME)
FREEDOMBOX_APACHE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, FREEDOMBOX_APACHE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR,
'freedombox.conf') 'freedombox.conf')
ADVANCED_MODE_KEY = 'advanced_mode'
app = None app = None
@ -126,6 +127,18 @@ def change_home_page(shortcut_id):
actions.superuser_run('config', ['set-home-page', str(url)]) actions.superuser_run('config', ['set-home-page', str(url)])
def get_advanced_mode():
"""Get whether option is enabled."""
from plinth import kvstore
return kvstore.get_default(ADVANCED_MODE_KEY, False)
def set_advanced_mode(advanced_mode):
"""Turn on/off advanced mode."""
from plinth import kvstore
kvstore.set(ADVANCED_MODE_KEY, advanced_mode)
def init(): def init():
"""Initialize the module""" """Initialize the module"""
global app global app

View File

@ -100,3 +100,8 @@ class ConfigurationForm(forms.Form):
'/freedombox to reach {box_name} Service (Plinth).'), '/freedombox to reach {box_name} Service (Plinth).'),
box_name=ugettext_lazy(cfg.box_name)), required=False, box_name=ugettext_lazy(cfg.box_name)), required=False,
choices=get_homepage_choices) choices=get_homepage_choices)
advanced_mode = forms.BooleanField(
label=_('Show advanced apps and features'), required=False,
help_text=_('Show apps and features that require more technical '
'knowledge.'))

View File

@ -64,6 +64,7 @@ def get_status():
'hostname': config.get_hostname(), 'hostname': config.get_hostname(),
'domainname': config.get_domainname(), 'domainname': config.get_domainname(),
'homepage': config.get_home_page(), 'homepage': config.get_home_page(),
'advanced_mode': config.get_advanced_mode(),
} }
@ -102,6 +103,22 @@ def _apply_changes(request, old_status, new_status):
else: else:
messages.success(request, _('Webserver home page set')) messages.success(request, _('Webserver home page set'))
if old_status['advanced_mode'] != new_status['advanced_mode']:
try:
config.set_advanced_mode(new_status['advanced_mode'])
except Exception as exception:
messages.error(
request,
_('Error changing advanced mode: {exception}').format(
exception=exception))
else:
if new_status['advanced_mode']:
messages.success(request,
_('Showing advanced apps and features'))
else:
messages.success(request,
_('Hiding advanced apps and features'))
def set_hostname(hostname): def set_hostname(hostname):
"""Sets machine hostname to hostname""" """Sets machine hostname to hostname"""

View File

@ -0,0 +1,34 @@
{% comment %}
#
# This file is part of FreedomBox.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
{% endcomment %}
{% load static %}
<div class="card thumbnail">
<a href="{{ item.url }}" class="nav-link">
<div class="card-title">{{ item.name }}</div>
<div class="card-icon">
{% if 'fa-' in item.icon %}
<span class="fa {{ item.icon }}"></span>
{% else %}
<img src="{% static 'theme/icons/' %}{{ item.icon }}.svg"/>
{% endif %}
</div>
<div class="card-description">{{ item.short_description|default:'' }}</div>
</a>
</div>

View File

@ -35,19 +35,9 @@
<div class="card-list card-list-primary"> <div class="card-list card-list-primary">
{% for item in submenu.sorted_items %} {% for item in submenu.sorted_items %}
{% if not show_disabled or item.is_enabled %} {% if not show_disabled or item.is_enabled %}
<div class="card thumbnail"> {% if advanced_mode or not item.advanced %}
<a href="{{ item.url }}" class="nav-link"> {% include "card.html" %}
<div class="card-title">{{ item.name }}</div> {% endif %}
<div class="card-icon">
{% if 'fa-' in item.icon %}
<span class="fa {{ item.icon }}"></span>
{% else %}
<img src="{% static 'theme/icons/' %}{{ item.icon }}.svg"/>
{% endif %}
</div>
<div class="card-description">{{ item.short_description|default:'' }}</div>
</a>
</div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
@ -61,19 +51,9 @@
<div class="card-list card-list-disabled"> <div class="card-list card-list-disabled">
{% for item in submenu.sorted_items %} {% for item in submenu.sorted_items %}
{% if not item.is_enabled %} {% if not item.is_enabled %}
<div class="card thumbnail"> {% if advanced_mode or not item.advanced %}
<a href="{{ item.url }}" class="nav-link"> {% include "card.html" %}
<div class="card-title">{{ item.name }}</div> {% endif %}
<div class="card-icon">
{% if 'fa-' in item.icon %}
<span class="fa {{ item.icon }}"></span>
{% else %}
<img src="{% static 'theme/icons/' %}{{ item.icon }}.svg"/>
{% endif %}
</div>
<div class="card-description">{{ item.short_description|default:'' }}</div>
</a>
</div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>

View File

@ -92,6 +92,7 @@ def test_menu_creation_without_arguments():
assert menu.icon is None assert menu.icon is None
assert menu.url == '/' assert menu.url == '/'
assert menu.order == 50 assert menu.order == 50
assert not menu.advanced
assert not menu.items assert not menu.items
@ -107,7 +108,7 @@ def test_menu_creation_with_arguments():
parent_menu = Menu('menu-index', url_name='index') parent_menu = Menu('menu-index', url_name='index')
menu = Menu('menu-test', expected_name, expected_short_description, menu = Menu('menu-test', expected_name, expected_short_description,
expected_icon, url_name, url_kwargs=url_kwargs, expected_icon, url_name, url_kwargs=url_kwargs,
parent_url_name='index', order=expected_order) parent_url_name='index', order=expected_order, advanced=True)
assert len(parent_menu.items) == 1 assert len(parent_menu.items) == 1
assert parent_menu.items[0] == menu assert parent_menu.items[0] == menu
@ -116,6 +117,7 @@ def test_menu_creation_with_arguments():
assert expected_icon == menu.icon assert expected_icon == menu.icon
assert expected_url == menu.url assert expected_url == menu.url
assert expected_order == menu.order assert expected_order == menu.order
assert menu.advanced
assert not menu.items assert not menu.items
@ -129,7 +131,7 @@ def test_get():
reversed_url = reverse(url_name) reversed_url = reverse(url_name)
expected_order = 2 expected_order = 2
menu = Menu('menu-test', expected_name, expected_short_description, menu = Menu('menu-test', expected_name, expected_short_description,
expected_icon, url_name, order=expected_order) expected_icon, url_name, order=expected_order, advanced=True)
actual_item = menu.get(expected_url) actual_item = menu.get(expected_url)
assert actual_item is not None assert actual_item is not None
@ -138,6 +140,7 @@ def test_get():
assert expected_icon == actual_item.icon assert expected_icon == actual_item.icon
assert reversed_url == actual_item.url assert reversed_url == actual_item.url
assert expected_order == actual_item.order assert expected_order == actual_item.order
assert actual_item.advanced
assert not actual_item.items assert not actual_item.items

View File

@ -32,6 +32,7 @@ from stronghold.decorators import public
import plinth import plinth
from plinth import package from plinth import package
from plinth.modules.config import get_advanced_mode
from plinth.modules.storage import views as disk_views from plinth.modules.storage import views as disk_views
from plinth.translation import get_language_from_request, set_language from plinth.translation import get_language_from_request, set_language
@ -48,9 +49,7 @@ def index(request):
selected = request.GET.get('selected') selected = request.GET.get('selected')
selected_shortcut = [ selected_shortcut = [
shortcut shortcut for shortcut in shortcuts if shortcut.component_id == selected
for shortcut in shortcuts
if shortcut.component_id == selected
] ]
selected_shortcut = selected_shortcut[0] if selected_shortcut else None selected_shortcut = selected_shortcut[0] if selected_shortcut else None
@ -71,13 +70,15 @@ class AppsIndexView(TemplateView):
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
context['show_disabled'] = True context['show_disabled'] = True
context['advanced_mode'] = get_advanced_mode()
return context return context
def system_index(request): def system_index(request):
"""Serve the system index page.""" """Serve the system index page."""
disk_views.warn_about_low_disk_space(request) disk_views.warn_about_low_disk_space(request)
return TemplateResponse(request, 'system.html') return TemplateResponse(request, 'system.html',
{'advanced_mode': get_advanced_mode()})
class LanguageSelectionView(FormView): class LanguageSelectionView(FormView):