mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
menu: Sort menu items for all locales
Currently menu items are shown in alphabetical order in applications and no clear order in system configuration. This is done using static weights for menu items based on English names that does not work for other locales. Sorting can't be done at the time of adding menu items as users of multiple locales may use the interface at the same time. Implement a sorting mechanism based on existing order as well as labels of menu item. This allows the flexiblity of grouping menu items in future as it may be need for system configuration. In case of help menu Remove sort order for all modules except for help menu as here we want that specific order.
This commit is contained in:
parent
6f99580f8a
commit
ad61028a3a
@ -56,9 +56,9 @@ class Menu(object):
|
||||
|
||||
raise KeyError('Menu item not found')
|
||||
|
||||
def sort_items(self):
|
||||
"""Sort the items in self.items by order."""
|
||||
self.items = sorted(self.items, key=lambda x: x.order, reverse=False)
|
||||
def sorted_items(self):
|
||||
"""Return menu items in sorted order according to current locale."""
|
||||
return sorted(self.items, key=lambda x: (x.order, x.label))
|
||||
|
||||
def add_urlname(self, label, icon, urlname, order=50, url_args=None,
|
||||
url_kwargs=None):
|
||||
@ -77,7 +77,6 @@ class Menu(object):
|
||||
"""
|
||||
item = Menu(label=label, icon=icon, url=url, order=order)
|
||||
self.items.append(item)
|
||||
self.sort_items()
|
||||
return item
|
||||
|
||||
def active_item(self, request):
|
||||
|
||||
@ -24,7 +24,7 @@ from plinth import cfg
|
||||
def init():
|
||||
"""Initailize the apps module"""
|
||||
cfg.main_menu.add_urlname(_('Apps'), 'glyphicon-download-alt',
|
||||
'apps:index', 80)
|
||||
'apps:index')
|
||||
|
||||
|
||||
def index(request):
|
||||
|
||||
@ -55,7 +55,7 @@ service = None
|
||||
def init():
|
||||
"""Intialize the service discovery module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-lamp', 'avahi:index', 950)
|
||||
menu.add_urlname(title, 'glyphicon-lamp', 'avahi:index')
|
||||
|
||||
global service # pylint: disable=W0603
|
||||
service = service_module.Service(
|
||||
|
||||
@ -148,7 +148,7 @@ def init():
|
||||
"""Initialize the module"""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(ugettext_lazy('Configure'), 'glyphicon-cog',
|
||||
'config:index', 10)
|
||||
'config:index')
|
||||
|
||||
# Register domain with Name Services module.
|
||||
domainname = get_domainname()
|
||||
|
||||
@ -47,7 +47,7 @@ service = None
|
||||
def init():
|
||||
"""Intialize the date/time module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-time', 'datetime:index', 900)
|
||||
menu.add_urlname(title, 'glyphicon-time', 'datetime:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -50,7 +50,7 @@ description = [
|
||||
def init():
|
||||
"""Initialize the Deluge module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-magnet', 'deluge:index', 200)
|
||||
menu.add_urlname(title, 'glyphicon-magnet', 'deluge:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -42,7 +42,7 @@ depends = ['system']
|
||||
def init():
|
||||
"""Initialize the module"""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-screenshot', 'diagnostics:index', 30)
|
||||
menu.add_urlname(title, 'glyphicon-screenshot', 'diagnostics:index')
|
||||
|
||||
|
||||
def diagnose():
|
||||
|
||||
@ -52,7 +52,7 @@ description = [
|
||||
def init():
|
||||
"""Initialize the module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-refresh', 'dynamicdns:index', 500)
|
||||
menu.add_urlname(title, 'glyphicon-refresh', 'dynamicdns:index')
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
|
||||
@ -50,7 +50,7 @@ LOGGER = logging.getLogger(__name__)
|
||||
def init():
|
||||
"""Initailze firewall module"""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-fire', 'firewall:index', 50)
|
||||
menu.add_urlname(title, 'glyphicon-fire', 'firewall:index')
|
||||
|
||||
service_enabled.connect(on_service_enabled)
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ from plinth import cfg, __version__
|
||||
def init():
|
||||
"""Initialize the Help module"""
|
||||
menu = cfg.main_menu.add_urlname(ugettext_lazy('Documentation'),
|
||||
'glyphicon-book', 'help:index', 101)
|
||||
'glyphicon-book', 'help:index')
|
||||
menu.add_urlname(ugettext_lazy('Where to Get Help'), 'glyphicon-search',
|
||||
'help:index_explicit', 5)
|
||||
menu.add_urlname(ugettext_lazy('Manual'), 'glyphicon-info-sign',
|
||||
|
||||
@ -44,7 +44,7 @@ description = [
|
||||
def init():
|
||||
"""Initialize the ikiwiki module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-edit', 'ikiwiki:index', 1100)
|
||||
menu.add_urlname(title, 'glyphicon-edit', 'ikiwiki:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -59,7 +59,7 @@ def init():
|
||||
"""Intialize the module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(_('Certificates (Let\'s Encrypt)'),
|
||||
'glyphicon-lock', 'letsencrypt:index', 20)
|
||||
'glyphicon-lock', 'letsencrypt:index')
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
|
||||
@ -51,7 +51,7 @@ description = [
|
||||
def init():
|
||||
"""Initialize the module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-th-large', 'minetest:index', 325)
|
||||
menu.add_urlname(title, 'glyphicon-th-large', 'minetest:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -54,7 +54,7 @@ def init():
|
||||
"""Initialize the monkeysphere module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(_('Monkeysphere'), 'glyphicon-certificate',
|
||||
'monkeysphere:index', 970)
|
||||
'monkeysphere:index')
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
|
||||
@ -50,7 +50,7 @@ description = [
|
||||
def init():
|
||||
"""Intialize the Mumble module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-headphones', 'mumble:index', 900)
|
||||
menu.add_urlname(title, 'glyphicon-headphones', 'mumble:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -48,7 +48,7 @@ logger = logging.getLogger(__name__)
|
||||
def init():
|
||||
"""Initialize the names module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-tag', 'names:index', 19)
|
||||
menu.add_urlname(title, 'glyphicon-tag', 'names:index')
|
||||
|
||||
domain_added.connect(on_domain_added)
|
||||
domain_removed.connect(on_domain_removed)
|
||||
|
||||
@ -42,7 +42,7 @@ logger = Logger(__name__)
|
||||
def init():
|
||||
"""Initialize the Networks module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-signal', 'networks:index', 18)
|
||||
menu.add_urlname(title, 'glyphicon-signal', 'networks:index')
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
|
||||
@ -53,7 +53,7 @@ description = [
|
||||
def init():
|
||||
"""Intialize the OpenVPN module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-lock', 'openvpn:index', 850)
|
||||
menu.add_urlname(title, 'glyphicon-lock', 'openvpn:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -60,7 +60,7 @@ def init():
|
||||
return
|
||||
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-picture', 'owncloud:index', 700)
|
||||
menu.add_urlname(title, 'glyphicon-picture', 'owncloud:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -34,7 +34,7 @@ title = _('Public Visibility (PageKite)')
|
||||
def init():
|
||||
"""Intialize the PageKite module"""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-flag', 'pagekite:index', 800)
|
||||
menu.add_urlname(title, 'glyphicon-flag', 'pagekite:index')
|
||||
|
||||
# Register kite name with Name Services module.
|
||||
utils.update_names_module(initial_registration=True)
|
||||
|
||||
@ -39,4 +39,4 @@ description = [
|
||||
def init():
|
||||
"""Initialize the power module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-off', 'power:index', 1000)
|
||||
menu.add_urlname(title, 'glyphicon-off', 'power:index')
|
||||
|
||||
@ -60,7 +60,7 @@ managed_services = ['privoxy']
|
||||
def init():
|
||||
"""Intialize the module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-cloud-upload', 'privoxy:index', 1000)
|
||||
menu.add_urlname(title, 'glyphicon-cloud-upload', 'privoxy:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -58,7 +58,7 @@ description = [
|
||||
def init():
|
||||
"""Initialize the quassel module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-retweet', 'quassel:index', 730)
|
||||
menu.add_urlname(title, 'glyphicon-retweet', 'quassel:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -53,7 +53,7 @@ description = [
|
||||
def init():
|
||||
"""Initialize the radicale module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-calendar', 'radicale:index', 375)
|
||||
menu.add_urlname(title, 'glyphicon-calendar', 'radicale:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -62,7 +62,7 @@ managed_services = ['repro']
|
||||
def init():
|
||||
"""Initialize the repro module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-phone-alt', 'repro:index', 825)
|
||||
menu.add_urlname(title, 'glyphicon-phone-alt', 'repro:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -53,7 +53,7 @@ managed_services = ['node-restore']
|
||||
def init():
|
||||
"""Initialize the reStore module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-hdd', 'restore:index', 750)
|
||||
menu.add_urlname(title, 'glyphicon-hdd', 'restore:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -61,7 +61,7 @@ service = None
|
||||
def init():
|
||||
"""Intialize the module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-envelope', 'roundcube:index', 600)
|
||||
menu.add_urlname(title, 'glyphicon-envelope', 'roundcube:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -48,7 +48,7 @@ service = None
|
||||
def init():
|
||||
"""Initialize the module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-bookmark', 'shaarli:index', 350)
|
||||
menu.add_urlname(title, 'glyphicon-bookmark', 'shaarli:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -44,4 +44,4 @@ description = [
|
||||
|
||||
def init():
|
||||
"""Initialize the system module"""
|
||||
cfg.main_menu.add_urlname(title, 'glyphicon-cog', 'system:index', 100)
|
||||
cfg.main_menu.add_urlname(title, 'glyphicon-cog', 'system:index')
|
||||
|
||||
@ -54,7 +54,7 @@ bridge_service = None
|
||||
def init():
|
||||
"""Initialize the module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-eye-close', 'tor:index', 100)
|
||||
menu.add_urlname(title, 'glyphicon-eye-close', 'tor:index')
|
||||
|
||||
global socks_service
|
||||
socks_service = service_module.Service(
|
||||
|
||||
@ -51,7 +51,7 @@ TRANSMISSION_CONFIG = '/etc/transmission-daemon/settings.json'
|
||||
def init():
|
||||
"""Intialize the Transmission module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-save', 'transmission:index', 300)
|
||||
menu.add_urlname(title, 'glyphicon-save', 'transmission:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -50,7 +50,7 @@ managed_services = ['tt-rss']
|
||||
def init():
|
||||
"""Intialize the module."""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-envelope', 'ttrss:index', 780)
|
||||
menu.add_urlname(title, 'glyphicon-envelope', 'ttrss:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -46,7 +46,7 @@ service = None
|
||||
def init():
|
||||
"""Initialize the module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-refresh', 'upgrades:index', 21)
|
||||
menu.add_urlname(title, 'glyphicon-refresh', 'upgrades:index')
|
||||
global service
|
||||
service = service_module.Service(
|
||||
'auto-upgrades', title, is_external=False, is_enabled=is_enabled,
|
||||
|
||||
@ -38,7 +38,7 @@ title = _('Users and Groups')
|
||||
def init():
|
||||
"""Intialize the user module."""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(title, 'glyphicon-user', 'users:index', 15)
|
||||
menu.add_urlname(title, 'glyphicon-user', 'users:index')
|
||||
|
||||
|
||||
def setup(helper, old_version=None):
|
||||
|
||||
@ -58,7 +58,7 @@ managed_services = ['ejabberd']
|
||||
def init():
|
||||
"""Initialize the XMPP module"""
|
||||
menu = cfg.main_menu.get('apps:index')
|
||||
menu.add_urlname(title, 'glyphicon-comment', 'xmpp:index', 400)
|
||||
menu.add_urlname(title, 'glyphicon-comment', 'xmpp:index')
|
||||
|
||||
global service
|
||||
service = service_module.Service(
|
||||
|
||||
@ -20,17 +20,16 @@
|
||||
{% load i18n %}
|
||||
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
{% for item in menu.items %}
|
||||
{% for item in menu.sorted_items %}
|
||||
|
||||
{% if item.url in active_menu_urls %}
|
||||
<li class="active">
|
||||
<a href="{{ item.url }}" class="active">
|
||||
<span class="{{ item.icon }} glyphicon"></span>
|
||||
{% else %}
|
||||
<li>
|
||||
<a href="{{ item.url }}">
|
||||
<span class="{{ item.icon }} glyphicon"></span>
|
||||
{% endif %}
|
||||
<span class="{{ item.icon }} glyphicon"></span>
|
||||
{{ item.label }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@ -119,13 +119,21 @@ class MenuTestCase(TestCase):
|
||||
|
||||
def test_sort_items(self):
|
||||
"""Verify that menu items are sorted correctly."""
|
||||
menu = build_menu()
|
||||
size = 1000
|
||||
menu = build_menu(size)
|
||||
|
||||
for index in range(0, 200):
|
||||
menu.items[index].order = 100
|
||||
|
||||
# Verify that the order of every item is equal to or greater
|
||||
# than the order of the item preceding it
|
||||
for index in range(1, 5):
|
||||
self.assertGreaterEqual(menu.items[index].order,
|
||||
menu.items[index - 1].order)
|
||||
# than the order of the item preceding it and if the order is
|
||||
# the same, the labels are considered.
|
||||
items = menu.sorted_items()
|
||||
for index in range(1, size):
|
||||
self.assertGreaterEqual(items[index].order, items[index - 1].order)
|
||||
if items[index].order == items[index - 1].order:
|
||||
self.assertGreaterEqual(items[index].label,
|
||||
items[index - 1].label)
|
||||
|
||||
def test_add_urlname(self):
|
||||
"""Verify that a named URL can be added to a menu correctly."""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user