Repository: openwisp/openwisp-utils (language: python)

Issue:
[ux] Create UI for the general navigation menu
Design reference 
https://miro.com/app/board/o9J_lMAQQZk=/

### Tasks

- [ ] Need to create the light version from the design reference.
- [ ] Create design for narrow screen.
- [ ] Menu should remain close on page change if it was before.
- [ ] Menu should remain open on page change if it was open before
- [ ] Don't show a menu on the login page.
- [ ] Register menu groups for the test project in a good structure.

blocked by #189 




Discussion / hints:

Fix patch:
diff --git a/.stylelintrc.json b/.stylelintrc.json
index f0341a61..517d1d88 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -14,7 +14,7 @@
         "except": ["first-nested"],
         "ignore": ["after-comment", "inside-block"]
       }],
-      "unit-allowed-list": ["em", "rem", "%", "s", "px", "vh", "deg", "dpi"],
+      "unit-allowed-list": ["em", "rem", "%", "s", "px", "vh", "deg", "dpi", "fr"],
       "declaration-block-trailing-semicolon": "always",
       "property-no-unknown": true
     }
diff --git a/README.rst b/README.rst
index 846f82fe..3cdbf9a3 100644
--- a/README.rst
+++ b/README.rst
@@ -444,7 +444,10 @@ specified dashboard chart is not registered.
 Main navigation menu
 --------------------
 
-Add ``openwisp_utils.admin_theme.context_processor.menu_items`` to
+The ``admin_theme`` sub app of this package provides a navigation menu which can be
+manipulated with the functions described in the next sections.
+
+Add ``openwisp_utils.admin_theme.context_processor.menu_groups`` to
 template ``context_processors`` in ``settings.py`` as shown below.
 
 .. code-block:: python
@@ -459,16 +462,223 @@ template ``context_processors`` in ``settings.py`` as shown below.
                 ],
                 'context_processors': [
                     # ... other context processors ...
-                    'openwisp_utils.admin_theme.context_processor.menu_items'    # <----- add this
+                    'openwisp_utils.admin_theme.context_processor.menu_groups'    # <----- add this
                 ],
             },
         },
     ]
 
-If you need to define custom menu items, see:
-`OPENWISP_ADMIN_MENU_ITEMS <#openwisp_admin_menu_items>`_.
+``register_menu_group``
+^^^^^^^^^^^^^^^^^^^^^^^
+
+It allows us to register different menu item or group at different position in the Main Navigation Menu.
+
+**Syntax:**
+
+.. code-block:: python
+
+    register_menu_group(position, config)
+
++--------------------+-------------------------------------------------------------+
+| **Parameter**      | **Description**                                             |
++--------------------+-------------------------------------------------------------+
+| ``position``       | (``int``) Position of the group or item.                    |
++--------------------+-------------------------------------------------------------+
+| ``config``         | (``dict``) Configuration of the goup or item.               |
++--------------------+-------------------------------------------------------------+
+
+Code example:
+
+.. code-block:: python
+
+    from django.utils.translation import ugettext_lazy as _
+    from openwisp_utils.admin_theme.menu import register_menu_group
+
+    register_menu_group(
+        position=1,
+        config={
+            'label': _('My Group'),
+            'items': {
+                1: {
+                    'label': _('Users List'),
+                    'model': 'auth.User',
+                    'name': 'changelist',
+                    'icon': 'list-icon',
+                },
+                2: {
+                    'label': _('Add User'),
+                    'model': 'auth.User',
+                    'name': 'add',
+                    'icon': 'add-icon',
+                },
+            },
+            'icon': 'user-group-icon',
+        },
+    )
+    register_menu_group(
+        position=2,
+        config={
+            'model': 'test_project.Shelf',
+            'name': 'changelist',
+            'label': _('View Shelf'),
+            'icon': 'shelf-icon',
+        },
+    )
+    register_menu_group(
+        position=3, config={'label': _('My Link'), 'url': 'https://link.com'}
+    )
+
+.. note::
+    An ``ImproperlyConfigured`` exception is raised if a menu element is already registered at the same position.
+
+    An ``ImproperlyConfigured`` exception is raised also if proper configuration is not provided based on the different types of
+    menu elements that you can register. Different types of configurations will be discussed in the next sections.
+
+    It is recommended to use ``register_menu_group`` in the ``ready`` method of the ``AppConfig``.
+    
+    ``register_menu_items`` is obsoleted by ``register_menu_group`` and will be removed in
+    future versions. Links added using ``register_menu_items`` will be shown at the top
+    of navigation menu and above any ``register_menu_group`` items.
+
+Adding a generic link
+~~~~~~~~~~~~~~~~~~~~~
+
+If you want to add a link which contains a custom url then you can use following syntax for config.
+
+**Syntax:**
+
+.. code-block:: python
+
+    register_menu_group(position=1, config={
+        "label": "Link Label",
+        "url": "link_url",
+        "icon": "my-icon"
+    })
+
+Following is the description of the configuration:
+
++------------------+--------------------------------------------------------------+
+| **Parameter**    | **Description**                                              |
++------------------+--------------------------------------------------------------+
+| ``label``        | (``str``) Display text for the link.                         |
++------------------+--------------------------------------------------------------+
+| ``url``          | (``str``) url for the link.                                  |
++------------------+--------------------------------------------------------------+
+| ``icon``         | An **optional** ``str`` CSS class name for the icon. No icon |
+|                  | is displayed if not provided.                                |
++------------------+--------------------------------------------------------------+
+
+Adding a model link
+~~~~~~~~~~~~~~~~~~~
+
+If you want to add a link that contains url of ``add`` or ``list`` page of a model
+then you can use following syntax. Users will only be able to see links for 
+models they have permission to either view or edit.
+
+**Syntax:**
 
-Users will only be able to see menu items for objects they have permission to either view or edit.
+.. code-block:: python
+
+    # adding a link of list page
+    register_menu_group(
+        position=1,
+        config={
+            'model': 'my_project.MyModel',
+            'name': 'changelist',
+            'label': 'MyModel List',
+            'icon': 'my-model-list-class',
+        },
+    )
+
+    # adding a link of add page
+    register_menu_group(
+        position=2,
+        config={
+            'model': 'my_project.MyModel',
+            'name': 'add',
+            'label': 'MyModel Add Item',
+            'icon': 'my-model-add-class',
+        },
+    )
+
+Following is the description of the configuration:
+
++------------------+--------------------------------------------------------------+
+| **Parameter**    | **Description**                                              |
++------------------+--------------------------------------------------------------+
+| ``model``        | (``str``) Model of the app for which you to add link.        |
++------------------+--------------------------------------------------------------+
+| ``name``         | (``str``) url name. eg. changelist or add.                   |
++------------------+--------------------------------------------------------------+
+| ``label``        | An **optional** ``str`` display text for the link. It is     |
+|                  | automatically generated if not provided.                     |
++------------------+--------------------------------------------------------------+
+| ``icon``         | An **optional** ``str`` CSS class name for the icon. No icon |
+|                  | is displayed if not provided.                                |
++------------------+--------------------------------------------------------------+
+
+Adding a menu group
+~~~~~~~~~~~~~~~~~~~
+
+If you want to add a nested menu group then you can use following syntax.
+It creates a dropdown in the menu.
+
+**Syntax:**
+
+.. code-block:: python
+    
+    register_menu_group(
+        position=1,
+        config={
+            'label': 'My Group Label',
+            'items': {
+                1: {'label': 'Link Label', 'url': 'link_url', 'icon': 'my-icon'},
+                2: {
+                    'model': 'my_project.MyModel',
+                    'name': 'changelist',
+                    'label': 'MyModel List',
+                    'icon': 'my-model-list-class',
+                },
+            },
+            'icon': 'my-group-icon-class',
+        },
+    )
+
+Following is the description of the configuration:
+
++------------------+--------------------------------------------------------------+
+| **Parameter**    | **Description**                                              |
++------------------+--------------------------------------------------------------+
+| ``label``        | (``str``) Display name for the link.                         |
++------------------+--------------------------------------------------------------+
+| ``items``        | (``dict``) Items to be displayed in the dropdown.            |
+|                  | It can be a dict of generic links or model links             |
+|                  | with key as their position in the group.                     |
++------------------+--------------------------------------------------------------+
+| ``icon``         | An **optional** ``str`` CSS class name for the icon. No icon |
+|                  | is displayed if not provided.                                |
++------------------+--------------------------------------------------------------+
+
+How to use custom icons in the menu
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Create a CSS file and use following syntax to provide the image for each
+icon used in the menu. The CSS class name should be same as the ``icon``
+parameter used in configuration of a menu item or group and ``icon`` should be
+in ``svg`` format.
+
+Example:
+
+.. code-block:: css
+
+    .icon-class-name:{
+        mask-image: url(imageurl);
+        -webkit-mask-image: url(imageurl);
+    }
+
+Follow the instructions in
+`Supplying custom CSS and JS for the admin theme <#supplying-custom-css-and-js-for-the-admin-theme>`_
+to know how to configure your OpenWISP instance to load custom CSS files.
 
 Model utilities
 ---------------
@@ -549,27 +759,6 @@ Code utilities
 
 Generates an random string of 32 characters.
 
-``openwisp_utils.utils.register_menu_items``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Takes input of a list of models name and settings_menu name and adds
-them to the side navigation bar in the admin dashboard interface.
-
-Usage:
-
-.. code-block:: python
-
-    from openwisp_utils.utils import register_menu_items
-    from openwisp_utils.api.apps import ApiAppConfig
-
-    class YourAwesomeAppConfig(ApiAppConfig):
-        def ready(self, *args, **kwargs):
-            super().ready(*args, **kwargs)
-            items = [{'model': 'your_project.your_model_name'}]
-            # register_menu_items(items[, name_menu=YOUR_SETTINGS_MENU_NAME])
-            register_menu_items(items, name_menu='OPENWISP_DEFAULT_ADMIN_MENU_ITEMS')
-
-
 ``openwisp_utils.utils.deep_merge_dicts``
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1004,32 +1193,6 @@ When ``True``, enables the `OpenWISP Dashboard <#openwisp-dashboard>`_.
 Upon login, the user will be greeted with the dashboard instead of the default
 Django admin index page.
 
-``OPENWISP_ADMIN_MENU_ITEMS``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-**default**: ``[]``
-
-Allows to pass a custom list of menu items to display in the admin menu.
-
-If passed, overrides the default menu which is built by different openwisp modules.
-
-The list should not include "home", "change password" and "log out", because those
-are automatically added and cannot be removed.
-
-Example usage:
-
-.. code-block:: python
-
-    OPENWISP_ADMIN_MENU_ITEMS = [
-        {'model': 'config.Device'},
-        {'model': 'config.Template'},
-        {'model': 'openwisp_users.User'},
-        {
-            'model': 'openwisp_radius.Accounting',
-            'label': 'Radius sessions'  # custom label
-        }
-    ]
-
 ``OPENWISP_ADMIN_THEME_LINKS``
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/openwisp_utils/admin_theme/apps.py b/openwisp_utils/admin_theme/apps.py
index eec83a40..662c8f42 100644
--- a/openwisp_utils/admin_theme/apps.py
+++ b/openwisp_utils/admin_theme/apps.py
@@ -1,7 +1,9 @@
 from django.apps import AppConfig
+from django.utils.translation import ugettext_lazy as _
 
 from . import settings as app_settings
 from .checks import admin_theme_settings_checks
+from .menu import register_menu_group
 
 
 class OpenWispAdminThemeConfig(AppConfig):
@@ -10,6 +12,7 @@ class OpenWispAdminThemeConfig(AppConfig):
 
     def ready(self):
         admin_theme_settings_checks(self)
+        self.register_menu_groups()
         # monkey patch django.contrib.admin.apps.AdminConfig.default_site
         # in order to supply our customized admin site class
         # this is necessary in order to avoid having to modify
@@ -17,3 +20,10 @@ def ready(self):
         from django.contrib import admin
 
         admin.apps.AdminConfig.default_site = app_settings.ADMIN_SITE_CLASS
+
+    def register_menu_groups(self):
+        # register dashboard item
+        register_menu_group(
+            position=10,
+            config={'label': _('Home'), 'url': '/admin', 'icon': 'ow-dashboard-icon'},
+        )
diff --git a/openwisp_utils/admin_theme/context_processor.py b/openwisp_utils/admin_theme/context_processor.py
index f785e139..d5d0c061 100644
--- a/openwisp_utils/admin_theme/context_processor.py
+++ b/openwisp_utils/admin_theme/context_processor.py
@@ -1,14 +1,24 @@
+import logging
+import sys
+
 from django.apps import registry
 from django.conf import settings
 from django.urls import reverse
 
+from ..admin_theme.menu import build_menu_groups
 from . import settings as app_settings
 
 
-def menu_items(request):
+def menu_groups(request):
     menu = build_menu(request)
+    if menu and sys.argv[1:2] != ['test']:
+        logging.warning(
+            'register_menu_items is deprecated. Please update to use register_menu_group'
+        )
+    menu_groups = build_menu_groups(request)
     return {
         'openwisp_menu_items': menu,
+        'openwisp_menu_groups': menu_groups,
         'show_userlinks_block': getattr(
             settings, 'OPENWISP_ADMIN_SHOW_USERLINKS_BLOCK', False
         ),
@@ -26,7 +36,7 @@ def build_menu(request):
         app_label, model = item['model'].split('.')
         model_class = registry.apps.get_model(app_label, model)
         model_label = model.lower()
-        url = reverse('admin:{}_{}_changelist'.format(app_label, model_label))
+        url = reverse(f'admin:{app_label}_{model_label}_changelist')
         label = item.get('label', model_class._meta.verbose_name_plural)
         view_perm = f'{app_label}.view_{model_label}'
         change_perm = f'{app_label}.change_{model_label}'
@@ -45,3 +55,8 @@ def admin_theme_settings(request):
         'OPENWISP_ADMIN_THEME_LINKS': app_settings.OPENWISP_ADMIN_THEME_LINKS,
         'OPENWISP_ADMIN_THEME_JS': app_settings.OPENWISP_ADMIN_THEME_JS,
     }
+
+
+# Kept for backward compatibility
+# Todo: remove in version 0.9.0
+menu_items = menu_groups
diff --git a/openwisp_utils/admin_theme/menu.py b/openwisp_utils/admin_theme/menu.py
new file mode 100644
index 00000000..2463c570
--- /dev/null
+++ b/openwisp_utils/admin_theme/menu.py
@@ -0,0 +1,204 @@
+from django.apps import registry
+from django.core.exceptions import ImproperlyConfigured
+from django.urls import reverse
+
+from ..utils import SortedOrderedDict
+
+MENU = SortedOrderedDict()
+
+
+class BaseMenuItem:
+    """
+    It is a base class for all types of menu items.
+    It is used to handle some common functions.
+    """
+
+    def __init__(self, config):
+        if not isinstance(config, dict):
+            raise ImproperlyConfigured(
+                f'"config" should be a type of "dict". Error for config- {config}'
+            )
+
+    def get_context(self, request=None):
+        return self.create_context(request)
+
+    def create_context(self, request=None):
+        return {'label': self.label, 'url': self.url, 'icon': self.icon}
+
+    def set_label(self, config):
+        label = config.get('label')
+        if not label:
+            raise ImproperlyConfigured(f'"label" is missing in the config- {config}')
+        self.label = label
+
+
+class ModelLink(BaseMenuItem):
+    """
+    It is to used create a link for a model, like "list view" and "add view".
+    Parameters for the config: name, model, label, icon
+    """
+
+    def __init__(self, config):
+        super().__init__(config)
+        name = config.get('name')
+        model = config.get('model')
+        if name:
+            if not isinstance(name, str):
+                raise ImproperlyConfigured(
+                    f'"name" should be a type of "str". Error for config-{config}'
+                )
+            self.name = name
+        else:
+            raise ImproperlyConfigured(f'"name" is missing in the config-{config}')
+        if not model:
+            raise ImproperlyConfigured(f'"model" is missing in config-{config}')
+        if not isinstance(model, str):
+            raise ImproperlyConfigured(
+                f'"model" should be a type of "str". Error for config-{config}'
+            )
+        self.model = model
+        self.set_label(config)
+        self.icon = config.get('icon')
+
+    def set_label(self, config=None):
+        if config.get('label'):
+            return super().set_label(config)
+        app_label, model = config['model'].split('.')
+        model_class = registry.apps.get_model(app_label, model)
+        self.label = f'{model_class._meta.verbose_name_plural} {self.name}'
+
+    def create_context(self, request):
+        app_label, model = self.model.split('.')
+        model_label = model.lower()
+        url = reverse(f'admin:{app_label}_{model_label}_{self.name}')
+        view_perm = f'{app_label}.view_{model_label}'
+        change_perm = f'{app_label}.change_{model_label}'
+        user = request.user
+        has_permission_method = (
+            user.has_permission if hasattr(user, 'has_permission') else user.has_perm
+        )
+        if has_permission_method(view_perm) or has_permission_method(change_perm):
+            return {'label': self.label, 'url': url, 'icon': self.icon}
+        return None
+
+
+class MenuLink(BaseMenuItem):
+    """
+    It is used to create any general link by supplying a custom url.
+    Parameters of config: label, url and icon.
+    """
+
+    def __init__(self, config):
+        super().__init__(config)
+        url = config.get('url')
+        self.set_label(config)
+        if not url:
+            raise ImproperlyConfigured(f'"url" is missing in the config- {config}')
+        if not isinstance(url, str):
+            raise ImproperlyConfigured(
+                f'"url" should be a type of "str". Error for the config- {config}'
+            )
+        self.url = url
+        self.icon = config.get('icon')
+
+
+class MenuGroup(BaseMenuItem):
+    """
+    It is used to create a dropdown in the menu.
+    Parameters of config: label, items and icon.
+    each item in items should repesent a config for MenuLink or ModelLink
+    """
+
+    def __init__(self, config):
+        super().__init__(config)
+        items = config.get('items')
+        self.set_label(config)
+        if not items:
+            raise ImproperlyConfigured(f'"items" is missing in the config- {config}')
+        if not isinstance(items, dict):
+            raise ImproperlyConfigured(
+                f'"items" should be a type of "dict". Error for the config- {config}'
+            )
+        self.items = SortedOrderedDict()
+        self.set_items(items, config)
+        self.icon = config.get('icon')
+
+    def get_items(self):
+        return self.items
+
+    def set_items(self, items, config):
+        _items = {}
+        for position, item in items.items():
+            if not isinstance(position, int):
+                raise ImproperlyConfigured(
+                    f'"key" should be type of "int". Error for "items" of config- {config}'
+                )
+
+            if not isinstance(item, dict):
+                raise ImproperlyConfigured(
+                    f'Each value of "items" should be a type of "dict". Error for "items" of config- {config}'
+                )
+            if item.get('url'):
+                # It is a menu link
+                try:
+                    _items[position] = MenuLink(config=item)
+                except ImproperlyConfigured as e:
+                    raise ImproperlyConfigured(
+                        f'{e}. "items" of config- {config} should have a valid json'
+                    )
+            elif item.get('model'):
+                # It is a model link
+                try:
+                    _items[position] = ModelLink(config=item)
+                except ImproperlyConfigured as e:
+                    raise ImproperlyConfigured(
+                        f'{e}. "items" of config- {config} should have a valid json'
+                    )
+            else:
+                raise ImproperlyConfigured(
+                    f'"items" should have a valid config. Error for config- {config}'
+                )
+        self.items.update(_items)
+
+    def create_context(self, request):
+        _items = []
+        for item in self.items.values():
+            context = item.get_context(request)
+            if context:
+                _items.append(context)
+        if not _items:
+            return None
+        return {'label': self.label, 'sub_items': _items, 'icon': self.icon}
+
+
+def register_menu_group(position, config):
+    if not isinstance(position, int):
+        raise ImproperlyConfigured('group position should be a type of "int"')
+    if not isinstance(config, dict):
+        raise ImproperlyConfigured('config should be a type of "dict"')
+    if position in MENU:
+        raise ImproperlyConfigured(
+            f'Another group is already registered at position "{position}"'
+        )
+    if config.get('url'):
+        # It is a menu link
+        group_class = MenuLink(config=config)
+    elif config.get('items'):
+        # It is a menu group
+        group_class = MenuGroup(config=config)
+    elif config.get('model'):
+        # It is a model link
+        group_class = ModelLink(config=config)
+    else:
+        # Unknown
+        raise ImproperlyConfigured(f'Invalid config provided at position {position}')
+    MENU.update({position: group_class})
+
+
+def build_menu_groups(request):
+    menu = []
+    for item in MENU.values():
+        item_context = item.get_context(request)
+        if item_context:
+            menu.append(item_context)
+    return menu
diff --git a/openwisp_utils/admin_theme/static/admin/css/openwisp.css b/openwisp_utils/admin_theme/static/admin/css/openwisp.css
index 754a13c5..ae151c0c 100644
--- a/openwisp_utils/admin_theme/static/admin/css/openwisp.css
+++ b/openwisp_utils/admin_theme/static/admin/css/openwisp.css
@@ -1,190 +1,210 @@
-body { min-width: 320px; }
-#header{
-  background-color: #464646;
-  color: #fff;
-  height: auto;
-  padding: 17px 40px !important;
-}
-@media (max-width: 1024px){
-  #header {
-    flex-direction: row !important;
-    justify-content: space-between !important;
-  }
+body {
+  min-width: 320px;
 }
-#site-name a{
-  display: block;
-  width: 150px;
-  height: 70px;
-  background: url(../../../static/ui/openwisp/images/openwisp-logo.svg) no-repeat scroll 0 50% / 100%;
-  text-indent: -2000px;
-  overflow: hidden;
-}
-.login #branding{
-  float: none;
-  padding: 8px 0;
-  margin: 0 auto;
-}
-.login #site-name a{ margin: 0 auto; }
-.button.default,
-input[type=submit].default,
-.submit-row input.default,
-.object-tools a:focus,
-.object-tools a:hover{
-  background-color: #333;
+.menu-backdrop {
+  position: fixed;
+  height: 100vh;
+  width: 100%;
+  top: 0;
+  left: 0;
+  background: rgba(0, 0, 0, 0.10);
+  z-index: 9999;
+  display: none;
 }
-.button.default:active, input[type=submit].default:active,
-.button.default:focus, input[type=submit].default:focus,
-.button.default:hover, input[type=submit].default:hover{
-  background-color: #000;
+#main-content .breadcrumbs,
+.module caption,
+div[class^="app-"].module th, div[class^="app-"].module td {
+  padding: 1rem 1.3rem;
 }
-#branding h1, #branding h1 a:link, #branding h1 a:visited {
-  color: #fff;
-  margin: 0 !important;
+div[class^="app-"].module td { padding-left: 0; }
+#main-content .results thead th .text a {
+  padding: 15px 10px;
 }
-div.breadcrumbs,
-.module h2, .module caption, .inline-group h2,
-#container .selector-chosen h2{
-  background-color: #df5d43;
-  color: #fff;
+#main-content .results tbody td, #main-content .results tbody th {
+  padding: 1rem 10px;
 }
-div.breadcrumbs{
-  color: #ffcbc0;
+#main-content .results thead th {
+  font-size: 13.5px;
 }
-div.breadcrumbs a:focus, div.breadcrumbs a:hover{
-  color: #ffe8e3;
+#main-content .breadcrumbs { font-size: 15px; }
+#main-content .breadcrumbs a,
+a.section:link,
+a.section:visited,
+.module th a,
+#main .help a {
+  color: #df5d43;
+  text-decoration: none;
 }
-.button, input[type=submit], input[type=button], .submit-row input, a.button{
-  background-color: #666;
+#main-content .breadcrumbs a:hover,
+a.section:link:hover,
+a.section:visited:hover,
+.module th a:hover,
+#main-content .breadcrumbs a:focus,
+a.section:link:focus,
+a.section:visited:focus,
+.module th a:focus,
+#main .help a:hover,
+#main .help a:focus {
+  text-decoration: underline;
 }
-.button:active, input[type=submit]:active, input[type=button]:active,
-.button:focus, input[type=submit]:focus, input[type=button]:focus,
-.button:hover, input[type=submit]:hover, input[type=button]:hover {
-  background-color: #444;
+#main-content .module caption a {
+  text-decoration: none;
+  color: #000;
 }
-#user-tools a:focus, #user-tools a:hover{
-  border-bottom-color: #ffcbc0;
-  color: #ffcbc0;
+#main-content .module caption a:hover {
+  text-decoration: underline;
 }
-#container .object-tools a{
-  padding: 5px 15px;
+.module h2,
+.module caption,
+.inline-group h2,
+fieldset.module h2 {
+  background: #f9f9f9;
+  color: #333;
+  padding: 15px;
 }
-
-#container .object-tools a.addlink{ padding-right: 28px; }
 table thead th.sorted .sortoptions a.sortremove:focus:after,
 table thead th.sorted .sortoptions a.sortremove:hover:after,
-a:link, a:visited {
+a:link,
+a:visited {
   color: #777;
+  text-decoration: none;
 }
-a:focus, a:hover {
+table thead th.sorted .sortoptions a.sortremove:focus:after,
+table thead th.sorted .sortoptions a.sortremove:hover:after,
+a:hover,
+a:focus {
   color: #000;
+  text-decoration: none;
 }
-#changelist-filter li.selected a{
+#changelist-filter li.selected a {
   color: #df5d43 !important;
 }
-#netjsonconfig-hint, #netjsonconfig-hint a,
-#container .field-backend a{ color: #df5d43; }
+#netjsonconfig-hint,
+#netjsonconfig-hint a,
+#container .field-backend a {
+  color: #df5d43;
+}
 #main .form-row label {
   color: #1b1818;
 }
-#main .form-row .help {
-  margin-top: 3px;
-  font-size: 13px;
-  color: #797572;
+#main .form-row .help,
+#container #main-content .help {
+  font-size: 14px !important;
+  line-height: 20px;
+  color: rgba(0, 0, 0, 0.45);
 }
-
-/* hide first delete link, hide save and add anoher */
-#main .submit-row:first-child .deletelink-box,
-.submit-row input[name="_addanother"] { display: none; }
-#main .submit-row .default { background: #498b26; }
-
-/* temporary frontend fix */
-a.button.secondaryAction{
-  background: transparent;
-  border: 0 none;
-  padding: 0;
-  margin: 15px 0;
-  display: block;
+.addlink, .changelink {
+  font-weight: bold;
+}
+.changelink { padding-left: 17px; }
+.addlink:hover, .changelink:hover {
+  color: #000;
 }
 
-/* menu */
+/* increase font size and spacing */
 
-html { overflow-x: hidden; }
-.nav-icon {
-  height: 16px;
-  vertical-align: middle;
+.module caption, .inline-group h2,
+#content-related h3,
+fieldset.module h2 {
+  font-size: 16px;
+}
+#main .inline-related h3 {
+  padding: 15px;
+  font-size: 15px;
+  background: #F9F9F9;
+}
+td, th, li {
+  font-size: 14px;
+}
+.mini { font-size: 12px; }
+#main .actionlist li {
+  line-height: 20px;
+  background-position: 0px 4px;
+}
+#main .aligned label,
+input, textarea, select, .form-row p, form .button,
+.readonly,
+#main .form-row { font-size: 15px; }
+select:not([disabled]):not(.readonly) { background: #fff; }
+input[type=text],
+input[type=password], input[type=email],
+input[type=url], input[type=number],
+input[type=tel], textarea,
+#main .vTextField {
+  padding: 8px 12px;
+  box-sizing: border-box;
+}
+select { height: 36px; padding: 0 12px; }
+#main span.select2-selection {
+  min-height: 36px;
+  min-width: 320px;
   position: relative;
-  top: -1px;
 }
-.nav-text {
-  vertical-align: middle;
-  display: inline-block;
+.select2-dropdown,
+.select2-container {
+  min-width: 320px !important;
 }
-#nav-activate {
-  position: absolute;
-  right: 40px;
-  cursor: pointer;
-  padding: 0;
-  background-color: #222;
-  line-height: 40px !important;
-  width: 52px;
-  text-align: center;
+#main .select2-selection__arrow {
+  height: 28px;
+  top: 3px;
+  right: 4px;
+  width: 24px;
 }
-
-#nav-activate:hover { background-color: #000; }
-#nav-activate:focus { outline: none; }
-
-#user-tools { padding-right: 76px; }
-#main-menu {
-  opacity: 0;
-  padding: 0 37px;
-  margin-top: 0;
-  width: 180px;
-  overflow: hidden;
-  position: absolute;
-  z-index: 9999 !important;
-  right: -270px;
-  top: 0;
-  background-color: #464646;
-  z-index: 10;
-  transition: all .5s;
+#main .select2-selection__rendered {
+  line-height: 34px;
+  height: 36px;
+  padding: 0 0 0 12px;
+  width: 100%;
+  box-sizing: border-box;
 }
-
-/* avoid change list filter to cover menu */
-#changelist-filter{ z-index: 9 !important; }
-#menu-toggle {
-  position: absolute;
-  left: -20px;
+.select2-results__option {
+  padding: 10px 12px !important;
 }
-#menu-toggle:checked ~ #main-menu, #main-menu:focus-within {
-  opacity: 1;
-  left: auto;
-  right: 0;
+.select2-search--dropdown .select2-search__field {
+  border: 1px solid rgba(0, 0, 0, 0.4);
+  border-radius: 4px;
+  box-sizing: border-box;
+}
+.select2-selection__clear {
+  left: -27px;
+}
+.related-widget-wrapper .change-related { margin-left: 7px; }
+#main .form-row { padding: 15px; box-sizing: border-box; }
+#main .inline-group .tabular td.original p { height: auto; }
+#main .inline-group thead th {
+  background: transparent;
+}
+#main .inline-group thead th:not(.original),
+#main .add-row td ,
+#main div.add-row {
+  padding-top: 15px;
+  padding-bottom: 15px;
+}
+#main .add-row td a,
+#main div.add-row a { font-size: 15px !important; }
+#main .delete input { vertical-align: -1px; }
+#main .delete label { font-size: 14px; }
+ul.messagelist li {
+  padding: 15px 10px 15px 65px;
+  background-position: 40px 17px;
+}
+
+/* hide first delete link, hide save and add anoher */
+#main .submit-row:first-child .deletelink-box,
+.submit-row input[name='_addanother'] {
+  display: none;
 }
-#main-menu a {
+
+/* temporary frontend fix */
+a.button.secondaryAction {
+  background: transparent;
+  border: 0 none;
+  padding: 0;
+  margin: 0.938rem 0;
   display: block;
-  text-align: center;
-  padding: 15px 0px 15px;
-  margin: 0 0 8px 0;
-  background-color: #222;
-  text-transform: uppercase;
-  font-size: 12px;
-  font-weight: bold;
 }
-#main-menu a:hover,
-#main-menu a:focus {
-  text-decoration: none !important;
-  background-color: #000;
-}
-#main-menu > a:first-child { margin-top: 15px; }
-#main-menu .account { margin-top: 0; }
-#main-menu .account a { background-color: #453232; }
-#main-menu .account a:hover,
-#main-menu .account a:focus { background-color: #2f1e1e; }
-#user-tools .user {
-  background: transparent url(../../ui/openwisp/images/user.svg) no-repeat scroll 0 50%;
-  background-size: 10px 10px;
-  padding-left: 18px;
-  line-height: 40px;
+html {
+  overflow-x: hidden;
 }
 .ow-overlay {
   display: none;
@@ -196,47 +216,1237 @@ html { overflow-x: hidden; }
   height: 100%;
   background: rgba(255, 255, 255, 0.75);
 }
-.ow-overlay-inner{
+.ow-overlay-inner {
+  display: -webkit-box;
+  display: -ms-flexbox;
   display: flex;
   width: 100%;
   height: 100%;
   position: fixed;
   overflow: auto;
   padding: 0;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
   align-items: center;
 }
 .ow-loading-spinner {
-  width: 50px;
-  height: 50px;
+  width: 3.125rem;
+  height: 3.125rem;
   background-color: rgba(0, 0, 0, 0.9);
   margin: 0 auto;
   border-radius: 100%;
-  animation: sk-scaleout 1.0s infinite ease-in-out;
+  -webkit-animation: sk-scaleout 1s infinite ease-in-out;
+  animation: sk-scaleout 1s infinite ease-in-out;
+}
+
+@-webkit-keyframes sk-scaleout {
+  0% {
+    -webkit-transform: scale(0);
+    transform: scale(0);
+  }
+  100% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
+    opacity: 0;
+  }
 }
 
 @keyframes sk-scaleout {
   0% {
     -webkit-transform: scale(0);
     transform: scale(0);
-  } 100% {
-    -webkit-transform: scale(1.0);
-    transform: scale(1.0);
+  }
+  100% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
     opacity: 0;
   }
 }
+div.breadcrumbs {
+  background: #fff;
+  color: #8d7d76cf;
+  border-bottom: 2px solid #f6f6f6;
+}
+#main-content div.breadcrumbs {
+  padding: 1rem 2.5rem;
+}
+#main .selector-chosen h2 {
+  background: rgba(0, 0, 0, 0.6);
+  color: #fff ;
+}
+span.datetimeshortcuts .date-icon{
+  mask: url(../../ui/openwisp/images/date.svg) no-repeat center;
+  -webkit-mask: url(../../ui/openwisp/images/date.svg) no-repeat center;
+  -webkit-mask-size: contain;
+  -webkit-mask: contain;
+  background: #df5d43;
+}
+span.datetimeshortcuts .clock-icon{
+  mask: url(../../ui/openwisp/images/clock.svg) no-repeat center;
+  -webkit-mask: url(../../ui/openwisp/images/clock.svg) no-repeat center;
+  -webkit-mask-size: contain;
+  -webkit-mask: contain;
+  background: #df5d43;
+}
+span.datetimeshortcuts .date-icon:hover,
+span.datetimeshortcuts .clock-icon:hover{
+  background: #b31e00;
+}
+
+/*******************************
+* Common button styles
+*******************************/
+
+/* For toggle button [ class="toggle-btn" ] */
+.toggle-btn {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  box-shadow: 0px 1px 2px #00000040;
+  border-radius: 4px;
+  background: #ffff;
+  cursor: pointer;
+  border: 0;
+  padding: 0.313rem 0.625rem;
+}
+.toggle-btn:hover,
+.toggle-btn:focus,
+.toggle-btn:active {
+  outline: 0 none;
+  background: #eeeeee69;
+}
+
+/* For danger,error, red button [ class="danger-btn" ] */
+.danger-btn,
+div.submit-row a.deletelink,
+.delete-confirmation form input[type='submit'] {
+  display: inline-block;
+  text-align: center;
+  border-radius: 4px;
+  background: #df5d43;
+  cursor: pointer;
+  border: 0;
+  padding: 0.625rem 1rem;
+  color: #fff;
+  font-weight: 500;
+}
+div.submit-row a.deletelink{
+  display: block;
+}
+.danger-btn:hover,
+.danger-btn:focus,
+.danger-btn:active,
+div.submit-row a.deletelink:hover,
+div.submit-row a.deletelink:focus,
+div.submit-row a.deletelink:active,
+.delete-confirmation form input[type='submit']:hover,
+.delete-confirmation form input[type='submit']:active,
+.delete-confirmation form input[type='submit']:focus {
+  background: #b31e00;
+  outline: 0 none;
+}
+
+/* For any normal, default, dark button [ class="default-btn" ] */
+
+.default-btn,
+.button.default,
+input[type='submit'].default,
+.object-tools a,
+.object-tools a:link,
+.object-tools a:visited,
+.button,
+input[type='submit'],
+input[type='button'],
+.submit-row input,
+.delete-confirmation form .cancel-link,
+a.button,
+.object-tools button {
+  display: inline-block;
+  text-align: center;
+  border-radius: 4px;
+  background: #333;
+  cursor: pointer;
+  border: 0;
+  padding: 0.625rem 1rem;
+  color: #fff;
+  font-weight: 500;
+  font-size: 15px;
+}
+div#toolbar {
+  padding: 0.8rem 1.2rem;
+}
+div#toolbar form input[type="submit"]{
+  margin-left: 3px;
+  padding: 0.47rem 1rem;
+  background: #333;
+  border: 1px solid #333;
+  color: #fff;
+}
+div#toolbar #searchbar {
+  padding: 15px 0.8em;
+  font-size: 15px;
+}
+div#changelist .actions label,
+div#changelist .actions span {
+  font-size: 14px !important;
+  line-height: 26px;
+}
+div#changelist .actions select {
+  height: 27px !important;
+}
+div#changelist .actions .button{
+  padding: 6px 1rem;
+  background: #333;
+  color: #fff;
+  height: unset;
+}
+div#changelist .actions .button:hover,
+div#toolbar form input[type="submit"]:hover{
+  opacity: 0.7;
+  border-color: #333;
+}
+.object-tools a,
+.object-tools a:link,
+.object-tools a:visited,
+.object-tools button {
+  padding: 0.4rem 0.8rem;
+  font-size: 13px;
+}
+#container .object-tools a.addlink {
+  background-image: url(../../ui/openwisp/images/add.svg);
+  background-repeat: no-repeat;
+  background-size: 1.35rem;
+  background-position: 0.5rem 43%;
+  padding-left: 1.9rem;
+}
+.default-btn:hover,
+.default-btn:active,
+.button.default:hover,
+.button.default:active,
+.button.default:focus,
+input[type='submit'].default:hover,
+input[type='submit'].default:active,
+input[type='submit'].default:focus,
+.default-btn:focus,
+.object-tools a:hover,
+.object-tools a:active,
+.object-tools a:focus,
+.button:active,
+input[type='submit']:active,
+input[type='button']:active,
+.button:focus,
+input[type='submit']:focus,
+input[type='button']:focus,
+.button:hover,
+input[type='submit']:hover,
+input[type='button']:hover,
+.delete-confirmation form .cancel-link:hover {
+  outline: 0 none;
+  background: rgba(51, 51, 51, 0.7);
+}
+#main .related-lookup { padding-left: 20px; width: auto; }
+.form-row .item-label {
+  position: relative;
+  bottom: -2px;
+  margin-left: 2px;
+  font-weight: bold;
+}
+#main label.vCheckboxLabel { width: auto; }
 
+/* For success, green button [ class="success-btn" ] */
+.success-btn,
+#main .submit-row .default {
+  display: inline-block;
+  text-align: center;
+  border-radius: 4px;
+  background: #498b26;
+  cursor: pointer;
+  border: 0;
+  padding: 0.625rem 1rem;
+  color: #fff;
+  font-weight: 500;
+}
+.success-btn:hover,
+.success-btn:active,
+.success-btn:focus,
+#main .submit-row .default:hover,
+#main .submit-row .default:active,
+#main .submit-row .default:focus {
+  opacity: 0.8;
+  outline: 0 none;
+}
+#main .submit-row input {
+  font-size: 14px;
+}
+
+/*
+  NOTE:
+  "menu-toggle" is a class of a button which is use to close menu.
+  "toggle-menu" is a class toggled on "#contianer" when menu changes it state.
+*/
+
+/* MENU TOGGLE BUTTONS */
+.login h1#site-name {
+  padding: 1.2rem 0;
+}
+.hamburger {
+  display: flex;
+  padding: 0.813rem 0.75rem;
+  cursor: pointer;
+  justify-content: center;
+  align-items: center;
+}
+.hamburger span {
+  background: url(../../ui/openwisp/images/hamburger.svg) no-repeat center;
+  height: 1.375rem;
+  width: 1.375rem;
+  display: inline-block;
+}
+.hamburger:hover {
+  background: #efefef;
+}
+.menu-toggle {
+  position: fixed;
+  left: 18.75rem;
+  width: 1.2rem;
+  border: 0;
+  height: 100px;
+  cursor: pointer;
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  top: 50vh;
+  margin-top: -3.125rem;
+  z-index: 1;
+  transition: all ease;
+  background: rgba(0, 0, 0, 0.25);
+  border-radius: 0 3px 3px 0px;
+}
+.menu-toggle span {
+  mask: url(../../ui/openwisp/images/left-arrow.svg) no-repeat center;
+  -webkit-mask: url(../../ui/openwisp/images/left-arrow.svg) no-repeat center;
+  mask-position: center;
+  background: #ffffff;
+  height: 1rem;
+  width: 1rem;
+  display: inline-block;
+  transition: all 0.3s ease 0.5s;
+}
+.menu-toggle:hover {
+  opacity: 1;
+  right: -1.65rem;
+  width: 1.65rem;
+  background: rgba(0, 0, 0, 0.6);
+}
+
+/* USER TOOLS */
+#ow-user-tools {
+  display: flex;
+  align-items: center;
+  margin-top: 3rem;
+}
+.account {
+  position: relative;
+}
+.account-button:hover,
+.account-button:focus {
+  color: #df5d43;
+}
+.account-button:hover span,
+.account-button:focus span,
+.account-menu a:hover span {
+  background: #df5d43;
+}
+.account-menu {
+  position: absolute;
+  opacity: 1;
+  transition: all 0.3s ease;
+  width: 200px;
+  top: 2.5rem;
+  right: 0;
+  background: #fff;
+  border-radius: 0.5rem;
+  box-shadow: 0px 1px 0.188rem #00000040;
+  z-index: 10;
+  padding: 0.45rem 0.625rem;
+}
+.account-menu.hide {
+  display: block;
+  pointer-events: none;
+  opacity: 0;
+  top: 100px;
+}
+.account span {
+  height: 1.375rem;
+  width: 1.375rem;
+  display: inline-block;
+  background: #777;
+  margin-right: 0.313rem;
+  -webkit-mask-size: 1.375rem;
+  -webkit-mask-repeat: no-repeat;
+  mask-size: 1.375rem;
+  mask-repeat: no-repeat;
+}
+.account-menu span {
+  margin-right: 0.5rem;
+}
+.account-button {
+  padding: 0.313rem 0.625rem;
+  position: relative;
+  color: #777;
+}
+.account-menu li {
+  list-style: none;
+  border-bottom: 2px solid #f6f6f6;
+}
+.account-menu-username {
+  justify-content: center;
+  align-items: center;
+  display: none;
+  color: #777;
+}
+#header .account-menu a {
+  color: #777;
+  display: flex;
+  font-weight: 700;
+  padding: 0.375rem;
+  text-decoration: none;
+  line-height: 22px;
+}
+#header .account-menu li:last-child {
+  border-bottom: 0;
+}
+.account-menu-username:hover,
+#header .account-menu a:hover {
+  color: #df5d43;
+}
+#main-content #header {
+  height: 0;
+  overflow: visible;
+  z-index: 999;
+  justify-content: flex-end;
+  flex-direction: row;
+  padding: 0px 2.5rem;
+}
+.no-auth #site-name a {
+  margin-left: 2.5rem;
+  width: 150px;
+  height: 86px;
+  background: url(../../../static/ui/openwisp/images/openwisp-logo-black.svg)
+  no-repeat scroll 0 50%/100%;
+}
+
+/* Fix for object tools */
+#content-main .object-tools{
+  display: none;
+}
+.title-wrapper h1,
+.title-wrapper h2{
+  float: left;
+  margin-top: 26px;
+  margin-bottom: 0px;
+}
+.title-wrapper .object-tools{
+  float: right;
+  margin: 20px 0px!important;
+  height: auto;
+}
+.title-wrapper .object-tools li{
+  height: auto;
+}
+.dashboard .title-wrapper h1{
+  float: none;
+  margin-bottom: 26px;
+}
+#changelist .results + .paginator{
+  box-sizing: border-box;
+  font-size: 14px;
+}
+p.paginator .this-page{
+  font-size: 14px;
+}
+p.paginator a:link, p.paginator a:visited{
+  background: #df5d43;
+}
+p.paginator a:focus, p.paginator a:hover{
+  background: #b31e00;
+}
+p.paginator a.showall{
+  background: none;
+  color: #df5d43;
+}
+p.paginator a.showall:focus, p.paginator a.showall:hover{
+  color: #b31e00;
+}
+div#toolbar #searchbar{
+  max-width: 68%;
+}
+#main .option-container {
+  position: absolute;
+  margin-top: 39px;
+  display: flex;
+  flex-direction: column;
+  text-align: center;
+  z-index: 999;
+  background-color: #efefef;
+  border-radius: 8px;
+  box-shadow: 0px 1px 3px #00000040;
+  color: #333333;
+  font-weight: normal;
+}
+#main .option-container .option {
+  padding: 10px;
+  border: 0;
+  font-weight: normal;
+  cursor: pointer;
+  background-color: #efefef;
+  color: #333333;
+  border-radius: 0;
+}
+#main .option-container .option:hover,
+#main .option-container .option:focus,
+#main .option-container .option:active {
+  background: #df5d43;
+  color: #fff;
+  outline: 0 none;
+}
+
+/* RESPONSIVE */
 @media (max-width: 1024px) {
-  .nav-icon { height: 15px; }
+  #main-content div.breadcrumbs {
+    padding: 1rem 1.875rem;
+  }
+  #main-content #header {
+    padding: 0rem 1.875rem;
+  }
+  .no-auth #site-name a{
+    margin-left: 1.875rem;
+  }
+}
+@media (max-width: 768px) {
+  #main-content div.breadcrumbs {
+    padding: 1rem 0.938rem;
+  }
+  #main-content #header {
+    padding: 0px 0.938rem;
+    top: 0;
+    position: sticky;
+  }
+  .account-menu-username {
+    display: flex;
+    padding-bottom: 5px;
+  }
+  .account-button strong {
+    display: none;
+  }
+  #ow-user-tools .account-button .user {
+    margin-right: 0;
+  }
+  .default-btn,
+  .success-btn,
+  .error-btn {
+    display: block;
+    text-align: center;
+  }
+  .title-wrapper .object-tools {
+    height: auto;
+    flex-direction: column;
+    align-items: self-start;
+    width: 100%;
+  }
+  .title-wrapper .object-tools li{
+    margin-left: 0px;
+    width: 100%;
+  }
+}
 
-  #main-menu {
-    padding-left: 35px;
-    padding-right: 35px;
+@media (max-width:1226px) and (min-width:1024px){
+
+  /*********** Selector fix ***********/
+  .related-widget-wrapper > a{
+    order: 2;
+  }
+  div.selector{display: flex;flex-direction: column;align-items: center;}
+  div.related-widget-wrapper{
+    display: flex;
+    align-items: flex-start;
+    width: 100%;
+  }
+  div.selector ul.selector-chooser{
+    margin: 15px auto 20px;
+  }
+}
+
+/****** COMMON CSS FOR MENU ON MUTIPLE SCREEN SIZE *****/
+#container.no-auth,
+#container.toggle-menu.no-auth {
+  flex-direction: column;
+}
+div#container.no-auth, .popup div#container{
+  display: flex;
+}
+#container.no-auth #menu {
+  position: relative;
+  height: auto;
+  width: 100%;
+  box-shadow: none;
+  min-height: unset;
+}
+#container.no-auth #main-content {
+  width: auto;
+}
+#container.no-auth #site-name {
+  display: block;
+}
+#container.no-auth .hamburger,
+#container.no-auth .menu-toggle {
+  display: none;
+}
+#menu {
+  background: #fcfcfc;
+  box-shadow: 0 1px 4px -1px #00000026;
+  top: 0;
+  left: 0;
+}
+.menu-bar {
+  border-bottom: 2px solid #f6f6f6;
+}
+a.menu-item,
+.mg-link,
+.mg-head {
+  display: flex;
+  padding: 0.875rem 1rem;
+  word-break: break-word;
+  cursor: pointer;
+  text-transform: uppercase;
+  font-size: 0.86rem;
+  font-weight: 500;
+  align-items: center;
+  color: #777;
+  text-decoration: none !important;
+}
+.menu-item .icon,
+.mg-heading .icon,
+.mg-link .icon {
+  background: #777;
+  width: 1.375rem;
+  height: 1.375rem;
+  flex-shrink: 0;
+  -webkit-mask-repeat: no-repeat;
+  -webkit-mask-position: center;
+  -webkit-mask-size: contain;
+  mask-repeat: no-repeat;
+  mask-position: center;
+  mask-size: contain;
+  display: inline-block;
+  margin-right: 0.8rem;
+}
+.menu-item:hover,
+.mg-head:hover,
+#menu .mg-link:hover,
+.menu-item:focus,
+.mg-head:focus,
+#menu .mg-link:focus,
+.select2-results__option--highlighted[aria-selected],
+.select2-results__option[aria-selected=true] {
+  background: #ffe5e5 !important;
+  color: #df5d43 !important;
+}
+#menu .mg-link:hover,
+#menu .mg-link:focus {
+  color: #c74126;
+}
+.mg-head {
+  justify-content: space-between;
+}
+#menu .mg-link {
+  font-weight: 300;
+  font-size: 0.9rem;
+  padding: 0.55rem 1rem;
+  text-transform: capitalize;
+  color: rgba(0, 0, 0, 0.675);
+}
+.menu-item:hover .icon,
+.mg-head:hover .icon,
+.menu-item:focus .icon,
+.mg-head:focus .icon,
+.mg-head:hover .mg-arrow,
+.mg-head:focus .mg-arrow,
+.menu-group.active .mg-head .icon,
+.mg-link:hover .icon,
+.menu-group.active .mg-arrow {
+  background: #df5d43;
+}
+.mg-arrow {
+  flex-shrink: 0;
+  mask: url(../../ui/openwisp/images/down-arrow.svg) no-repeat center;
+  -webkit-mask: url(../../ui/openwisp/images/down-arrow.svg) no-repeat center;
+  height: 1.25rem;
+  width: 1.25rem;
+  margin-left: 1.25rem;
+  background: #bbbbbb;
+  transition: transform 0.3s;
+}
+.mg-heading {
+  display: flex;
+  align-items: center;
+}
+.mg-dropdown {
+  max-height: 0;
+  overflow: hidden;
+  transition: max-height 0.3s ease;
+  background: #fdf2f2;
+}
+
+/* for transition in the height of mg-dropdown */
+.menu-group.active .mg-dropdown {
+  max-height: 200vh;
+}
+.mg-dropdown-label {
+  text-transform: uppercase;
+  color: #777;
+  padding: 0.625rem 0.875rem;
+  font-weight: 600;
+  display: none;
+}
+.mg-list {
+  padding: 0;
+  margin: 0;
+}
+.mg-list li {
+  list-style: none;
+}
+.menu-group.active .mg-arrow {
+  transform: rotate(-90deg);
+}
+.menu-group.active .mg-head {
+  color: #df5d43;
+}
+.mg-heading,
+.mg-list span,
+.mg-arrow {
+  pointer-events: none;
+}
+.menu-group.active {
+  background: #fdf2f2f2;
+}
+h1#site-name {
+  margin: 0;
+  padding: 0.5rem 0px;
+}
+#site-name a {
+  display: block;
+  width: 165px;
+  height: 95px;
+  margin: auto;
+  background: url(../../../static/ui/openwisp/images/openwisp-logo-black.svg)
+  no-repeat scroll 0 50%/100%;
+  text-indent: -2000px;
+}
+#main-content.m-0 {
+  margin: 0;
+}
+.popup #main-content {
+  margin-left: 0;
+}
+#changelist-search > div{
+  align-items: center;
+}
+
+/****************** MENU(screen-size > 768px) ******************/
+@media (min-width: 769px) {
+  #container {
+    display: block;
+  }
+  .toggle-menu .menu-toggle span {
+    transform: rotate(180deg);
+  }
+  .toggle-menu .hamburger {
+    display: flex;
+  }
+  .toggle-menu .menu-toggle {
+    left: 3.75rem;
+  }
+  .toggle-menu .menu-backdrop {
+    display: none;
+  }
+  .menu-backdrop{
+    display: block;
+  }
+
+  /*** MENU OPEN ***/
+  #container.toggle-menu {
+    height: auto;
+    display: grid;
+    grid-template-columns: 3.75rem calc(100% - 3.75rem);
+    overflow: hidden;
+  }
+  #container:not(.toggle-menu) {
+    margin-left: 3.75rem;
+    width: auto;
+  }
+  .hamburger {
+    display: none;
+  }
+  #main-content #header {
+    position: sticky;
+    top: 0;
+  }
+
+  #menu {
+    position: fixed;
+    width: 18.75rem;
+    height: 100vh;
+    z-index: 9999;
+    overflow: visible;
+  }
+  #menu .nav {
+    height: calc(100% - 105px);
+    overflow-y: hidden;
+    scrollbar-width: thin;
+  }
+  #menu .nav:hover {
+    overflow-y: auto;
+    overflow-y: overlay;
+    overflow-x: hidden;
+    scrollbar-width: thin;
+  }
+
+  a.menu-item,
+  .mg-link,
+  .mg-head {
+    width: 268px;
+  }
+
+  /*** MENU CLOSE ***/
+  .toggle-menu #main-content #header {
+    position: relative;
+  }
+
+  .toggle-menu #menu {
+    width: 3.75rem;
+    position: relative;
+    height: 100%;
+    min-height: 100vh;
+  }
+  .toggle-menu .menu-item .icon,
+  .toggle-menu .mg-heading .icon {
+    margin: 0;
+  }
+
+  .toggle-menu .menu-item,
+  .toggle-menu .mg-head {
+    justify-content: center;
+    width: auto;
+  }
+  .toggle-menu #menu .nav {
+    height: auto;
+    overflow: visible;
+  }
+
+  .toggle-menu .mg-arrow,
+  .toggle-menu #site-name,
+  .toggle-menu .menu-group.active .mg-heading .label {
+    display: none;
+  }
+
+  .toggle-menu .mg-heading .label,
+  .toggle-menu .menu-item .label {
+    opacity: 0;
+    position: absolute;
+    left: 3.125rem;
+    width: fit-content;
+    background: #777;
+    color: #fff;
+    padding: 0.375rem 0.875rem;
+    white-space: nowrap;
+    border-radius: 0.188rem;
+    box-shadow: 0px 0px 4px #00000030;
+    pointer-events: none;
+  }
+
+  .toggle-menu .menu-item:hover .label,
+  .toggle-menu .mg-head:hover .mg-heading .label {
+    opacity: 1;
+    left: 4.1rem;
+    z-index: 2;
+    transition: all 0.2s ease-in;
+  }
+  .toggle-menu .menu-group {
+    position: relative;
+  }
+  .toggle-menu .mg-dropdown {
+    position: absolute;
+    left: 3.95rem;
+    opacity: 0;
+    top: 47px;
+    background: transparent;
+    pointer-events: none;
+    padding: 0.375rem;
+    transition: top 0.3s ease;
+    max-height: unset;
+  }
+  .toggle-menu .mg-dropdown-label,
+  .toggle-menu .mg-list {
+    border-radius: 0.5rem;
+    background: #ffffff;
+    box-shadow: 0px 1px 4px #00000040;
+  }
+  .toggle-menu .mg-dropdown-label {
+    display: block;
+  }
+  .toggle-menu .mg-list {
+    padding: 0.625rem 0rem;
+    margin-top: 0.375rem;
+  }
+  .toggle-menu .menu-group.active .mg-dropdown {
+    opacity: 1;
+    top: 0;
+    z-index: 1;
+    pointer-events: all;
   }
-  #main-menu a { margin-bottom: 12px; }
-  #main-menu .account { margin-top: 0; }
-  #user-tools { margin-left: 10px !important; }
 }
 
-@media (min-width: 700px) {
-  #login-form{ padding-bottom: 20px; }
+/****************** MENU(screen-size > 1024px) ******************/
+@media (min-width: 1024px) {
+  #container:not(.toggle-menu) {
+    margin-left: 0rem;
+  }
+  .menu-backdrop{
+    display: none;
+  }
+
+  /*** MENU OPEN ***/
+  #main-content {
+    margin-left: 18.75rem;
+  }
+
+  /*** MENU CLOSE ***/
+  .toggle-menu #main-content {
+    margin-left: 0;
+  }
+}
+
+/****************** MENU(screen-size < 768px) ******************/
+@media (max-width: 768px) {
+  #container{
+    height: 100vh;
+    overflow-y: scroll;
+    overflow-y: overlay;
+  }
+  #container:not(.toggle-menu)::-webkit-scrollbar {
+    display: none !important;
+  }
+  #container:not(.toggle-menu){
+    scrollbar-width: none;
+  }
+  #main-content #header {
+    margin-bottom: 3rem;
+    position: sticky;
+    z-index: 9999;
+  }
+  .no-auth #main-content #header {
+    margin-bottom: 0;
+  }
+  .menu-toggle {
+    display: none;
+  }
+  h1#site-name {
+    padding: 0;
+    margin-left: 10px;
+  }
+
+  #site-name a {
+    width: 2.5rem;
+    height: 2.5rem;
+    background: url(../../../static/ui/openwisp/images/openwisp-logo-small.svg)  no-repeat center;
+  }
+  .hamburger {
+    padding: 0.813rem 1rem;
+  }
+  .head {
+    display: flex;
+    align-items: center;
+  }
+  .nav {
+    height: calc(100% - 3rem);
+    overflow-y: auto;
+  }
+  .no-auth #site-name a {
+    margin-left: 0.938rem;
+  }
+
+  /*** MENU OPEN ***/
+
+  #menu {
+    height: 100vh;
+    position: fixed;
+    width: 100%;
+    z-index: 9999;
+    overflow: hidden;
+    min-width: 314px;
+    top: 0;
+  }
+
+  /*** MENU CLOSE ***/
+  .toggle-menu #menu {
+    height: 3rem;
+  }
+}
+
+/* LOGIN PAGE */
+
+.login #main-content {
+  padding-bottom: 1.25rem;
+}
+.login #menu {
+  box-shadow: none;
+}
+body.login {
+  background: #f4f7f6;
+}
+.login #container {
+  box-shadow: 0px 0px 6px #f4f7f6;
+  width: 31em !important;
+}
+.hide {
+  display: none;
+}
+.login #menu {
+  position: relative;
+  height: auto;
+  width: 100%;
+}
+.login .head {
+  display: block;
+}
+.login #site-name {
+  display: block;
+}
+.login #site-name a {
+  background: url(../../../static/ui/openwisp/images/openwisp-logo-black.svg)
+  no-repeat scroll 0 50%/100%;
+  text-indent: -2000px;
+  width: 150px;
+  height: 86px;
+  margin: auto;
+}
+.login .hamburger {
+  display: none;
+}
+.login #main .form-row {
+  padding: 4px 0;
+}
+.login #main #content {
+  padding: 20px 35px 10px;
+}
+.login #main .submit-row {
+  padding-left: 0;
+  text-align: center;
+}
+
+/************
+* Scrollbar
+************/
+:root{
+  scrollbar-color: #777 #f1f1f1 !important;
+}
+body::-webkit-scrollbar {
+  width: 12px;
+}
+::-webkit-scrollbar {
+  width: 5px;
+}
+::-webkit-scrollbar-track {
+  background: #f1f1f1;
+}
+::-webkit-scrollbar-thumb {
+  background: #777;
+}
+::-webkit-scrollbar-thumb:hover {
+  background: #333;
+}
+
+/* UTILS ICONS */
+.user {
+  mask-image: url(../../ui/openwisp/images/user.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/user.svg);
+}
+.ow-dashboard-icon {
+  mask-image: url(../../ui/openwisp/images/dashboard.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/dashboard.svg);
+}
+.password {
+  mask-image: url(../../ui/openwisp/images/password.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/password.svg);
+}
+.logout {
+  mask-image: url(../../ui/openwisp/images/logout.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/logout.svg);
+}
+
+/* USERS ICONS */
+
+.ow-users {
+  mask-image: url(../../ui/openwisp/images/users.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/users.svg);
+}
+.ow-org {
+  mask-image: url(../../ui/openwisp/images/org.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/org.svg);
+}
+.ow-org-user {
+  mask-image: url(../../ui/openwisp/images/org-user.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/org-user.svg);
+}
+.ow-org-owner {
+  mask-image: url(../../ui/openwisp/images/org-owner.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/org-owner.svg);
+}
+.ow-user-and-org {
+  mask-image: url(../../ui/openwisp/images/user-and-org.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/user-and-org.svg);
+}
+.ow-permission {
+  mask-image: url(../../ui/openwisp/images/permission.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/permission.svg);
+}
+
+/* CONTROLLER ICONS */
+
+.ow-config {
+  mask-image: url(../../ui/openwisp/images/config.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/config.svg);
+}
+.ow-device {
+  mask-image: url(../../ui/openwisp/images/device.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/device.svg);
+}
+.ow-device-group {
+  mask-image: url(../../ui/openwisp/images/device-group.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/device-group.svg);
+}
+.ow-template {
+  mask-image: url(../../ui/openwisp/images/template.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/template.svg);
+}
+.ow-vpn {
+  mask-image: url(../../ui/openwisp/images/vpn.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/vpn.svg);
+}
+.ow-geo {
+  mask-image: url(../../ui/openwisp/images/geo-info.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/geo-info.svg);
+}
+.ow-location {
+  mask-image: url(../../ui/openwisp/images/location.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/location.svg);
+}
+.ow-floor {
+  mask-image: url(../../ui/openwisp/images/floor.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/floor.svg);
+}
+.ow-cer-group {
+  mask-image: url(../../ui/openwisp/images/cer-group.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/cer-group.svg);
+}
+.ow-access-credential {
+  mask-image: url(../../ui/openwisp/images/access-credential.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/access-credential.svg);
+}
+.ow-ca {
+  mask-image: url(../../ui/openwisp/images/ca.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/ca.svg);
+}
+.ow-certificate {
+  mask-image: url(../../ui/openwisp/images/certificate.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/certificate.svg);
+}
+
+/* RADIUS ICONS */
+
+.ow-radius {
+  mask-image: url(../../ui/openwisp/images/radius.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/radius.svg);
+}
+.ow-radius-accounting {
+  mask-image: url(../../ui/openwisp/images/accounting.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/accounting.svg);
+}
+.ow-batch-creation {
+  mask-image: url(../../ui/openwisp/images/batch-user.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/batch-user.svg);
+}
+.ow-radius-checks {
+  mask-image: url(../../ui/openwisp/images/check.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/check.svg);
+}
+.ow-radius-group {
+  mask-image: url(../../ui/openwisp/images/radius-group.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/radius-group.svg);
+}
+.ow-radius-nas {
+  mask-image: url(../../ui/openwisp/images/nas.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/nas.svg);
+}
+.ow-radius-token {
+  mask-image: url(../../ui/openwisp/images/token.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/token.svg);
+}
+.ow-radius-replies {
+  mask-image: url(../../ui/openwisp/images/replies.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/replies.svg);
+}
+.ow-radius-post-log {
+  mask-image: url(../../ui/openwisp/images/log.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/log.svg);
+}
+
+/* IPAN ICONS */
+
+.ow-ipam {
+  mask-image: url(../../ui/openwisp/images/ipam.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/ipam.svg);
+}
+.ow-subnet {
+  mask-image: url(../../ui/openwisp/images/subnet.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/subnet.svg);
+}
+.ow-ip-address {
+  mask-image: url(../../ui/openwisp/images/ip-address.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/ip-address.svg);
+}
+
+/* MONITORING ICONS */
+
+.ow-monitoring {
+  mask-image: url(../../ui/openwisp/images/monitoring.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/monitoring.svg);
+}
+.ow-metrics {
+  mask-image: url(../../ui/openwisp/images/metrics.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/metrics.svg);
+}
+.ow-monitoring-checks {
+  mask-image: url(../../ui/openwisp/images/montoring-checks.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/montoring-checks.svg);
+}
+
+/* FIRMWARE */
+
+.ow-firmware {
+  mask-image: url(../../ui/openwisp/images/firmware.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/firmware.svg);
+}
+.ow-build {
+  mask-image: url(../../ui/openwisp/images/build.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/build.svg);
+}
+.ow-category {
+  mask-image: url(../../ui/openwisp/images/category.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/category.svg);
+}
+.ow-mass-upgrade {
+  mask-image: url(../../ui/openwisp/images/mass-upgrade.svg);
+  -webkit-mask-image: url(../../ui/openwisp/images/mass-upgrade.svg);
 }
diff --git a/openwisp_utils/admin_theme/static/admin/css/ow-dashboard.css b/openwisp_utils/admin_theme/static/admin/css/ow-dashboard.css
index 93218e7d..4441812f 100644
--- a/openwisp_utils/admin_theme/static/admin/css/ow-dashboard.css
+++ b/openwisp_utils/admin_theme/static/admin/css/ow-dashboard.css
@@ -1,47 +1,34 @@
 #plot-container {
-  padding: 0 40px 10px 40px;
+  padding: 0.625rem 2.5rem;
   text-align: center;
+  overflow-x: hidden;
 }
 .js-plotly-plot {
   display: inline-block;
 }
-.js-plotly-plot .surface{
+.js-plotly-plot .surface {
   cursor: pointer;
 }
 .js-plotly-plot .legendtext,
-.js-plotly-plot .hoverlayer{
+.js-plotly-plot .hoverlayer {
   text-transform: capitalize;
 }
-#quick-menu {
-  line-height: 40px;
-  padding: 20px 40px 0 40px;
-}
-#quick-menu a{
-  color: #fff;
-  padding: 7px 12px;
-  font-size: 12px;
-  text-transform: uppercase;
-  font-variant: small-caps;
-  font-weight: bold;
-  margin: 0 5px 0 0;
-  text-decoration: none !important;
-}
-.dashboard:not([class*="app-"]) #container #content {
+.dashboard:not([class*='app-']) #container #content {
   margin: 0 auto;
   width: auto;
 }
-.dashboard:not([class*="app-"]) #container #content-main {
+.dashboard:not([class*='app-']) #container #content-main {
   width: 63%;
 }
-.dashboard:not([class*="app-"]) #container #content-related {
+.dashboard:not([class*='app-']) #container #content-related {
   width: 35%;
   margin-left: 2%;
   margin-right: 0;
 }
 
 @media (max-width: 767px) {
-  .dashboard:not([class*="app-"]) #container #content-main,
-  .dashboard:not([class*="app-"]) #container #content-related {
+  .dashboard:not([class*='app-']) #container #content-main,
+  .dashboard:not([class*='app-']) #container #content-related {
     width: 100% !important;
     margin-left: 0;
   }
diff --git a/openwisp_utils/admin_theme/static/admin/js/menu.js b/openwisp_utils/admin_theme/static/admin/js/menu.js
index 3270a21e..15e916f9 100644
--- a/openwisp_utils/admin_theme/static/admin/js/menu.js
+++ b/openwisp_utils/admin_theme/static/admin/js/menu.js
@@ -1,21 +1,209 @@
 'use strict';
+const owContainer = document.getElementById('container');
+const owMenu = document.getElementById('menu');
+const owMainContent = document.getElementById('main-content');
+const owMenuToggle = document.querySelector('.menu-toggle');
+const owHamburger = document.querySelector('.hamburger');
+const menuBackdrop = document.querySelector('.menu-backdrop');
+var MenuTransitionTime = '0.1s';
+
 (function () {
-  window.addEventListener('load', function(){
-    var nav = document.getElementById('main-menu'),
-        container = document.getElementById('container'),
-        header = document.getElementById('header'),
-    setHeightToMenu = function() {
-      var windowHeight = window.innerHeight,
-          pageHeight = document.body.scrollHeight || container.offsetHeight,
-          height = windowHeight;
-      if (pageHeight > windowHeight) {
-        height = pageHeight;
+  setMenu();
+  initMenuGroupClickListener();
+  initToggleMenuHandlers();
+  initAccountViewHandler();
+  initToolTipHandlers();
+  initResizeScreenHelpers();
+})();
+
+function Window() {
+  /*
+    To prevent editing of variables from console.
+    Because variables are used to manage state of window
+  */ 
+  var windowWidth = window.innerWidth;
+  this.setWindowWidth = function (size) {
+    windowWidth = size;
+  };
+  this.getWindowWidth = function () {
+    return windowWidth;
+  };
+}
+
+function initResizeScreenHelpers() {
+  function changeMenuState(owWindow) {
+    var currentWidth = window.innerWidth;
+    var isMenuOpen = !owContainer.classList.contains('toggle-menu');
+    if (currentWidth <= 1024) {
+      if (owWindow.getWindowWidth() > 1024 && isMenuOpen) {
+        // close window
+        owContainer.classList.add('toggle-menu');
+        owWindow.setWindowWidth(currentWidth);
+        setMenuToggleText();
       }
-      if (!nav) { return; }
-      nav.style.height = (height - header.offsetHeight) + 'px';
-      nav.style.marginTop = header.offsetHeight + 'px';
-    };
-    setHeightToMenu();
-    window.addEventListener('resize', setHeightToMenu);
+    } else if (owWindow.getWindowWidth() <= 1024) {
+      // when window width is greater than 1024px
+      // work according to user last choice
+      setMenuState();
+      owWindow.setWindowWidth(currentWidth);
+      setMenuToggleText();
+    }
+  }
+  var owWindow = new Window();
+  window.addEventListener('resize', function () {
+    changeMenuState(owWindow);
   });
-})();
+}
+
+function initMenuGroupClickListener() {
+  let mgHeads = document.querySelectorAll('.mg-head');
+  mgHeads.forEach(function (mgHead) {
+    // Handle click on menu group
+    mgHead.addEventListener('click', function (e) {
+      e.stopPropagation();
+      var currentActiveGroup = document.querySelector('.menu-group.active');
+      if (currentActiveGroup && currentActiveGroup !== mgHead.parentElement) {
+        currentActiveGroup.classList.remove('active');
+        currentActiveGroup.querySelector('.mg-dropdown').style = '';
+      }
+      if (
+        window.innerWidth > 768 &&
+        document.querySelector('#container.toggle-menu')
+      ) {
+        var group = e.target.parentElement;
+        var dropdown = group.querySelector('.mg-dropdown');
+        if (!group.classList.contains('active')) {
+          var groupPos = group.offsetTop;
+          var scrolledBy = document.querySelector('html').scrollTop;
+          var dropdownHeight = group.querySelector('.mg-dropdown').offsetHeight;
+          e.target.parentElement.classList.toggle('active');
+          if (dropdownHeight + groupPos - scrolledBy >= window.innerHeight) {
+            dropdown.style.top = -dropdownHeight + 40 + 'px';
+          }
+        } else {
+          e.target.parentElement.classList.toggle('active');
+          dropdown.style = '';
+        }
+        return;
+      }
+      e.target.parentElement.classList.toggle('active');
+    });
+  });
+  // Handle click out side the current active menu group
+  document.addEventListener('click', function (e) {
+    var currentActiveGroup = document.querySelector('.menu-group.active');
+    if (currentActiveGroup && !currentActiveGroup.contains(e.target)) {
+      currentActiveGroup.classList.remove('active');
+      currentActiveGroup.querySelector('.mg-dropdown').style = '';
+    }
+  });
+}
+
+function setMenuState() {
+  let openMenu = localStorage.getItem('ow-menu');
+  if (window.innerWidth > 1024) {
+    if (openMenu === null) {
+      // User visits first time. Keep open menu
+      localStorage.setItem('ow-menu', true);
+      owContainer.classList.toggle('toggle-menu');
+    } else if (openMenu === 'true') {
+      // Close the menu
+      owContainer.classList.toggle('toggle-menu');
+    }
+  }
+}
+
+function setMenuToggleText(){
+  var isMenuOpen = !owContainer.classList.contains('toggle-menu');
+  if(isMenuOpen){
+    owMenuToggle.setAttribute('title','Minimize menu');
+  }
+  else{
+    owMenuToggle.setAttribute('title','Maximize menu');
+  }
+}
+
+function setMenu() {
+  setMenuState();
+  setMenuToggleText();
+  setTimeout(function () {
+    // Transition fix: Add transition to menu and main content
+    // after some time.
+    if (owMenu) {
+      owMenu.style.transitionDuration = MenuTransitionTime;
+    }
+    if (owMainContent) {
+      owMainContent.style.transitionDuration = MenuTransitionTime;
+    }
+    if (owMenuToggle) {
+      owMenuToggle.style.transitionDuration = MenuTransitionTime;
+    }
+  }, 1000);
+  setMenuToggleText();
+}
+
+function initToggleMenuHandlers() {
+  function toggleMenuHandler() {
+    owContainer.classList.toggle('toggle-menu');
+    let isMenuOpen = localStorage.getItem('ow-menu');
+    if (window.innerWidth > 1024) {
+      localStorage.setItem('ow-menu', isMenuOpen === 'true' ? false : true);
+    }
+    setMenuToggleText();
+  }
+  if (owMenuToggle && owContainer) {
+    owMenuToggle.addEventListener('click', toggleMenuHandler);
+  }
+  if (owHamburger && owContainer) {
+    owHamburger.addEventListener('click', toggleMenuHandler);
+  }
+  // Close menu when backdrop is clicked
+  menuBackdrop.addEventListener('click', function (e) {
+    e.stopPropagation();
+    owContainer.classList.toggle('toggle-menu');
+  });
+}
+
+function initAccountViewHandler() {
+  var accountMenu = document.querySelector('.account-menu');
+  var accountToggle = document.querySelector('.account-button');
+  // When account button is clicked
+  if (accountToggle) {
+    accountToggle.addEventListener('click', function (e) {
+      e.stopPropagation();
+      accountMenu.classList.toggle('hide');
+    });
+  }
+  // When clicked outside the account button
+  document.addEventListener('click', function (e) {
+    e.stopPropagation();
+    var target = e.target;
+    if (accountMenu && !accountMenu.contains(target)) {
+      accountMenu.classList.add('hide');
+    }
+  });
+}
+
+function initToolTipHandlers() {
+  // Tooltips shown only on narrow screen
+  var tooltips = document.querySelectorAll('.tooltip-sm');
+  function mouseLeaveHandler(e) {
+    var tooltipText = e.target.getAttribute('tooltip-data');
+    e.target.setAttribute('title', tooltipText);
+    e.target.removeAttribute('tooltip-data');
+    removeMouseLeaveListner(e.target);
+  }
+  function removeMouseLeaveListner(tooltip) {
+    tooltip.removeEventListener('mouseleave', mouseLeaveHandler);
+  }
+  tooltips.forEach(function (tooltip) {
+    tooltip.addEventListener('mouseenter', function () {
+      if (window.innerWidth > 768) {
+        var tooltipText = tooltip.getAttribute('title');
+        tooltip.removeAttribute('title');
+        tooltip.setAttribute('tooltip-data', tooltipText);
+        tooltip.addEventListener('mouseleave', mouseLeaveHandler);
+      }
+    });
+  });
+}
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/access-credential.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/access-credential.svg
new file mode 100644
index 00000000..f37f98a7
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/access-credential.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17 8H18C19.1 8 20 8.9 20 10V20C20 21.1 19.1 22 18 22H6C4.9 22 4 21.1 4 20V17H6V20H18V16V13V10H6V12H4V10C4 8.9 4.9 8 6 8H7V6C7 3.24 9.24 1 12 1C14.76 1 17 3.24 17 6V8ZM12 3C10.34 3 9 4.34 9 6V8H15V6C15 4.34 13.66 3 12 3Z" fill="black"/>
+<rect x="0.5" y="12.5" width="16" height="4" rx="0.5" stroke="black"/>
+<path d="M5.51562 14.5996L5.03809 14.4678L5.1333 14.1909L5.60059 14.3828L5.56396 13.8672H5.87744L5.83936 14.3931L6.29346 14.2056L6.38867 14.4854L5.90527 14.6172L6.22607 15.0054L5.97266 15.1782L5.70459 14.7476L5.43506 15.1636L5.18164 14.998L5.51562 14.5996ZM6.91016 14.5996L6.43262 14.4678L6.52783 14.1909L6.99512 14.3828L6.9585 13.8672H7.27197L7.23389 14.3931L7.68799 14.2056L7.7832 14.4854L7.2998 14.6172L7.62061 15.0054L7.36719 15.1782L7.09912 14.7476L6.82959 15.1636L6.57617 14.998L6.91016 14.5996ZM8.30469 14.5996L7.82715 14.4678L7.92236 14.1909L8.38965 14.3828L8.35303 13.8672H8.6665L8.62842 14.3931L9.08252 14.2056L9.17773 14.4854L8.69434 14.6172L9.01514 15.0054L8.76172 15.1782L8.49365 14.7476L8.22412 15.1636L7.9707 14.998L8.30469 14.5996ZM9.69922 14.5996L9.22168 14.4678L9.31689 14.1909L9.78418 14.3828L9.74756 13.8672H10.061L10.0229 14.3931L10.4771 14.2056L10.5723 14.4854L10.0889 14.6172L10.4097 15.0054L10.1562 15.1782L9.88818 14.7476L9.61865 15.1636L9.36523 14.998L9.69922 14.5996ZM11.0938 14.5996L10.6162 14.4678L10.7114 14.1909L11.1787 14.3828L11.1421 13.8672H11.4556L11.4175 14.3931L11.8716 14.2056L11.9668 14.4854L11.4834 14.6172L11.8042 15.0054L11.5508 15.1782L11.2827 14.7476L11.0132 15.1636L10.7598 14.998L11.0938 14.5996Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/accounting.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/accounting.svg
new file mode 100644
index 00000000..ac391b1f
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/accounting.svg
@@ -0,0 +1,9 @@
+<svg width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14 5V2C14 1.44772 13.5523 1 13 1H2C1.44772 1 1 1.44772 1 2V20C1 20.5523 1.44772 21 2 21H13C13.5523 21 14 20.5523 14 20V20" stroke="black"/>
+<circle cx="14" cy="13.5" r="5.5" stroke="#010101"/>
+<circle cx="14" cy="13.5" r="0.75" stroke="black" stroke-width="0.5"/>
+<path d="M12.5 5.7C12.5 5.58954 12.5895 5.5 12.7 5.5H15.3C15.4105 5.5 15.5 5.58954 15.5 5.7V6.3C15.5 6.41046 15.4105 6.5 15.3 6.5H12.7C12.5895 6.5 12.5 6.41046 12.5 6.3V5.7Z" fill="black"/>
+<path d="M14 6V8" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M14.25 9.5C14.25 9.36193 14.1381 9.25 14 9.25C13.8619 9.25 13.75 9.36193 13.75 9.5H14.25ZM13.75 12.5C13.75 12.6381 13.8619 12.75 14 12.75C14.1381 12.75 14.25 12.6381 14.25 12.5H13.75ZM16.3232 16.1768C16.4209 16.2744 16.5791 16.2744 16.6768 16.1768C16.7744 16.0791 16.7744 15.9209 16.6768 15.8232L16.3232 16.1768ZM13.75 9.5V12.5H14.25V9.5H13.75ZM14.3232 14.1768L16.3232 16.1768L16.6768 15.8232L14.6768 13.8232L14.3232 14.1768Z" fill="black"/>
+<path d="M3.5 4H11M3.5 6.5H11M3.5 9H9M3.5 11.5H7.5M3.5 14H7.3125M3.5 16.5H8" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/add.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/add.svg
new file mode 100644
index 00000000..78e13a8b
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/add.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#fff"><g><rect fill="none" height="24" width="24"/>
+  </g><g><g><path d="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6V13z"/></g></g>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/batch-user.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/batch-user.svg
new file mode 100644
index 00000000..7322fdee
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/batch-user.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/><rect fill="none" height="24" width="24"/></g><g><g><polygon points="22,9 22,7 20,7 20,9 18,9 18,11 20,11 20,13 22,13 22,11 24,11 24,9"/><path d="M8,12c2.21,0,4-1.79,4-4s-1.79-4-4-4S4,5.79,4,8S5.79,12,8,12z"/><path d="M8,13c-2.67,0-8,1.34-8,4v3h16v-3C16,14.34,10.67,13,8,13z"/><path d="M12.51,4.05C13.43,5.11,14,6.49,14,8s-0.57,2.89-1.49,3.95C14.47,11.7,16,10.04,16,8S14.47,4.3,12.51,4.05z"/><path d="M16.53,13.83C17.42,14.66,18,15.7,18,17v3h2v-3C20,15.55,18.41,14.49,16.53,13.83z"/>
+  </g></g>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/build.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/build.svg
new file mode 100644
index 00000000..7df363b9
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/build.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <g><rect fill="none" height="24" width="24"/></g><g><g><rect height="8.48" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -6.8717 17.6255)" width="3" x="16.34" y="12.87"/><path d="M17.5,10c1.93,0,3.5-1.57,3.5-3.5c0-0.58-0.16-1.12-0.41-1.6l-2.7,2.7L16.4,6.11l2.7-2.7C18.62,3.16,18.08,3,17.5,3 C15.57,3,14,4.57,14,6.5c0,0.41,0.08,0.8,0.21,1.16l-1.85,1.85l-1.78-1.78l0.71-0.71L9.88,5.61L12,3.49 c-1.17-1.17-3.07-1.17-4.24,0L4.22,7.03l1.41,1.41H2.81L2.1,9.15l3.54,3.54l0.71-0.71V9.15l1.41,1.41l0.71-0.71l1.78,1.78 l-7.41,7.41l2.12,2.12L16.34,9.79C16.7,9.92,17.09,10,17.5,10z"/></g></g>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/ca.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/ca.svg
new file mode 100644
index 00000000..5b21f8f3
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/ca.svg
@@ -0,0 +1,10 @@
+<svg width="22" height="23" viewBox="0 0 22 23" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7 22H20C20.5523 22 21 21.5523 21 21V2C21 1.44772 20.5523 1 20 1H8C7.44772 1 7 1.44772 7 2V8.5" stroke="black"/>
+<path d="M7 9.5L2.5 11.5V14.5C2.5 17.275 4.42 19.87 7 20.5C9.58 19.87 11.5 17.275 11.5 14.5V11.5L7 9.5ZM7 14.995H10.5C10.235 17.055 8.86 18.89 7 19.465V15H3.5V12.15L7 10.595V14.995Z" fill="black"/>
+<path d="M13.5001 3.41675C12.3501 3.41675 11.4167 4.35008 11.4167 5.50008C11.4167 6.65008 12.3501 7.58342 13.5001 7.58342C14.6501 7.58342 15.5834 6.65008 15.5834 5.50008C15.5834 4.35008 14.6501 3.41675 13.5001 3.41675ZM13.5001 7.16675C12.5813 7.16675 11.8334 6.41883 11.8334 5.50008C11.8334 4.58133 12.5813 3.83341 13.5001 3.83341C14.4188 3.83341 15.1667 4.58133 15.1667 5.50008C15.1667 6.41883 14.4188 7.16675 13.5001 7.16675ZM14.4563 4.57925L13.0834 5.95216L12.5438 5.41466L12.2501 5.70841L13.0834 6.54175L14.7501 4.87508L14.4563 4.57925Z" fill="black"/>
+<path d="M13.5 10.5C13.5 10.7761 13.2761 11 13 11C12.7239 11 12.5 10.7761 12.5 10.5C12.5 10.2239 12.7239 10 13 10C13.2761 10 13.5 10.2239 13.5 10.5Z" fill="black"/>
+<rect x="14" y="10" width="5" height="1" rx="0.5" fill="black"/>
+<path d="M13.5 12.5C13.5 12.7761 13.2761 13 13 13C12.7239 13 12.5 12.7761 12.5 12.5C12.5 12.2239 12.7239 12 13 12C13.2761 12 13.5 12.2239 13.5 12.5Z" fill="black"/>
+<rect x="14" y="12" width="5" height="1" rx="0.5" fill="black"/>
+<path d="M15.8333 18.3334V19.5834H19.1666V18.3334C19.1666 18.1042 18.9791 17.9167 18.7499 17.9167H16.2499C16.0208 17.9167 15.8333 18.1042 15.8333 18.3334ZM18.7499 18.7501H16.2499V18.3334H18.7499V18.7501ZM17.4999 15.4167C16.9249 15.4167 16.4583 15.8834 16.4583 16.4584L17.4999 17.9167L18.5416 16.4584C18.5416 15.8834 18.0749 15.4167 17.4999 15.4167ZM17.4999 17.2917L16.8749 16.4584C16.8749 16.1126 17.1541 15.8334 17.4999 15.8334C17.8458 15.8334 18.1249 16.1126 18.1249 16.4584L17.4999 17.2917Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/category.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/category.svg
new file mode 100644
index 00000000..a121361a
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/category.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0z" fill="none"/><path d="M12 2l-5.5 9h11z"/><circle cx="17.5" cy="17.5" r="4.5"/>
+  <path d="M3 13.5h8v8H3z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/cer-group.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/cer-group.svg
new file mode 100644
index 00000000..3ff74997
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/cer-group.svg
@@ -0,0 +1,9 @@
+<svg width="21" height="22" viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1 18.5V20C1 20.5523 1.44772 21 2 21H14C14.5523 21 15 20.5523 15 20V2C15 1.44772 14.5523 1 14 1H2C1.44772 1 1 1.44772 1 2V16" stroke="black"/>
+<path d="M16 2.5L19.4847 2.88724C20.0418 2.94916 20.4393 3.45691 20.3655 4.01263L20.0703 6.23809M19.9472 7.59865L18.5996 19.6115C18.5428 20.1175 18.115 20.5 17.6058 20.5L16.4999 20.5" stroke="black"/>
+<path d="M8 3.25L5.75 4.25V5.75C5.75 7.1375 6.71 8.435 8 8.75C9.29 8.435 10.25 7.1375 10.25 5.75V4.25L8 3.25ZM9.75 5.75C9.75 6.88 9.005 7.9225 8 8.2325C6.995 7.9225 6.25 6.88 6.25 5.75V4.575L8 3.7975L9.75 4.575V5.75ZM6.8525 5.8975L6.5 6.25L7.5 7.25L9.5 5.25L9.1475 4.895L7.5 6.5425L6.8525 5.8975Z" fill="black"/>
+<path d="M4.5 11.25C3.81 11.25 3.25 11.81 3.25 12.5C3.25 13.19 3.81 13.75 4.5 13.75C5.19 13.75 5.75 13.19 5.75 12.5C5.75 11.81 5.19 11.25 4.5 11.25ZM4.5 13.5C3.94875 13.5 3.5 13.0512 3.5 12.5C3.5 11.9488 3.94875 11.5 4.5 11.5C5.05125 11.5 5.5 11.9488 5.5 12.5C5.5 13.0512 5.05125 13.5 4.5 13.5ZM5.07375 11.9475L4.25 12.7713L3.92625 12.4488L3.75 12.625L4.25 13.125L5.25 12.125L5.07375 11.9475Z" fill="black"/>
+<path d="M4.5 15.25C3.81 15.25 3.25 15.81 3.25 16.5C3.25 17.19 3.81 17.75 4.5 17.75C5.19 17.75 5.75 17.19 5.75 16.5C5.75 15.81 5.19 15.25 4.5 15.25ZM4.5 17.5C3.94875 17.5 3.5 17.0512 3.5 16.5C3.5 15.9488 3.94875 15.5 4.5 15.5C5.05125 15.5 5.5 15.9488 5.5 16.5C5.5 17.0512 5.05125 17.5 4.5 17.5ZM5.07375 15.9475L4.25 16.7713L3.92625 16.4488L3.75 16.625L4.25 17.125L5.25 16.125L5.07375 15.9475Z" fill="black"/>
+<path d="M7 12H12M7 13H8.5H10" stroke="black" stroke-width="0.5"/>
+<path d="M7 16H12M7 17H8.5H10" stroke="black" stroke-width="0.5"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/certificate.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/certificate.svg
new file mode 100644
index 00000000..27d66ea8
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/certificate.svg
@@ -0,0 +1,7 @@
+<svg width="24" height="21" viewBox="0 0 24 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1 3.34375V3C1 1.89543 1.89543 1 3 1H21C22.1046 1 23 1.89543 23 3V13.1875M1 4.75V14C1 15.1046 1.89543 16 3 16H14M23 14.125V14.125C23 15.1605 22.1605 16 21.125 16H19" stroke="black"/>
+<path d="M19 13V20.3234C19 20.4011 18.9152 20.4491 18.8486 20.4091L16.5514 19.0309C16.5198 19.0119 16.4802 19.0119 16.4486 19.0309L14.1514 20.4091C14.0848 20.4491 14 20.4011 14 20.3234V13" stroke="black"/>
+<path d="M5.5 4H16M5.5 5.5H13M5.5 7H16" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M5 14C5.5 13 6.5 10.8 6.5 10C6.5 9.80787 6.5 9.67917 6.50693 9.58761C6.53261 9.24828 7.08939 9.44697 7.15613 9.78066L7.72828 12.6414C7.76077 12.8039 8 12.7802 8 12.6145V12.6145C8 12.4527 8.23105 12.4243 8.27029 12.5812L8.37515 13.0007C8.41803 13.1722 8.65114 13.1978 8.7302 13.0397L8.90696 12.6861C8.96398 12.5721 9.08054 12.5001 9.20805 12.5001H10.0625" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
+<circle cx="16.5" cy="12.5" r="2.5" stroke="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/check.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/check.svg
new file mode 100644
index 00000000..f812f6ce
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/check.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <rect fill="none" height="24" width="24"/>
+  <path d="M22,5.18L10.59,16.6l-4.24-4.24l1.41-1.41l2.83,2.83l10-10L22,5.18z M19.79,10.22C19.92,10.79,20,11.39,20,12 c0,4.42-3.58,8-8,8s-8-3.58-8-8c0-4.42,3.58-8,8-8c1.58,0,3.04,0.46,4.28,1.25l1.44-1.44C16.1,2.67,14.13,2,12,2C6.48,2,2,6.48,2,12 c0,5.52,4.48,10,10,10s10-4.48,10-10c0-1.19-0.22-2.33-0.6-3.39L19.79,10.22z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/clock.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/clock.svg
new file mode 100644
index 00000000..fd39e6aa
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/clock.svg
@@ -0,0 +1,1 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24" x="0"/></g><g><g><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M12,20c-4.41,0-8-3.59-8-8s3.59-8,8-8s8,3.59,8,8 S16.41,20,12,20z M12.5,7H11v6l5.2,3.2l0.8-1.3l-4.5-2.7V7z"/></g></g></svg>
\ No newline at end of file
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/config.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/config.svg
new file mode 100644
index 00000000..00e39c33
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/config.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.01 4C4.01 2.9 4.9 2 6 2H14L20 8V13H16C13.7909 13 12 14.7909 12 17V22H5.99C4.89 22 4 21.1 4 20L4.01 4ZM13 3.5V9H18.5L13 3.5Z" fill="black"/>
+<path d="M19.975 18.3917C19.9916 18.2667 20 18.1375 20 18C20 17.8667 19.9916 17.7333 19.9708 17.6083L20.8166 16.95C20.8916 16.8917 20.9125 16.7792 20.8666 16.6958L20.0666 15.3125C20.0166 15.2208 19.9125 15.1917 19.8208 15.2208L18.825 15.6208C18.6166 15.4625 18.3958 15.3292 18.15 15.2292L18 14.1708C17.9833 14.0708 17.9 14 17.8 14H16.2C16.1 14 16.0208 14.0708 16.0041 14.1708L15.8541 15.2292C15.6083 15.3292 15.3833 15.4667 15.1791 15.6208L14.1833 15.2208C14.0916 15.1875 13.9875 15.2208 13.9375 15.3125L13.1416 16.6958C13.0916 16.7833 13.1083 16.8917 13.1916 16.95L14.0375 17.6083C14.0166 17.7333 14 17.8708 14 18C14 18.1292 14.0083 18.2667 14.0291 18.3917L13.1833 19.05C13.1083 19.1083 13.0875 19.2208 13.1333 19.3042L13.9333 20.6875C13.9833 20.7792 14.0875 20.8083 14.1791 20.7792L15.175 20.3792C15.3833 20.5375 15.6041 20.6708 15.85 20.7708L16 21.8292C16.0208 21.9292 16.1 22 16.2 22H17.8C17.9 22 17.9833 21.9292 17.9958 21.8292L18.1458 20.7708C18.3916 20.6708 18.6166 20.5375 18.8208 20.3792L19.8166 20.7792C19.9083 20.8125 20.0125 20.7792 20.0625 20.6875L20.8625 19.3042C20.9125 19.2125 20.8916 19.1083 20.8125 19.05L19.975 18.3917ZM17 19.5C16.175 19.5 15.5 18.825 15.5 18C15.5 17.175 16.175 16.5 17 16.5C17.825 16.5 18.5 17.175 18.5 18C18.5 18.825 17.825 19.5 17 19.5Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/dashboard.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/dashboard.svg
new file mode 100644
index 00000000..a57c611a
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/dashboard.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0V0z" fill="none"/>
+  <path d="M4 13h6c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v8c0 .55.45 1 1 1zm0 8h6c.55 0 1-.45 1-1v-4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1zm10 0h6c.55 0 1-.45 1-1v-8c0-.55-.45-1-1-1h-6c-.55 0-1 .45-1 1v8c0 .55.45 1 1 1zM13 4v4c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1h-6c-.55 0-1 .45-1 1z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/date.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/date.svg
new file mode 100644
index 00000000..70f1937f
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/date.svg
@@ -0,0 +1,1 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><rect fill="none" height="24" width="24"/><path d="M5,10h14v2h2V6c0-1.1-0.9-2-2-2h-1V2h-2v2H8V2H6v2H5C3.89,4,3.01,4.9,3.01,6L3,20c0,1.1,0.89,2,2,2h7v-2H5V10z M5,6h14v2H5 V6z M22.84,16.28l-0.71,0.71l-2.12-2.12l0.71-0.71c0.39-0.39,1.02-0.39,1.41,0l0.71,0.71C23.23,15.26,23.23,15.89,22.84,16.28z M19.3,15.58l2.12,2.12l-5.3,5.3H14v-2.12L19.3,15.58z"/></svg>
\ No newline at end of file
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/device-group.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/device-group.svg
new file mode 100644
index 00000000..c6accf4a
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/device-group.svg
@@ -0,0 +1,5 @@
+<svg width="19" height="22" viewBox="0 0 19 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15.503 13L18 15.0683L10.2581 21L2 15.0683L4.31385 13" stroke="black" stroke-linejoin="round"/>
+<path d="M4.1875 8L1 10.6812L10.0312 17L18 10.6812L15.214 8.5625" stroke="black" stroke-linejoin="round"/>
+<path d="M2 7L10.2581 1L18 6.68831L10.2581 13L2 7Z" stroke="black" stroke-linejoin="round"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/device.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/device.svg
new file mode 100644
index 00000000..7ca87160
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/device.svg
@@ -0,0 +1,16 @@
+<svg width="22" height="17" viewBox="0 0 22 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="0.5" y="11.5" width="21" height="4" rx="0.5" stroke="black"/>
+<rect x="11.9167" y="13" width="8.25" height="1" rx="0.5" fill="black"/>
+<ellipse cx="3.20833" cy="13.5" rx="0.458333" ry="0.5" fill="black"/>
+<ellipse cx="5.04159" cy="13.5" rx="0.458333" ry="0.5" fill="black"/>
+<path d="M1.83325 16H7.33325C7.33325 16.2761 7.10939 16.5 6.83325 16.5H2.33325C2.05711 16.5 1.83325 16.2761 1.83325 16Z" fill="black"/>
+<path d="M14.6667 16H20.1667C20.1667 16.2761 19.9429 16.5 19.6667 16.5H15.1667C14.8906 16.5 14.6667 16.2761 14.6667 16Z" fill="black"/>
+<path d="M16.5 1.5C16.5 1.22386 16.7239 1 17 1C17.2761 1 17.5 1.22386 17.5 1.5V11H16.5V1.5Z" fill="black"/>
+<path d="M2.75 10.4583C2.75 10.2052 2.9552 10 3.20833 10C3.46146 10 3.66667 10.2052 3.66667 10.4583V11H2.75V10.4583Z" fill="black"/>
+<path d="M19.7579 5.94714C20.046 5.61175 20.2707 5.21775 20.4192 4.78762C20.5678 4.35749 20.6371 3.89967 20.6235 3.44028C20.6098 2.9809 20.5133 2.52895 20.3395 2.11025C20.1657 1.69154 19.918 1.31428 19.6106 1" stroke="black" stroke-width="0.5"/>
+<path d="M18.931 5.10182C19.1173 4.8849 19.2627 4.63006 19.3587 4.35187C19.4548 4.07367 19.4996 3.77755 19.4908 3.48043C19.482 3.18331 19.4195 2.891 19.3071 2.62019C19.1947 2.34938 19.0345 2.10537 18.8357 1.9021" stroke="black" stroke-width="0.5"/>
+<path d="M18.109 4.26137C18.1942 4.16222 18.2606 4.04574 18.3045 3.91858C18.3484 3.79142 18.3689 3.65607 18.3649 3.52026C18.3608 3.38445 18.3323 3.25084 18.2809 3.12706C18.2295 3.00327 18.1563 2.89174 18.0654 2.79883" stroke="black" stroke-width="0.5"/>
+<path d="M14.1105 5.94714C13.8224 5.61175 13.5977 5.21775 13.4492 4.78762C13.3007 4.35749 13.2313 3.89967 13.2449 3.44028C13.2586 2.9809 13.3551 2.52895 13.5289 2.11025C13.7027 1.69154 13.9504 1.31428 14.2578 1" stroke="black" stroke-width="0.5"/>
+<path d="M14.9374 5.10182C14.7511 4.8849 14.6057 4.63006 14.5097 4.35187C14.4136 4.07367 14.3688 3.77755 14.3776 3.48043C14.3865 3.18331 14.4489 2.891 14.5613 2.62019C14.6737 2.34938 14.8339 2.10537 15.0327 1.9021" stroke="black" stroke-width="0.5"/>
+<path d="M15.7597 4.26137C15.6745 4.16222 15.6081 4.04574 15.5642 3.91858C15.5203 3.79142 15.4997 3.65607 15.5038 3.52026C15.5078 3.38445 15.5364 3.25084 15.5877 3.12706C15.6391 3.00327 15.7123 2.89174 15.8032 2.79883" stroke="black" stroke-width="0.5"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/down-arrow.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/down-arrow.svg
new file mode 100644
index 00000000..ea1feb6d
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/down-arrow.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 24 24" width="16px" fill="#000000">
+  <path d="M24 24H0V0h24v24z" fill="none" opacity=".87"/>
+  <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6-1.41-1.41z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/firmware.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/firmware.svg
new file mode 100644
index 00000000..43d4acfe
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/firmware.svg
@@ -0,0 +1,3 @@
+<svg width="21" height="21" viewBox="0 0 21 21" fill="000000" xmlns="http://www.w3.org/2000/svg">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M7.41055 1.04037C7.42203 0.488219 6.98368 0.0314926 6.43149 0.0202317C5.87937 0.00897067 5.4224 0.447478 5.41098 0.999632L5.36942 3H7.36984L7.41055 1.04037ZM1.20328 4.806L3.00601 4.84344C3.00199 4.89511 2.99997 4.94729 2.99997 5V6.84372L1.16257 6.80557C0.610384 6.7941 0.171907 6.33719 0.183138 5.78503C0.194368 5.23285 0.651156 4.79452 1.20328 4.806ZM1.12235 8.80493L2.99997 8.84372V10.8441L1.08145 10.8045C0.529268 10.7931 0.0907917 10.3362 0.102144 9.78403C0.113436 9.23187 0.570223 8.79352 1.12235 8.80493ZM1.04068 12.8042L2.99997 12.8447V14.8451L0.999788 14.8038C0.447603 14.7924 0.00912669 14.3355 0.0204792 13.7833C0.0317707 13.2311 0.488558 12.7928 1.04068 12.8042ZM5.0206 19.7966L5.05789 18H7.05832L7.02017 19.8373C7.0087 20.3895 6.55179 20.828 5.99961 20.8167C5.44748 20.8055 5.00913 20.3488 5.0206 19.7966ZM9.01987 19.8779L9.05887 18H11.0593L11.0194 19.9186C11.008 20.4708 10.5511 20.9093 9.99887 20.898C9.44675 20.8868 9.00839 20.4301 9.01987 19.8779ZM13.0189 19.9594L13.0596 18H15.06L15.0185 20.0002C15.007 20.5523 14.5501 20.9908 13.9979 20.9796C13.4458 20.9683 13.0074 20.5116 13.0189 19.9594ZM19.7966 15.1923L18 15.1551V13.1547L19.8376 13.1927C20.3897 13.2041 20.8282 13.661 20.8169 14.2131C20.8056 14.7653 20.3488 15.2037 19.7966 15.1923ZM19.8783 11.193L18 11.1542V9.15375L19.9192 9.19342C20.4714 9.20483 20.9098 9.66171 20.8985 10.2139C20.8872 10.7661 20.4305 11.2044 19.8783 11.193ZM19.9594 7.19592L18 7.15524V5.15481L20.0002 5.19635C20.5523 5.20782 20.9908 5.66473 20.9795 6.21689C20.9683 6.76907 20.5116 7.2074 19.9594 7.19592ZM15.4088 1.20322L15.3715 3H13.3711L13.4093 1.16247C13.4207 0.61032 13.8777 0.171812 14.4298 0.183073C14.982 0.194334 15.4203 0.651061 15.4088 1.20322ZM11.4098 1.12167L11.3708 3H9.37039L9.41025 1.08093C9.42166 0.528777 9.87863 0.0902695 10.4308 0.10153C10.9829 0.112791 11.4213 0.569518 11.4098 1.12167ZM4.99997 4C4.44766 4 3.99997 4.44772 3.99997 5V16C3.99997 16.5523 4.44766 17 4.99997 17H16C16.5523 17 17 16.5523 17 16V5C17 4.44772 16.5523 4 16 4H4.99997Z" fill="#C4C4C4"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/floor.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/floor.svg
new file mode 100644
index 00000000..e4bdca54
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/floor.svg
@@ -0,0 +1,6 @@
+<svg width="23" height="22" viewBox="0 0 23 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6 21H22V1H1V21H3" stroke="black"/>
+<path d="M2.5 19V21M6.5 19V21" stroke="black"/>
+<path d="M11 1V15M11 21V17M1 10.5H3M22 10.5H17M18 1.5V5H21.5M15 10.5H5" stroke="black"/>
+<path d="M12.5 10.5C12.5 11.3284 11.8284 12 11 12C10.1716 12 9.5 11.3284 9.5 10.5C9.5 9.67157 10.1716 9 11 9C11.8284 9 12.5 9.67157 12.5 10.5Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/geo-info.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/geo-info.svg
new file mode 100644
index 00000000..8d6823f2
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/geo-info.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM11 19.93C7.05 19.44 4 16.08 4 12C4 11.38 4.08 10.79 4.21 10.21L9 15V16C9 17.1 9.9 18 11 18V19.93ZM17.9 17.39C17.64 16.58 16.9 16 16 16H15V13C15 12.45 14.55 12 14 12H8V10H10C10.55 10 11 9.55 11 9V7H13C14.1 7 15 6.1 15 5V4.59C17.93 5.78 20 8.65 20 12C20 14.08 19.2 15.97 17.9 17.39Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/hamburger.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/hamburger.svg
new file mode 100644
index 00000000..8dbe30ee
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/hamburger.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#777">
+  <path d="M0 0h24v24H0V0z" fill="none"/>
+  <path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/ip-address.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/ip-address.svg
new file mode 100644
index 00000000..bc98b5a0
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/ip-address.svg
@@ -0,0 +1,3 @@
+<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path d="M7.5 0C3.36 0 0 3.36 0 7.5C0 11.64 3.36 15 7.5 15H11.25V13.5H7.5C4.245 13.5 1.5 10.755 1.5 7.5C1.5 4.245 4.245 1.5 7.5 1.5C10.755 1.5 13.5 4.245 13.5 7.5V8.5725C13.5 9.165 12.9675 9.75 12.375 9.75C11.7825 9.75 11.25 9.165 11.25 8.5725V7.5C11.25 5.43 9.57 3.75 7.5 3.75C5.43 3.75 3.75 5.43 3.75 7.5C3.75 9.57 5.43 11.25 7.5 11.25C8.535 11.25 9.48 10.83 10.155 10.1475C10.6425 10.815 11.4825 11.25 12.375 11.25C13.8525 11.25 15 10.05 15 8.5725V7.5C15 3.36 11.64 0 7.5 0ZM7.5 9.75C6.255 9.75 5.25 8.745 5.25 7.5C5.25 6.255 6.255 5.25 7.5 5.25C8.745 5.25 9.75 6.255 9.75 7.5C9.75 8.745 8.745 9.75 7.5 9.75Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/ipam.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/ipam.svg
new file mode 100644
index 00000000..681f3cb1
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/ipam.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M4 10.2C4 5.22 7.8 2 12 2C16.2 2 20 5.22 20 10.2C20 13.52 17.33 17.45 12 22C6.67 17.45 4 13.52 4 10.2ZM12 15C14.7614 15 17 12.7614 17 10C17 7.23858 14.7614 5 12 5C9.23858 5 7 7.23858 7 10C7 12.7614 9.23858 15 12 15Z" fill="black"/>
+  <path d="M10.5347 13H9.50928V8.02344H10.5347V13ZM12.5137 11.2466V13H11.4883V8.02344H13.4297C13.8034 8.02344 14.1315 8.0918 14.4141 8.22852C14.6989 8.36523 14.9176 8.56006 15.0703 8.81299C15.223 9.06364 15.2993 9.34961 15.2993 9.6709C15.2993 10.1585 15.1318 10.5436 14.7969 10.8262C14.4642 11.1064 14.0028 11.2466 13.4126 11.2466H12.5137ZM12.5137 10.416H13.4297C13.7008 10.416 13.9071 10.3522 14.0483 10.2246C14.1919 10.097 14.2637 9.91471 14.2637 9.67773C14.2637 9.43392 14.1919 9.23682 14.0483 9.08643C13.9048 8.93604 13.7065 8.85856 13.4536 8.854H12.5137V10.416Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/left-arrow.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/left-arrow.svg
new file mode 100644
index 00000000..48fab52b
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/left-arrow.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0V0z" fill="none"/>
+  <path d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/location.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/location.svg
new file mode 100644
index 00000000..3b245cbd
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/location.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12 2C8.13 2 5 5.13 5 9C5 14.25 12 22 12 22C12 22 19 14.25 19 9C19 5.13 15.87 2 12 2ZM7 9C7 6.24 9.24 4 12 4C14.76 4 17 6.24 17 9C17 11.88 14.12 16.19 12 18.88C9.92 16.21 7 11.85 7 9Z" fill="black"/>
+<path d="M12 11.5C13.3807 11.5 14.5 10.3807 14.5 9C14.5 7.61929 13.3807 6.5 12 6.5C10.6193 6.5 9.5 7.61929 9.5 9C9.5 10.3807 10.6193 11.5 12 11.5Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/log.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/log.svg
new file mode 100644
index 00000000..e796f8f7
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/log.svg
@@ -0,0 +1,5 @@
+<svg width="17" height="22" viewBox="0 0 17 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14 21H2C1.44772 21 1 20.5523 1 20V2C1 1.44772 1.44772 1 2 1H13C13.5523 1 14 1.44772 14 2V12" stroke="black" stroke-linecap="round"/>
+<path d="M4 5H11.5M4 7.5H11.5M4 10H11.5" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7.504 18V13.289C7.504 13.2143 7.51567 13.1653 7.539 13.142C7.567 13.114 7.61833 13.1 7.693 13.1H8.064V17.594H9.541V17.811C9.541 17.8857 9.527 17.937 9.499 17.965C9.47567 17.9883 9.42667 18 9.352 18H7.504ZM10.7639 17.195C10.7639 17.3397 10.7825 17.4423 10.8199 17.503C10.8572 17.5637 10.9482 17.594 11.0929 17.594H11.7229C11.8675 17.594 11.9585 17.5637 11.9959 17.503C12.0332 17.4423 12.0519 17.3397 12.0519 17.195V13.905C12.0519 13.7603 12.0332 13.6577 11.9959 13.597C11.9585 13.5363 11.8675 13.506 11.7229 13.506H11.0929C10.9482 13.506 10.8572 13.5363 10.8199 13.597C10.7825 13.6577 10.7639 13.7603 10.7639 13.905V17.195ZM10.2039 13.765C10.2039 13.5223 10.2529 13.352 10.3509 13.254C10.4535 13.1513 10.6262 13.1 10.8689 13.1H11.9469C12.1895 13.1 12.3599 13.1513 12.4579 13.254C12.5605 13.352 12.6119 13.5223 12.6119 13.765V17.335C12.6119 17.5777 12.5605 17.7503 12.4579 17.853C12.3599 17.951 12.1895 18 11.9469 18H10.8689C10.6262 18 10.4535 17.951 10.3509 17.853C10.2529 17.7503 10.2039 17.5777 10.2039 17.335V13.765ZM14.2595 18C14.0168 18 13.8442 17.951 13.7415 17.853C13.6435 17.7503 13.5945 17.5777 13.5945 17.335V13.765C13.5945 13.5223 13.6435 13.352 13.7415 13.254C13.8442 13.1513 14.0168 13.1 14.2595 13.1H15.6245C15.6992 13.1 15.7458 13.114 15.7645 13.142C15.7878 13.1653 15.7995 13.2143 15.7995 13.289V13.506H14.4835C14.3388 13.506 14.2478 13.5363 14.2105 13.597C14.1732 13.6577 14.1545 13.7603 14.1545 13.905V17.195C14.1545 17.3397 14.1732 17.4423 14.2105 17.503C14.2478 17.5637 14.3388 17.594 14.4835 17.594H15.0435C15.1882 17.594 15.2792 17.5637 15.3165 17.503C15.3538 17.4423 15.3725 17.3397 15.3725 17.195V15.662H14.7705V15.445C14.7705 15.3703 14.7822 15.3213 14.8055 15.298C14.8335 15.27 14.8848 15.256 14.9595 15.256H15.9325V17.335C15.9325 17.5777 15.8812 17.7503 15.7785 17.853C15.6758 17.951 15.5032 18 15.2605 18H14.2595Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/logout.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/logout.svg
new file mode 100644
index 00000000..a84ce000
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/logout.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0z" fill="none"/>
+  <path d="M17 7l-1.41 1.41L18.17 11H8v2h10.17l-2.58 2.58L17 17l5-5zM4 5h8V3H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h8v-2H4V5z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/mass-upgrade.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/mass-upgrade.svg
new file mode 100644
index 00000000..2a07dfce
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/mass-upgrade.svg
@@ -0,0 +1,3 @@
+<svg width="19" height="23" viewBox="0 0 19 23" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M6 1H17.5V18.5H18.5V0.5V0H18H6V1ZM10.1709 10.8165C9.47683 10.0726 8.53331 9.61014 7.52019 9.5173C6.50706 9.42445 5.4952 9.7077 4.67753 10.313C3.85985 10.9184 3.29355 11.8035 3.08661 12.7996C2.91377 13.6316 3.0017 14.4923 3.33186 15.2667L3.48779 15.1507L3.66548 16.6478L2.33124 16.0109L2.51111 15.8771C2.02066 14.861 1.87656 13.7078 2.10752 12.5962C2.36442 11.3596 3.06743 10.2608 4.08251 9.50933C5.09759 8.75784 6.35374 8.40621 7.61145 8.52147C8.86916 8.63673 10.0405 9.21083 10.902 10.1343L10.1709 10.8165ZM9.09569 13.6483C9.09569 13.7342 9.09033 13.815 9.07963 13.8931L9.61775 14.3045C9.66862 14.341 9.682 14.4061 9.64988 14.4634L9.13585 15.328C9.10372 15.3853 9.03679 15.4061 8.97789 15.3853L8.33803 15.1353C8.20685 15.2342 8.06228 15.3176 7.90432 15.3801L7.80794 16.0415C7.79991 16.104 7.74636 16.1483 7.68211 16.1483H6.65405C6.5898 16.1483 6.53893 16.104 6.52555 16.0415L6.42916 15.3801C6.27121 15.3176 6.12931 15.2342 5.99545 15.1353L5.35559 15.3853C5.2967 15.4035 5.22976 15.3853 5.19764 15.328L4.68361 14.4634C4.65416 14.4113 4.66755 14.341 4.71574 14.3045L5.25921 13.8931C5.24583 13.815 5.24047 13.729 5.24047 13.6483C5.24047 13.5676 5.25118 13.4816 5.26457 13.4035L4.72109 12.992C4.66755 12.9556 4.65684 12.8879 4.68896 12.8332L5.20031 11.9686C5.23244 11.9113 5.29937 11.8905 5.35827 11.9113L5.99813 12.1613C6.12931 12.065 6.27389 11.979 6.43184 11.9165L6.52822 11.2551C6.53893 11.1926 6.5898 11.1483 6.65405 11.1483H7.68211C7.74636 11.1483 7.79991 11.1926 7.81062 11.2551L7.907 11.9165C8.06495 11.979 8.20685 12.0624 8.34071 12.1613L8.98057 11.9113C9.03947 11.8931 9.1064 11.9113 9.13853 11.9686L9.65255 12.8332C9.682 12.8853 9.66862 12.9556 9.62043 12.992L9.07695 13.4035C9.09033 13.4816 9.09569 13.565 9.09569 13.6483ZM6.20428 13.6483C6.20428 14.1639 6.63799 14.5858 7.16808 14.5858C7.69817 14.5858 8.13188 14.1639 8.13188 13.6483C8.13188 13.1327 7.69817 12.7108 7.16808 12.7108C6.63799 12.7108 6.20428 13.1327 6.20428 13.6483ZM6.82806 17.7724C5.81362 17.6953 4.86305 17.2475 4.15758 16.5144L3.43705 17.2079C4.31283 18.1179 5.4929 18.6738 6.75224 18.7695C8.01159 18.8653 9.26214 18.4942 10.2655 17.7271C11.2688 16.9599 11.9547 15.8504 12.1924 14.61C12.3976 13.5389 12.2563 12.435 11.7963 11.4558L11.9768 11.3312L10.6655 10.6483L10.791 12.1506L10.9594 12.0342C11.2752 12.7839 11.365 13.6144 11.2102 14.4218C11.0188 15.421 10.4663 16.3147 9.65805 16.9327C8.84986 17.5506 7.84251 17.8495 6.82806 17.7724ZM15.5 3H4V2H16H16.5V2.5V20.5H15.5V3ZM1 5.5H13V21.5H1V5.5ZM0 4.5H1H13H14V5.5V21.5V22.5H13H1H0V21.5V5.5V4.5Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/menu.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/menu.svg
deleted file mode 100644
index 4443c7a2..00000000
--- a/openwisp_utils/admin_theme/static/ui/openwisp/images/menu.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 width="640px" height="640px" viewBox="0 0 640 640" enable-background="new 0 0 640 640" xml:space="preserve">
-<line fill="none" stroke="#FFFFFF" stroke-width="90" stroke-linecap="round" stroke-miterlimit="10" x1="118" y1="130" x2="522" y2="130"/>
-<line fill="none" stroke="#FFFFFF" stroke-width="90" stroke-linecap="round" stroke-miterlimit="10" x1="118" y1="320" x2="522" y2="320"/>
-<line fill="none" stroke="#FFFFFF" stroke-width="90" stroke-linecap="round" stroke-miterlimit="10" x1="118" y1="510" x2="522" y2="510"/>
-</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/metrics.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/metrics.svg
new file mode 100644
index 00000000..efc6a32f
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/metrics.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="19" viewBox="0 0 20 19" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19 1H1V18H19V1ZM1 0C0.447715 0 0 0.447715 0 1V18C0 18.5523 0.447715 19 1 19H19C19.5523 19 20 18.5523 20 18V1C20 0.447715 19.5523 0 19 0H1ZM14.5 16.5C16.1569 16.5 17.5 15.1569 17.5 13.5C17.5 11.9273 16.2899 10.6373 14.75 10.5103V13V13.0669C14.8994 13.1533 15 13.3149 15 13.5C15 13.7761 14.7761 14 14.5 14C14.4709 14 14.4425 13.9975 14.4148 13.9928L12.778 15.9569C13.2654 16.2991 13.8592 16.5 14.5 16.5ZM11.5 13.5C11.5 11.9273 12.7101 10.6373 14.25 10.5103V13V13.0669C14.1005 13.1534 14 13.3149 14 13.5C14 13.5607 14.0108 13.6189 14.0306 13.6727L12.3941 15.6366C11.8421 15.0925 11.5 14.3362 11.5 13.5ZM14.5 17C16.433 17 18 15.433 18 13.5C18 11.567 16.433 10 14.5 10C12.567 10 11 11.567 11 13.5C11 15.433 12.567 17 14.5 17ZM14.7 13.5C14.7 13.6105 14.6105 13.7 14.5 13.7C14.3895 13.7 14.3 13.6105 14.3 13.5C14.3 13.3895 14.3895 13.3 14.5 13.3C14.6105 13.3 14.7 13.3895 14.7 13.5ZM2.75 2C2.75 1.86193 2.63807 1.75 2.5 1.75C2.36193 1.75 2.25 1.86193 2.25 2V9C2.25 9.13807 2.36193 9.25 2.5 9.25H15C15.1381 9.25 15.25 9.13807 15.25 9C15.25 8.86193 15.1381 8.75 15 8.75H2.75V2ZM10.75 2.5C10.75 2.36193 10.6381 2.25 10.5 2.25C10.3619 2.25 10.25 2.36193 10.25 2.5V8C10.25 8.13807 10.3619 8.25 10.5 8.25C10.6381 8.25 10.75 8.13807 10.75 8V2.5ZM6.25 3C6.25 2.86193 6.13807 2.75 6 2.75C5.86193 2.75 5.75 2.86193 5.75 3V8C5.75 8.13807 5.86193 8.25 6 8.25C6.13807 8.25 6.25 8.13807 6.25 8V3ZM4.75 4C4.75 3.86193 4.63807 3.75 4.5 3.75C4.36193 3.75 4.25 3.86193 4.25 4V8C4.25 8.13807 4.36193 8.25 4.5 8.25C4.63807 8.25 4.75 8.13807 4.75 8V4ZM9.25 4C9.25 3.86193 9.13807 3.75 9 3.75C8.86193 3.75 8.75 3.86193 8.75 4V8C8.75 8.13807 8.86193 8.25 9 8.25C9.13807 8.25 9.25 8.13807 9.25 8V4ZM7.75 5C7.75 4.86193 7.63807 4.75 7.5 4.75C7.36193 4.75 7.25 4.86193 7.25 5V8C7.25 8.13807 7.36193 8.25 7.5 8.25C7.63807 8.25 7.75 8.13807 7.75 8V5ZM12.25 5.5C12.25 5.36193 12.1381 5.25 12 5.25C11.8619 5.25 11.75 5.36193 11.75 5.5V8C11.75 8.13807 11.8619 8.25 12 8.25C12.1381 8.25 12.25 8.13807 12.25 8V5.5ZM13.75 6.5C13.75 6.36193 13.6381 6.25 13.5 6.25C13.3619 6.25 13.25 6.36193 13.25 6.5V8C13.25 8.13807 13.3619 8.25 13.5 8.25C13.6381 8.25 13.75 8.13807 13.75 8V6.5ZM2.5 11.75C2.36193 11.75 2.25 11.8619 2.25 12C2.25 12.1381 2.36193 12.25 2.5 12.25H8C8.13807 12.25 8.25 12.1381 8.25 12C8.25 11.8619 8.13807 11.75 8 11.75H2.5ZM2.5 13.25C2.36193 13.25 2.25 13.3619 2.25 13.5C2.25 13.6381 2.36193 13.75 2.5 13.75H5C5.13807 13.75 5.25 13.6381 5.25 13.5C5.25 13.3619 5.13807 13.25 5 13.25H2.5ZM2.5 14.75C2.36193 14.75 2.25 14.8619 2.25 15C2.25 15.1381 2.36193 15.25 2.5 15.25H6.5C6.63807 15.25 6.75 15.1381 6.75 15C6.75 14.8619 6.63807 14.75 6.5 14.75H2.5Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/monitoring.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/monitoring.svg
new file mode 100644
index 00000000..6a852010
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/monitoring.svg
@@ -0,0 +1,3 @@
+<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1H19C19.5523 1 20 1.44772 20 2V17.5C20 18.0523 19.5523 18.5 19 18.5H2C1.44772 18.5 1 18.0523 1 17.5V2C1 1.44772 1.44772 1 2 1ZM0 2C0 0.89543 0.895431 0 2 0H19C20.1046 0 21 0.895431 21 2V17.5C21 18.6046 20.1046 19.5 19 19.5H2C0.89543 19.5 0 18.6046 0 17.5V2ZM3.7 11.5C3.58954 11.5 3.5 11.5895 3.5 11.7V16.3C3.5 16.4105 3.58954 16.5 3.7 16.5H5.3C5.41046 16.5 5.5 16.4105 5.5 16.3V11.7C5.5 11.5895 5.41046 11.5 5.3 11.5H3.7ZM15.5 5.7C15.5 5.58954 15.5895 5.5 15.7 5.5H17.3C17.4105 5.5 17.5 5.58954 17.5 5.7V16.3C17.5 16.4105 17.4105 16.5 17.3 16.5H15.7C15.5895 16.5 15.5 16.4105 15.5 16.3V5.7ZM11.7 9.5C11.5895 9.5 11.5 9.58954 11.5 9.7V16.3C11.5 16.4105 11.5895 16.5 11.7 16.5H13.3C13.4105 16.5 13.5 16.4105 13.5 16.3V9.7C13.5 9.58954 13.4105 9.5 13.3 9.5H11.7ZM7.5 8.7C7.5 8.58954 7.58954 8.5 7.7 8.5H9.3C9.41046 8.5 9.5 8.58954 9.5 8.7V16.3C9.5 16.4105 9.41046 16.5 9.3 16.5H7.7C7.58954 16.5 7.5 16.4105 7.5 16.3V8.7ZM4.5 10.6338C5.05228 10.6338 5.5 10.1861 5.5 9.63378C5.5 9.41372 5.42891 9.21025 5.30845 9.0451L7.91132 6.44223C8.07647 6.56269 8.27994 6.63378 8.5 6.63378C8.84478 6.63378 9.14881 6.45929 9.32859 6.1938L11.5036 7.28129C11.5012 7.30928 11.5 7.3376 11.5 7.3662C11.5 7.91849 11.9477 8.3662 12.5 8.3662C13.0523 8.3662 13.5 7.91849 13.5 7.3662C13.5 7.21608 13.4669 7.07368 13.4076 6.9459L15.9113 4.44223C16.0765 4.56269 16.2799 4.63378 16.5 4.63378C17.0523 4.63378 17.5 4.18606 17.5 3.63378C17.5 3.08149 17.0523 2.63378 16.5 2.63378C15.9477 2.63378 15.5 3.08149 15.5 3.63378C15.5 3.7839 15.5331 3.92631 15.5924 4.05409L13.0887 6.55776C12.9235 6.43729 12.7201 6.3662 12.5 6.3662C12.1552 6.3662 11.8512 6.5407 11.6714 6.80619L9.49644 5.71871C9.4988 5.69071 9.5 5.66238 9.5 5.63378C9.5 5.08149 9.05229 4.63378 8.5 4.63378C7.94772 4.63378 7.5 5.08149 7.5 5.63378C7.5 5.7839 7.53308 5.92631 7.59236 6.05409L4.92031 8.72614C4.79253 8.66687 4.65013 8.63378 4.5 8.63378C3.94772 8.63378 3.5 9.0815 3.5 9.63378C3.5 10.1861 3.94772 10.6338 4.5 10.6338Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/montoring-checks.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/montoring-checks.svg
new file mode 100644
index 00000000..160ac894
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/montoring-checks.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="19" viewBox="0 0 20 19" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1 1H19V18H1V1ZM0 1C0 0.447715 0.447715 0 1 0H19C19.5523 0 20 0.447715 20 1V18C20 18.5523 19.5523 19 19 19H1C0.447715 19 0 18.5523 0 18V1ZM13.2334 11.9542C13.6796 11.9923 14.102 12.1716 14.4394 12.466L14.7681 12.0892C14.3506 11.725 13.828 11.5032 13.2759 11.456C12.7239 11.4089 12.1712 11.5388 11.698 11.8269C11.2248 12.1151 10.8556 12.5464 10.6441 13.0585C10.4325 13.5706 10.3896 14.1367 10.5215 14.6748C10.6534 15.2129 10.9533 15.6951 11.3777 16.0513C11.802 16.4075 12.3288 16.6192 12.8816 16.6558C13.4345 16.6925 13.9846 16.5521 14.4523 16.255C14.9199 15.9579 15.2808 15.5195 15.4825 15.0035L15.0168 14.8215C14.8538 15.2385 14.5621 15.5928 14.1841 15.8329C13.8062 16.0731 13.3615 16.1865 12.9147 16.1569C12.4679 16.1273 12.0421 15.9562 11.6991 15.6683C11.3561 15.3804 11.1137 14.9907 11.0071 14.5558C10.9005 14.1209 10.9352 13.6633 11.1062 13.2494C11.2772 12.8355 11.5755 12.4869 11.958 12.254C12.3405 12.0211 12.7872 11.9161 13.2334 11.9542ZM2.5 1.75C2.63807 1.75 2.75 1.86193 2.75 2V8.75H15C15.1381 8.75 15.25 8.86193 15.25 9C15.25 9.13807 15.1381 9.25 15 9.25H2.5C2.36193 9.25 2.25 9.13807 2.25 9V2C2.25 1.86193 2.36193 1.75 2.5 1.75ZM10.5 2.25C10.6381 2.25 10.75 2.36193 10.75 2.5V8C10.75 8.13807 10.6381 8.25 10.5 8.25C10.3619 8.25 10.25 8.13807 10.25 8V2.5C10.25 2.36193 10.3619 2.25 10.5 2.25ZM6 2.75C6.13807 2.75 6.25 2.86193 6.25 3V8C6.25 8.13807 6.13807 8.25 6 8.25C5.86193 8.25 5.75 8.13807 5.75 8V3C5.75 2.86193 5.86193 2.75 6 2.75ZM4.5 3.75C4.63807 3.75 4.75 3.86193 4.75 4V8C4.75 8.13807 4.63807 8.25 4.5 8.25C4.36193 8.25 4.25 8.13807 4.25 8V4C4.25 3.86193 4.36193 3.75 4.5 3.75ZM9 3.75C9.13807 3.75 9.25 3.86193 9.25 4V8C9.25 8.13807 9.13807 8.25 9 8.25C8.86193 8.25 8.75 8.13807 8.75 8V4C8.75 3.86193 8.86193 3.75 9 3.75ZM7.5 4.75C7.63807 4.75 7.75 4.86193 7.75 5V8C7.75 8.13807 7.63807 8.25 7.5 8.25C7.36193 8.25 7.25 8.13807 7.25 8V5C7.25 4.86193 7.36193 4.75 7.5 4.75ZM12 5.25C12.1381 5.25 12.25 5.36193 12.25 5.5V8C12.25 8.13807 12.1381 8.25 12 8.25C11.8619 8.25 11.75 8.13807 11.75 8V5.5C11.75 5.36193 11.8619 5.25 12 5.25ZM13.5 6.25C13.6381 6.25 13.75 6.36193 13.75 6.5V8C13.75 8.13807 13.6381 8.25 13.5 8.25C13.3619 8.25 13.25 8.13807 13.25 8V6.5C13.25 6.36193 13.3619 6.25 13.5 6.25ZM17.124 12.7171C17.2439 12.6486 17.2856 12.4958 17.2171 12.376C17.1486 12.2561 16.9958 12.2144 16.876 12.2829L13.5418 14.1882L12.6768 13.3232C12.5791 13.2256 12.4209 13.2256 12.3232 13.3232C12.2256 13.4209 12.2256 13.5791 12.3232 13.6768L13.3232 14.6768C13.4029 14.7565 13.5262 14.773 13.624 14.7171L17.124 12.7171ZM2.5 11.2C2.5 11.0895 2.58954 11 2.7 11H4.3C4.41046 11 4.5 11.0895 4.5 11.2V12.8C4.5 12.9105 4.41046 13 4.3 13H2.7C2.58954 13 2.5 12.9105 2.5 12.8V11.2ZM2.7 14C2.58954 14 2.5 14.0895 2.5 14.2V15.8C2.5 15.9105 2.58954 16 2.7 16H4.3C4.41046 16 4.5 15.9105 4.5 15.8V14.2C4.5 14.0895 4.41046 14 4.3 14H2.7ZM9.21437 10.8714C9.28541 10.9898 9.24702 11.1433 9.12862 11.2144L6.62862 12.7144C6.56891 12.7502 6.49696 12.7595 6.4301 12.74C6.36324 12.7206 6.30754 12.6741 6.27639 12.6118L5.77639 11.6118C5.71465 11.4883 5.7647 11.3381 5.8882 11.2764C6.01169 11.2146 6.16186 11.2647 6.22361 11.3882L6.60287 12.1467L8.87138 10.7856C8.98977 10.7146 9.14334 10.753 9.21437 10.8714ZM9.12862 14.2144C9.24702 14.1433 9.28541 13.9898 9.21437 13.8714C9.14334 13.753 8.98977 13.7146 8.87138 13.7856L6.60287 15.1467L6.22361 14.3882C6.16186 14.2647 6.01169 14.2146 5.8882 14.2764C5.7647 14.3381 5.71465 14.4883 5.77639 14.6118L6.27639 15.6118C6.30754 15.6741 6.36324 15.7206 6.4301 15.74C6.49696 15.7595 6.56891 15.7502 6.62862 15.7144L9.12862 14.2144Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/nas.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/nas.svg
new file mode 100644
index 00000000..fead6208
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/nas.svg
@@ -0,0 +1,7 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path d="M2 8.5C1.2 8.5 0.333333 9.5 0 10C0.5 7.66667 1.6 2.7 2 1.5C2.5 0 3.5 0 4 0H20C21 0 21.5 0 22 1.5L24 10C23.6 8.8 22 8.5 22 8.5H2Z" fill="black"/>
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M2 10C0.895416 10 0 10.8954 0 12V22C0 23.1046 0.895416 24 2 24H22C23.1046 24 24 23.1046 24 22V12C24 10.8954 23.1046 10 22 10H2ZM4 14.5C4.55228 14.5 5 14.0523 5 13.5C5 12.9477 4.55228 12.5 4 12.5C3.44772 12.5 3 12.9477 3 13.5C3 14.0523 3.44772 14.5 4 14.5ZM5 16C5 16.5523 4.55228 17 4 17C3.44772 17 3 16.5523 3 16C3 15.4477 3.44772 15 4 15C4.55228 15 5 15.4477 5 16ZM12 12C10.8954 12 10 12.8954 10 14V19C10 20.1046 10.8954 21 12 21H20C21.1046 21 22 20.1046 22 19V14C22 12.8954 21.1046 12 20 12H12Z" fill="black"/>
+  <rect x="12" y="13" width="2" height="7" rx="1" fill="black"/>
+  <rect x="15" y="13" width="2" height="7" rx="1" fill="black"/>
+  <rect x="18" y="13" width="2" height="7" rx="1" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo-black.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo-black.svg
new file mode 100644
index 00000000..e85636c9
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo-black.svg
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   viewBox="0 0 834.01251 482.63751"
+   height="482.63751"
+   width="834.01251"
+   xml:space="preserve"
+   version="1.1"
+   id="svg4155"><metadata
+     id="metadata4161"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+     id="defs4159"><clipPath
+       id="clipPath4171"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path4173"
+         d="M 5806.68,3511.64 C 5449.15,3664.07 4745.83,2493.09 4416.4,1478.31 c 0,0 -104.22,263.26 -114.1,571.55 -5.81,179.13 42.8,124.58 62.67,112.62 l 7.15,53.36 -94.23,13.42 0,0.07 -97.47,11.35 -6.92,-53.43 c 22.34,6.58 83.21,46.91 31.88,-124.85 -88.35,-295.48 -256.35,-523.49 -256.35,-523.49 -59.34,1065.22 -440.17,2376.71 -824.86,2320.43 -137.11,-20.05 -631.33,-304.87 -364.82,-855.17 -0.1,-0.06 -0.23,-0.29 -0.28,-0.47 3.74,-7.81 8.1,-15.75 12.24,-23.66 2.92,-5.58 5.48,-10.91 8.49,-16.49 9.72,-18 20.37,-36.14 31.79,-54.66 3.33,-5.39 6.96,-10.99 10.65,-16.38 9.22,-14.73 19.33,-29.56 29.81,-44.58 4.04,-5.62 7.91,-11.44 12.09,-17.17 14.12,-19.49 29.13,-39.27 45.09,-59.19 3.15,-3.98 6.65,-7.96 9.94,-11.95 13.89,-16.82 28.5,-33.95 43.83,-51.3 5.3,-5.92 10.61,-11.92 16.09,-17.91 19.21,-21 39.07,-42.38 60.51,-63.82 20.1,-20.21 38.13,-39.23 57.19,-58.87 -0.32,0.38 -0.58,0.69 -0.9,1.08 -567.66,669.28 -212.55,993.27 -96.07,1065.38 327.38,202.3 911.72,-1687.94 907.85,-2234.81 127.41,144.03 243.4,313.97 331.69,545.14 26.3,-246.1 94.95,-439.95 181.31,-611.77 136.03,529.59 1183.75,2208.46 1448.63,1929.46 94.23,-99.4 354.26,-502.63 -363.51,-1004.42 22.11,13.33 44.55,26.68 67.65,40.22 26.21,15.44 50.72,30.84 74.73,46.35 6.87,4.47 13.52,8.83 20.26,13.24 19.25,12.9 37.73,25.64 55.35,38.39 4.18,3.04 8.54,5.98 12.63,9.06 20.67,15.22 40.19,30.48 58.85,45.68 5.54,4.49 10.6,9.08 16.09,13.48 13.95,11.89 27.47,23.74 40.29,35.47 4.76,4.43 9.79,8.86 14.33,13.2 15.79,14.95 30.75,29.8 44.78,44.78 4.27,4.6 8.09,9.12 12.41,13.82 5.94,6.48 12.27,13.15 17.94,19.78 -0.09,0.11 -0.23,0.38 -0.23,0.56 398.36,463.95 -6.82,865.46 -134.19,919.83 z" /></clipPath><radialGradient
+       id="radialGradient4175"
+       spreadMethod="pad"
+       gradientTransform="matrix(196.157,2248.14,2248.14,-196.157,4274.47,2111.59)"
+       gradientUnits="userSpaceOnUse"
+       r="1"
+       cy="0"
+       cx="0"
+       fy="0"
+       fx="0"><stop
+         id="stop4177"
+         offset="0"
+         style="stop-opacity:1;stop-color:#161315" /><stop
+         id="stop4179"
+         offset="0.674286"
+         style="stop-opacity:1;stop-color:#161315" /><stop
+         id="stop4181"
+         offset="0.91399019"
+         style="stop-opacity:1;stop-color:#161315" /><stop
+         id="stop4183"
+         offset="1"
+         style="stop-opacity:1;stop-color:#e0e0e1" /></radialGradient><clipPath
+       id="clipPath4191"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path4193"
+         d="m 5869.3,3262.2 c -264.88,279 -1312.6,-1399.87 -1448.63,-1929.46 4.76,-9.44 9.53,-19.07 14.38,-28.46 12.6,-22.88 32.91,-59.7 59.03,-106.73 C 4674.09,872.648 5127.39,61.6289 5196.8,4.37109 5258.67,-46.6211 4978.22,362.309 5030.5,538.449 c 99.9,-126.469 179.47,-221.508 205.23,-238.41 3.33,-2.109 5.81,-3.23 7.23,-3.457 19.03,-2.57 -120.21,161.168 -173.98,297.16 25.31,17.528 62.35,26.078 114.78,22.028 143.32,-11.188 40.06,31.199 -102.06,135.949 24.34,16.281 63.53,23.742 122.38,18.39 300.4,-27.25 -488.4,159.911 -455.28,565.871 22.62,239.61 215.43,543.88 755.28,920.59 0.53,0.43 1.12,0.81 1.71,1.21 717.77,501.79 457.74,905.02 363.51,1004.42 z m -2869.48,371.98 c -116.48,-72.11 -471.59,-396.1 96.07,-1065.38 0.32,-0.39 0.58,-0.7 0.9,-1.08 425.06,-501.29 533.6,-844.4 494.34,-1081.72 -71.75,-400.88 -882.31,-380.74 -584.88,-430.96 58.09,-9.8 94.22,-27.02 113.47,-48.92 -163.96,-64.96 -274.78,-79.741 -133.25,-105.499 51.79,-9.402 85.28,-27.16 105.24,-50.629 -86.72,-117.601 -263.13,-240.523 -244.07,-242.801 1.4,-0.242 4,0.219 7.74,1.469 29.3,9.809 130.54,81.332 259.39,178.129 5.53,-183.687 -370.03,-507.469 -297.2,-473.937 81.95,37.73 729.73,708.608 986.02,975.828 35.79,37.36 64.02,66.9 81.92,85.64 7.45,8.18 14.79,16.69 22.16,25.05 3.87,546.87 -580.47,2437.11 -907.85,2234.81 z" /></clipPath><radialGradient
+       id="radialGradient4195"
+       spreadMethod="pad"
+       gradientTransform="matrix(1718.42,0,0,-1718.42,4388.12,1824.63)"
+       gradientUnits="userSpaceOnUse"
+       r="1"
+       cy="0"
+       cx="0"
+       fy="0"
+       fx="0"><stop
+         id="stop4197"
+         offset="0"
+         style="stop-opacity:1;stop-color:#fde3c3" /><stop
+         id="stop4199"
+         offset="1"
+         style="stop-opacity:1;stop-color:#f79210" /></radialGradient><clipPath
+       id="clipPath4207"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path4209"
+         d="m 5806.05,2781.78 c -8.81,4.76 -18.43,7.86 -28.96,9.31 -284.8,37.42 -1184.87,-1153.28 -1336.27,-1412.09 -7.48,-15.51 -16.15,-36.1 -20.15,-46.26 28.42,-38.39 375.98,-498.119 609.57,-793.931 6.83,23.023 19.1,41.722 38.66,55.121 -26.57,67.242 -32.15,127.761 12.72,157.89 -156.67,115.52 -360.41,306.99 -332.82,586.49 0.41,4.86 1,9.89 1.67,14.92 30.22,236.79 226.67,535.62 753.61,903.34 1.83,1.15 3.42,2.27 5.12,3.47 204.88,143.74 331.33,281.26 404.65,406.02 -30.07,56.93 -74.58,97.37 -107.8,115.72 z m -2837.39,373.36 c -10.52,1.32 -20.63,0.75 -30.3,-1.55 -36.86,-9.28 -90.36,-36.95 -133.88,-84.43 38.98,-139.25 126.11,-304.58 287.54,-495.78 1.31,-1.6 2.57,-3.08 3.87,-4.58 415.58,-489.92 529.27,-828.94 498.02,-1065.59 -0.71,-5.04 -1.51,-10.07 -2.2,-15.02 -44.81,-277.14 -290.91,-410.27 -471.81,-482.2 35.74,-40.361 14.88,-97.459 -27.96,-155.728 15.37,-17.973 22.47,-39.242 23.28,-63.114 301.48,226.402 755.31,582.272 792.45,612.222 -1.21,10.88 -4.35,32.81 -7.55,49.71 -80.39,288.9 -646.48,1669.53 -931.46,1706.06 z" /></clipPath><radialGradient
+       id="radialGradient4211"
+       spreadMethod="pad"
+       gradientTransform="matrix(2097.01,-325.913,-95.8387,-616.652,4244.08,1881.86)"
+       gradientUnits="userSpaceOnUse"
+       r="1"
+       cy="0"
+       cx="0"
+       fy="0"
+       fx="0"><stop
+         id="stop4213"
+         offset="0"
+         style="stop-opacity:1;stop-color:#f9b2b4" /><stop
+         id="stop4215"
+         offset="0.70487066"
+         style="stop-opacity:1;stop-color:#c4161d" /><stop
+         id="stop4217"
+         offset="1"
+         style="stop-opacity:1;stop-color:#c4161d" /></radialGradient></defs><g
+     transform="matrix(1.25,0,0,-1.25,0,482.6375)"
+     id="g4163"><g
+       transform="scale(0.1,0.1)"
+       id="g4165"><g
+         id="g4167"><g
+           clip-path="url(#clipPath4171)"
+           id="g4169"><path
+             id="path4185"
+             style="fill:url(#radialGradient4175);fill-opacity:1;fill-rule:nonzero;stroke:none"
+             d="M 5806.68,3511.64 C 5449.15,3664.07 4745.83,2493.09 4416.4,1478.31 c 0,0 -104.22,263.26 -114.1,571.55 -5.81,179.13 42.8,124.58 62.67,112.62 l 7.15,53.36 -94.23,13.42 0,0.07 -97.47,11.35 -6.92,-53.43 c 22.34,6.58 83.21,46.91 31.88,-124.85 -88.35,-295.48 -256.35,-523.49 -256.35,-523.49 -59.34,1065.22 -440.17,2376.71 -824.86,2320.43 -137.11,-20.05 -631.33,-304.87 -364.82,-855.17 -0.1,-0.06 -0.23,-0.29 -0.28,-0.47 3.74,-7.81 8.1,-15.75 12.24,-23.66 2.92,-5.58 5.48,-10.91 8.49,-16.49 9.72,-18 20.37,-36.14 31.79,-54.66 3.33,-5.39 6.96,-10.99 10.65,-16.38 9.22,-14.73 19.33,-29.56 29.81,-44.58 4.04,-5.62 7.91,-11.44 12.09,-17.17 14.12,-19.49 29.13,-39.27 45.09,-59.19 3.15,-3.98 6.65,-7.96 9.94,-11.95 13.89,-16.82 28.5,-33.95 43.83,-51.3 5.3,-5.92 10.61,-11.92 16.09,-17.91 19.21,-21 39.07,-42.38 60.51,-63.82 20.1,-20.21 38.13,-39.23 57.19,-58.87 -0.32,0.38 -0.58,0.69 -0.9,1.08 -567.66,669.28 -212.55,993.27 -96.07,1065.38 327.38,202.3 911.72,-1687.94 907.85,-2234.81 127.41,144.03 243.4,313.97 331.69,545.14 26.3,-246.1 94.95,-439.95 181.31,-611.77 136.03,529.59 1183.75,2208.46 1448.63,1929.46 94.23,-99.4 354.26,-502.63 -363.51,-1004.42 22.11,13.33 44.55,26.68 67.65,40.22 26.21,15.44 50.72,30.84 74.73,46.35 6.87,4.47 13.52,8.83 20.26,13.24 19.25,12.9 37.73,25.64 55.35,38.39 4.18,3.04 8.54,5.98 12.63,9.06 20.67,15.22 40.19,30.48 58.85,45.68 5.54,4.49 10.6,9.08 16.09,13.48 13.95,11.89 27.47,23.74 40.29,35.47 4.76,4.43 9.79,8.86 14.33,13.2 15.79,14.95 30.75,29.8 44.78,44.78 4.27,4.6 8.09,9.12 12.41,13.82 5.94,6.48 12.27,13.15 17.94,19.78 -0.09,0.11 -0.23,0.38 -0.23,0.56 398.36,463.95 -6.82,865.46 -134.19,919.83" /></g></g><g
+         id="g4187"><g
+           clip-path="url(#clipPath4191)"
+           id="g4189"><path
+             id="path4201"
+             style="fill:url(#radialGradient4195);fill-opacity:1;fill-rule:nonzero;stroke:none"
+             d="m 5869.3,3262.2 c -264.88,279 -1312.6,-1399.87 -1448.63,-1929.46 4.76,-9.44 9.53,-19.07 14.38,-28.46 12.6,-22.88 32.91,-59.7 59.03,-106.73 C 4674.09,872.648 5127.39,61.6289 5196.8,4.37109 5258.67,-46.6211 4978.22,362.309 5030.5,538.449 c 99.9,-126.469 179.47,-221.508 205.23,-238.41 3.33,-2.109 5.81,-3.23 7.23,-3.457 19.03,-2.57 -120.21,161.168 -173.98,297.16 25.31,17.528 62.35,26.078 114.78,22.028 143.32,-11.188 40.06,31.199 -102.06,135.949 24.34,16.281 63.53,23.742 122.38,18.39 300.4,-27.25 -488.4,159.911 -455.28,565.871 22.62,239.61 215.43,543.88 755.28,920.59 0.53,0.43 1.12,0.81 1.71,1.21 717.77,501.79 457.74,905.02 363.51,1004.42 z m -2869.48,371.98 c -116.48,-72.11 -471.59,-396.1 96.07,-1065.38 0.32,-0.39 0.58,-0.7 0.9,-1.08 425.06,-501.29 533.6,-844.4 494.34,-1081.72 -71.75,-400.88 -882.31,-380.74 -584.88,-430.96 58.09,-9.8 94.22,-27.02 113.47,-48.92 -163.96,-64.96 -274.78,-79.741 -133.25,-105.499 51.79,-9.402 85.28,-27.16 105.24,-50.629 -86.72,-117.601 -263.13,-240.523 -244.07,-242.801 1.4,-0.242 4,0.219 7.74,1.469 29.3,9.809 130.54,81.332 259.39,178.129 5.53,-183.687 -370.03,-507.469 -297.2,-473.937 81.95,37.73 729.73,708.608 986.02,975.828 35.79,37.36 64.02,66.9 81.92,85.64 7.45,8.18 14.79,16.69 22.16,25.05 3.87,546.87 -580.47,2437.11 -907.85,2234.81" /></g></g><g
+         id="g4203"><g
+           clip-path="url(#clipPath4207)"
+           id="g4205"><path
+             id="path4219"
+             style="fill:url(#radialGradient4211);fill-opacity:1;fill-rule:nonzero;stroke:none"
+             d="m 5806.05,2781.78 c -8.81,4.76 -18.43,7.86 -28.96,9.31 -284.8,37.42 -1184.87,-1153.28 -1336.27,-1412.09 -7.48,-15.51 -16.15,-36.1 -20.15,-46.26 28.42,-38.39 375.98,-498.119 609.57,-793.931 6.83,23.023 19.1,41.722 38.66,55.121 -26.57,67.242 -32.15,127.761 12.72,157.89 -156.67,115.52 -360.41,306.99 -332.82,586.49 0.41,4.86 1,9.89 1.67,14.92 30.22,236.79 226.67,535.62 753.61,903.34 1.83,1.15 3.42,2.27 5.12,3.47 204.88,143.74 331.33,281.26 404.65,406.02 -30.07,56.93 -74.58,97.37 -107.8,115.72 z m -2837.39,373.36 c -10.52,1.32 -20.63,0.75 -30.3,-1.55 -36.86,-9.28 -90.36,-36.95 -133.88,-84.43 38.98,-139.25 126.11,-304.58 287.54,-495.78 1.31,-1.6 2.57,-3.08 3.87,-4.58 415.58,-489.92 529.27,-828.94 498.02,-1065.59 -0.71,-5.04 -1.51,-10.07 -2.2,-15.02 -44.81,-277.14 -290.91,-410.27 -471.81,-482.2 35.74,-40.361 14.88,-97.459 -27.96,-155.728 15.37,-17.973 22.47,-39.242 23.28,-63.114 301.48,226.402 755.31,582.272 792.45,612.222 -1.21,10.88 -4.35,32.81 -7.55,49.71 -80.39,288.9 -646.48,1669.53 -931.46,1706.06" /></g></g><path
+         id="path4221"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 3491.42,2798.59 c -20.95,1.6 -38.85,-4.4 -53.95,-18.52 -15.33,-13.82 -23.73,-31 -25.27,-50.73 -1.57,-20.8 4.01,-38.67 16.99,-53.84 12.82,-15.26 29.59,-23.51 50.58,-25.29 19.7,-1.48 36.83,4.12 50.9,17.2 14.2,13.05 21.8,30.03 23.42,50.79 1.53,19.68 -3.28,37.86 -15.2,53.8 -11.74,16.3 -27.73,24.95 -47.47,26.59" /><path
+         id="path4223"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 116.438,1988 c 0.996,-42.55 7.687,-90.36 19.925,-143.48 12.176,-53.18 32.09,-104.43 59.742,-153.85 27.594,-49.44 64.286,-93.05 110.047,-130.73 45.68,-37.76 102.547,-61.94 170.571,-72.56 63.789,-9.53 120.574,-8.53 170.566,3.2 49.945,11.65 93.563,30.79 130.684,57.41 37.269,26.52 68.558,58.17 94.14,94.86 25.45,36.68 46.446,75.17 62.942,115.53 16.453,40.38 28.461,80.79 35.836,121.2 7.453,40.4 11.687,77.06 12.761,110 1.032,81.84 -9.304,153.83 -31.058,216.01 -21.809,62.2 -51.563,114.77 -89.289,157.84 -37.719,43.05 -81.864,76.54 -132.309,100.46 -50.484,23.87 -104.433,38.5 -161.887,43.83 -59.437,0 -116.886,-10.92 -172.089,-32.68 -55.262,-21.81 -103.946,-54.49 -145.836,-98.05 -42.043,-43.59 -75.536,-97.8 -100.481,-162.63 C 125.746,2149.55 114.234,2074.09 116.438,1988 Z M 0,1991.17 c 0,89.27 12.7695,170.32 38.3047,243.12 25.4922,72.82 61.0547,135.24 106.8163,187.34 45.633,52.08 99.895,92.97 162.613,122.76 62.621,29.73 130.684,46.21 204.008,49.4 82.949,6.39 159.961,-3.19 231.211,-28.68 71.211,-25.51 133.117,-64.56 185.715,-117.18 52.645,-52.6 93.782,-117.45 123.592,-194.51 29.71,-77.05 44.59,-163.95 44.59,-260.65 0,-89.29 -13.26,-170.32 -39.82,-243.11 -26.62,-72.82 -63.26,-135.31 -110.018,-187.32 -46.746,-52.11 -102.047,-92.75 -165.84,-121.98 -63.75,-29.27 -132.848,-44.32 -207.207,-45.41 -80.785,-5.3 -155.996,5.04 -225.641,31.03 -69.59,26.07 -130.144,65.41 -181.66,118.05 -51.613,52.6 -92.207,116.62 -121.9726,192.06 C 14.8867,1811.52 0,1896.56 0,1991.17" /><path
+         id="path4225"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 1597.4,2141.04 c -43.57,0 -80.52,-10.66 -110.77,-31.88 -30.26,-21.29 -54.76,-48.37 -73.33,-81.33 -18.61,-32.95 -31.87,-69.34 -39.88,-109.2 -7.95,-39.83 -11.91,-77.89 -11.91,-113.98 0,-36.15 3.69,-73.87 11.11,-113.2 7.46,-39.34 20.5,-75.48 39.02,-108.39 18.65,-32.96 43.11,-60.07 73.41,-81.28 30.26,-21.31 67.71,-31.93 112.35,-31.93 46.8,0 85.33,10.07 115.58,30.31 30.3,20.18 54.5,46.48 72.61,78.94 18.02,32.37 30.48,68.51 37.44,108.39 6.84,39.84 10.3,78.9 10.3,117.16 0,38.25 -3.46,77.32 -10.3,117.18 -6.96,39.87 -19.42,75.99 -37.44,108.41 -18.11,32.41 -42.31,58.98 -72.61,79.7 -30.25,20.73 -68.78,31.1 -115.58,31.1 z m -454.37,-1060.2 c 15.96,2.17 34.02,5.09 54.21,8.77 20.19,3.78 36.19,14.12 47.88,31.11 l 0,1015.55 c -11.69,16.95 -27.16,27.31 -46.31,31.07 -19.1,3.73 -36.63,6.63 -52.59,8.76 l 0,43.04 215.29,0 0,-141.88 3.19,0 c 26.58,51.03 60.25,88.5 101.21,112.42 40.86,23.87 90.09,35.87 147.45,35.87 54.22,0 102.27,-10.92 144.26,-32.71 41.99,-21.77 77.1,-51.54 105.25,-89.27 28.14,-37.73 49.45,-82.37 63.79,-133.91 14.29,-51.57 21.49,-106.52 21.49,-165.01 0,-60.56 -6.38,-116.4 -19.11,-167.38 -12.77,-51.02 -32.68,-95.12 -59.79,-132.35 -27.11,-37.22 -61.95,-66.44 -104.47,-87.66 -42.49,-21.22 -92.98,-31.92 -151.42,-31.92 -39.3,0 -73.59,6.38 -102.82,19.14 -29.22,12.78 -54.17,27.61 -74.9,44.65 -20.71,16.99 -36.99,34.31 -48.64,51.84 -11.68,17.53 -19.15,31.01 -22.3,40.63 l -3.19,0 0,-497.4 -218.48,0 0,36.64" /><path
+         id="path4227"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 2373.85,2152.18 c -36.15,0 -68.56,-8.22 -97.24,-24.68 -28.69,-16.5 -52.92,-37.74 -72.57,-63.79 -19.64,-26.05 -34.8,-55.26 -45.4,-87.66 -10.66,-32.45 -16.01,-64.58 -16.01,-96.47 l 432.13,0 c 0,34 -3.78,67.49 -11.2,100.44 -7.42,32.93 -19.16,62.17 -35.06,87.66 -15.97,25.54 -36.69,45.95 -62.18,61.42 -25.53,15.37 -56.33,23.08 -92.47,23.08 z m 218.44,-720.59 c -18.12,-6.37 -41.5,-15.14 -70.14,-26.3 -28.76,-11.15 -66.49,-16.71 -113.24,-16.71 -59.53,0 -113.48,8.49 -161.81,25.48 -48.36,17 -89.27,43.29 -122.77,78.9 -33.49,35.62 -59.2,80.74 -77.28,135.51 -18.11,54.74 -26.57,119.84 -25.58,195.28 1.08,60.61 10.94,115.86 29.55,165.83 18.61,49.94 43.59,93.28 74.93,129.94 31.3,36.66 68.56,65.05 111.63,85.28 42.98,20.17 89.51,30.3 139.5,30.3 55.21,0 103.04,-10.36 143.46,-31.09 40.37,-20.72 73.36,-50.21 98.81,-88.49 25.53,-38.26 44.11,-84.22 55.8,-137.88 11.68,-53.7 17.03,-114.01 15.95,-180.95 l -550.04,0 c -3.19,-66.99 5.08,-124.89 24.77,-173.8 19.65,-48.87 49.14,-86.85 88.48,-113.97 39.24,-27.1 87.39,-43.33 144.25,-48.65 56.84,-5.34 121.44,1.58 193.73,20.74 l 0,-49.42" /><path
+         id="path4229"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 3443.59,1484.24 c 11.64,-17.08 27.6,-27.42 47.83,-31.11 20.14,-3.73 38.2,-6.65 54.16,-8.76 l 0,-39.89 -218.38,0 0,489.45 c 0,76.52 -14.62,137.1 -43.88,181.74 -29.23,44.64 -77.87,66.93 -145.84,66.93 -45.68,0 -83.76,-9.79 -113.97,-29.46 -30.3,-19.67 -54.8,-44.37 -73.37,-74.13 -18.57,-29.77 -31.64,-62.96 -39.06,-99.67 -7.47,-36.66 -11.16,-71.44 -11.16,-104.39 l 0,-428.85 -114.77,0 0,726.96 c -11.74,16.99 -27.65,27.35 -47.88,31.1 -20.18,3.71 -38.26,6.61 -54.17,8.77 l 0,46.21 215.25,0 0,-149.83 c 7.42,18.07 18.35,36.39 32.64,54.98 14.39,18.59 32.42,35.63 54.17,51.02 21.81,15.4 47.88,27.89 78.18,37.45 30.3,9.58 65.59,14.37 106.01,14.37 99.89,0 170.56,-22.87 212.01,-68.56 41.45,-45.72 62.23,-113.2 62.23,-202.47 l 0,-471.86" /><path
+         id="path4231"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 5237.3,2219.14 0,-814.66 -116.39,0 0,731.79 c -11.69,16.95 -27.59,27.31 -47.83,31.07 -20.19,3.73 -38.22,6.63 -54.18,8.76 l 0,43.04 218.4,0" /><path
+         id="path4233"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 5823.94,1613.35 c -14.87,-51.01 -40.1,-92.25 -75.7,-123.53 -35.65,-31.38 -76.25,-54 -121.98,-67.8 -45.67,-13.8 -93.01,-18.87 -141.87,-15.15 -48.87,3.74 -93.52,14.61 -133.89,32.68 l 0,51.03 c 24.42,-12.73 56.6,-20.99 96.43,-24.68 39.84,-3.78 78.9,-0.81 117.21,8.72 38.22,9.62 71.17,26.61 98.82,51.07 27.6,24.41 41.39,58.39 41.39,101.97 0,31.91 -9.52,57.95 -28.68,78.12 -19.05,20.24 -43.24,37.5 -72.51,51.84 -29.22,14.34 -60.82,27.92 -94.86,40.64 -34.04,12.77 -65.64,27.92 -94.86,45.45 -29.22,17.54 -53.41,38.51 -72.51,62.99 -19.11,24.43 -28.73,56.28 -28.73,95.64 0,39.3 6.92,73.86 20.77,103.61 13.8,29.75 32.64,54.21 56.56,73.37 23.91,19.12 51.83,33.44 83.7,43.02 31.88,9.55 65.87,14.36 102.02,14.36 48.86,0 87.71,-2.68 116.42,-7.98 28.65,-5.35 52.6,-11.71 71.71,-19.12 l -1.57,-47.82 c -41.49,16.97 -82.14,26.53 -121.96,28.68 -39.88,2.09 -75.48,-3.46 -106.82,-16.74 -31.38,-13.31 -56.6,-34.28 -75.71,-62.97 -19.2,-28.67 -28.72,-64.85 -28.72,-108.41 0,-24.45 10.43,-44.66 31.1,-60.58 20.73,-15.94 46.49,-30.57 77.29,-43.85 30.83,-13.31 63.79,-26.86 98.9,-40.62 35.02,-13.84 67.16,-31.11 96.43,-51.88 29.22,-20.68 52.83,-46.21 70.95,-76.46 18.02,-30.36 24.95,-68.84 20.67,-115.6" /><path
+         id="path4235"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 6558.89,2302.04 c 0,26.55 -4.76,52.6 -14.3,78.12 -9.53,25.53 -23.69,48.08 -42.25,67.77 -18.61,19.64 -41.72,35.31 -69.38,47.02 -27.59,11.69 -58.93,17.56 -94.04,17.56 l -251.84,0 0,-446.4 232.73,0 c 33.99,0 65.64,6.09 94.81,18.34 29.27,12.21 54.45,28.93 75.77,50.2 21.26,21.24 38.02,46.26 50.2,74.95 12.23,28.7 18.3,59.49 18.3,92.44 z m -471.81,-350.7 0,-548.43 -116.4,0 0,1119.13 c -12.76,14.88 -28.77,24.19 -47.83,27.92 -19.15,3.7 -36.18,6.63 -51.03,8.74 l 0,43.07 491.02,0 c 48.86,0 92.47,-8.22 130.68,-24.73 38.35,-16.47 70.72,-38.52 97.3,-66.13 26.61,-27.67 46.74,-60.06 60.54,-97.26 13.9,-37.2 20.78,-77.08 20.78,-119.59 0,-40.36 -6.88,-79.97 -20.78,-118.75 -13.8,-38.81 -32.9,-74.13 -57.36,-106 -24.45,-31.9 -54.17,-58.47 -89.28,-79.73 -35.07,-21.27 -73.9,-34.01 -116.3,-38.24 l -301.34,0" /><path
+         id="path4237"
+         style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 5191.86,2575.13 c -20.96,1.6 -38.9,-4.47 -54.09,-18.57 -15.28,-13.77 -23.6,-30.99 -25.18,-50.7 -1.62,-20.78 3.96,-38.69 16.91,-53.86 12.81,-15.24 29.71,-23.58 50.62,-25.27 19.69,-1.46 36.82,4.1 50.84,17.18 14.21,13.08 21.95,30.03 23.52,50.79 1.57,19.66 -3.28,37.86 -15.2,53.78 -11.82,16.34 -27.78,25.01 -47.42,26.65" /></g></g></svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo-small.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo-small.svg
new file mode 100644
index 00000000..b39dfda6
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo-small.svg
@@ -0,0 +1,2 @@
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" version="1.1" id="svg4155" viewBox="335.2 0 428.8 482.65"><metadata id="metadata4161"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs id="defs4159"><clipPath id="clipPath4171" clipPathUnits="userSpaceOnUse">
+       <path id="path4173" d="M 5806.68,3511.64 C 5449.15,3664.07 4745.83,2493.09 4416.4,1478.31 c 0,0 -104.22,263.26 -114.1,571.55 -5.81,179.13 42.8,124.58 62.67,112.62 l 7.15,53.36 -94.23,13.42 0,0.07 -97.47,11.35 -6.92,-53.43 c 22.34,6.58 83.21,46.91 31.88,-124.85 -88.35,-295.48 -256.35,-523.49 -256.35,-523.49 -59.34,1065.22 -440.17,2376.71 -824.86,2320.43 -137.11,-20.05 -631.33,-304.87 -364.82,-855.17 -0.1,-0.06 -0.23,-0.29 -0.28,-0.47 3.74,-7.81 8.1,-15.75 12.24,-23.66 2.92,-5.58 5.48,-10.91 8.49,-16.49 9.72,-18 20.37,-36.14 31.79,-54.66 3.33,-5.39 6.96,-10.99 10.65,-16.38 9.22,-14.73 19.33,-29.56 29.81,-44.58 4.04,-5.62 7.91,-11.44 12.09,-17.17 14.12,-19.49 29.13,-39.27 45.09,-59.19 3.15,-3.98 6.65,-7.96 9.94,-11.95 13.89,-16.82 28.5,-33.95 43.83,-51.3 5.3,-5.92 10.61,-11.92 16.09,-17.91 19.21,-21 39.07,-42.38 60.51,-63.82 20.1,-20.21 38.13,-39.23 57.19,-58.87 -0.32,0.38 -0.58,0.69 -0.9,1.08 -567.66,669.28 -212.55,993.27 -96.07,1065.38 327.38,202.3 911.72,-1687.94 907.85,-2234.81 127.41,144.03 243.4,313.97 331.69,545.14 26.3,-246.1 94.95,-439.95 181.31,-611.77 136.03,529.59 1183.75,2208.46 1448.63,1929.46 94.23,-99.4 354.26,-502.63 -363.51,-1004.42 22.11,13.33 44.55,26.68 67.65,40.22 26.21,15.44 50.72,30.84 74.73,46.35 6.87,4.47 13.52,8.83 20.26,13.24 19.25,12.9 37.73,25.64 55.35,38.39 4.18,3.04 8.54,5.98 12.63,9.06 20.67,15.22 40.19,30.48 58.85,45.68 5.54,4.49 10.6,9.08 16.09,13.48 13.95,11.89 27.47,23.74 40.29,35.47 4.76,4.43 9.79,8.86 14.33,13.2 15.79,14.95 30.75,29.8 44.78,44.78 4.27,4.6 8.09,9.12 12.41,13.82 5.94,6.48 12.27,13.15 17.94,19.78 -0.09,0.11 -0.23,0.38 -0.23,0.56 398.36,463.95 -6.82,865.46 -134.19,919.83 z"/></clipPath><radialGradient id="radialGradient4175" spreadMethod="pad" gradientTransform="matrix(196.157,2248.14,2248.14,-196.157,4274.47,2111.59)" gradientUnits="userSpaceOnUse" r="1" cy="0" cx="0" fy="0" fx="0"><stop id="stop4177" offset="0" style="stop-opacity:1;stop-color:#161315"/><stop id="stop4179" offset="0.674286" style="stop-opacity:1;stop-color:#161315"/><stop id="stop4181" offset="0.91399019" style="stop-opacity:1;stop-color:#161315"/><stop id="stop4183" offset="1" style="stop-opacity:1;stop-color:#e0e0e1"/></radialGradient><clipPath id="clipPath4191" clipPathUnits="userSpaceOnUse"><path id="path4193" d="m 5869.3,3262.2 c -264.88,279 -1312.6,-1399.87 -1448.63,-1929.46 4.76,-9.44 9.53,-19.07 14.38,-28.46 12.6,-22.88 32.91,-59.7 59.03,-106.73 C 4674.09,872.648 5127.39,61.6289 5196.8,4.37109 5258.67,-46.6211 4978.22,362.309 5030.5,538.449 c 99.9,-126.469 179.47,-221.508 205.23,-238.41 3.33,-2.109 5.81,-3.23 7.23,-3.457 19.03,-2.57 -120.21,161.168 -173.98,297.16 25.31,17.528 62.35,26.078 114.78,22.028 143.32,-11.188 40.06,31.199 -102.06,135.949 24.34,16.281 63.53,23.742 122.38,18.39 300.4,-27.25 -488.4,159.911 -455.28,565.871 22.62,239.61 215.43,543.88 755.28,920.59 0.53,0.43 1.12,0.81 1.71,1.21 717.77,501.79 457.74,905.02 363.51,1004.42 z m -2869.48,371.98 c -116.48,-72.11 -471.59,-396.1 96.07,-1065.38 0.32,-0.39 0.58,-0.7 0.9,-1.08 425.06,-501.29 533.6,-844.4 494.34,-1081.72 -71.75,-400.88 -882.31,-380.74 -584.88,-430.96 58.09,-9.8 94.22,-27.02 113.47,-48.92 -163.96,-64.96 -274.78,-79.741 -133.25,-105.499 51.79,-9.402 85.28,-27.16 105.24,-50.629 -86.72,-117.601 -263.13,-240.523 -244.07,-242.801 1.4,-0.242 4,0.219 7.74,1.469 29.3,9.809 130.54,81.332 259.39,178.129 5.53,-183.687 -370.03,-507.469 -297.2,-473.937 81.95,37.73 729.73,708.608 986.02,975.828 35.79,37.36 64.02,66.9 81.92,85.64 7.45,8.18 14.79,16.69 22.16,25.05 3.87,546.87 -580.47,2437.11 -907.85,2234.81 z"/></clipPath><radialGradient id="radialGradient4195" spreadMethod="pad" gradientTransform="matrix(1718.42,0,0,-1718.42,4388.12,1824.63)" gradientUnits="userSpaceOnUse" r="1" cy="0" cx="0" fy="0" fx="0"><stop id="stop4197" offset="0" style="stop-opacity:1;stop-color:#fde3c3"/><stop id="stop4199" offset="1" style="stop-opacity:1;stop-color:#f79210"/></radialGradient><clipPath id="clipPath4207" clipPathUnits="userSpaceOnUse"><path id="path4209" d="m 5806.05,2781.78 c -8.81,4.76 -18.43,7.86 -28.96,9.31 -284.8,37.42 -1184.87,-1153.28 -1336.27,-1412.09 -7.48,-15.51 -16.15,-36.1 -20.15,-46.26 28.42,-38.39 375.98,-498.119 609.57,-793.931 6.83,23.023 19.1,41.722 38.66,55.121 -26.57,67.242 -32.15,127.761 12.72,157.89 -156.67,115.52 -360.41,306.99 -332.82,586.49 0.41,4.86 1,9.89 1.67,14.92 30.22,236.79 226.67,535.62 753.61,903.34 1.83,1.15 3.42,2.27 5.12,3.47 204.88,143.74 331.33,281.26 404.65,406.02 -30.07,56.93 -74.58,97.37 -107.8,115.72 z m -2837.39,373.36 c -10.52,1.32 -20.63,0.75 -30.3,-1.55 -36.86,-9.28 -90.36,-36.95 -133.88,-84.43 38.98,-139.25 126.11,-304.58 287.54,-495.78 1.31,-1.6 2.57,-3.08 3.87,-4.58 415.58,-489.92 529.27,-828.94 498.02,-1065.59 -0.71,-5.04 -1.51,-10.07 -2.2,-15.02 -44.81,-277.14 -290.91,-410.27 -471.81,-482.2 35.74,-40.361 14.88,-97.459 -27.96,-155.728 15.37,-17.973 22.47,-39.242 23.28,-63.114 301.48,226.402 755.31,582.272 792.45,612.222 -1.21,10.88 -4.35,32.81 -7.55,49.71 -80.39,288.9 -646.48,1669.53 -931.46,1706.06 z"/></clipPath><radialGradient id="radialGradient4211" spreadMethod="pad" gradientTransform="matrix(2097.01,-325.913,-95.8387,-616.652,4244.08,1881.86)" gradientUnits="userSpaceOnUse" r="1" cy="0" cx="0" fy="0" fx="0"><stop id="stop4213" offset="0" style="stop-opacity:1;stop-color:#f9b2b4"/><stop id="stop4215" offset="0.70487066" style="stop-opacity:1;stop-color:#c4161d"/><stop id="stop4217" offset="1" style="stop-opacity:1;stop-color:#c4161d"/></radialGradient></defs><g transform="matrix(1.25,0,0,-1.25,0,482.6375)" id="g4163"><g transform="scale(0.1,0.1)" id="g4165"><g id="g4167"><g clip-path="url(#clipPath4171)" id="g4169"><path id="path4185" style="fill:url(#radialGradient4175);fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 5806.68,3511.64 C 5449.15,3664.07 4745.83,2493.09 4416.4,1478.31 c 0,0 -104.22,263.26 -114.1,571.55 -5.81,179.13 42.8,124.58 62.67,112.62 l 7.15,53.36 -94.23,13.42 0,0.07 -97.47,11.35 -6.92,-53.43 c 22.34,6.58 83.21,46.91 31.88,-124.85 -88.35,-295.48 -256.35,-523.49 -256.35,-523.49 -59.34,1065.22 -440.17,2376.71 -824.86,2320.43 -137.11,-20.05 -631.33,-304.87 -364.82,-855.17 -0.1,-0.06 -0.23,-0.29 -0.28,-0.47 3.74,-7.81 8.1,-15.75 12.24,-23.66 2.92,-5.58 5.48,-10.91 8.49,-16.49 9.72,-18 20.37,-36.14 31.79,-54.66 3.33,-5.39 6.96,-10.99 10.65,-16.38 9.22,-14.73 19.33,-29.56 29.81,-44.58 4.04,-5.62 7.91,-11.44 12.09,-17.17 14.12,-19.49 29.13,-39.27 45.09,-59.19 3.15,-3.98 6.65,-7.96 9.94,-11.95 13.89,-16.82 28.5,-33.95 43.83,-51.3 5.3,-5.92 10.61,-11.92 16.09,-17.91 19.21,-21 39.07,-42.38 60.51,-63.82 20.1,-20.21 38.13,-39.23 57.19,-58.87 -0.32,0.38 -0.58,0.69 -0.9,1.08 -567.66,669.28 -212.55,993.27 -96.07,1065.38 327.38,202.3 911.72,-1687.94 907.85,-2234.81 127.41,144.03 243.4,313.97 331.69,545.14 26.3,-246.1 94.95,-439.95 181.31,-611.77 136.03,529.59 1183.75,2208.46 1448.63,1929.46 94.23,-99.4 354.26,-502.63 -363.51,-1004.42 22.11,13.33 44.55,26.68 67.65,40.22 26.21,15.44 50.72,30.84 74.73,46.35 6.87,4.47 13.52,8.83 20.26,13.24 19.25,12.9 37.73,25.64 55.35,38.39 4.18,3.04 8.54,5.98 12.63,9.06 20.67,15.22 40.19,30.48 58.85,45.68 5.54,4.49 10.6,9.08 16.09,13.48 13.95,11.89 27.47,23.74 40.29,35.47 4.76,4.43 9.79,8.86 14.33,13.2 15.79,14.95 30.75,29.8 44.78,44.78 4.27,4.6 8.09,9.12 12.41,13.82 5.94,6.48 12.27,13.15 17.94,19.78 -0.09,0.11 -0.23,0.38 -0.23,0.56 398.36,463.95 -6.82,865.46 -134.19,919.83"/></g></g><g id="g4187"><g clip-path="url(#clipPath4191)" id="g4189"><path id="path4201" style="fill:url(#radialGradient4195);fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 5869.3,3262.2 c -264.88,279 -1312.6,-1399.87 -1448.63,-1929.46 4.76,-9.44 9.53,-19.07 14.38,-28.46 12.6,-22.88 32.91,-59.7 59.03,-106.73 C 4674.09,872.648 5127.39,61.6289 5196.8,4.37109 5258.67,-46.6211 4978.22,362.309 5030.5,538.449 c 99.9,-126.469 179.47,-221.508 205.23,-238.41 3.33,-2.109 5.81,-3.23 7.23,-3.457 19.03,-2.57 -120.21,161.168 -173.98,297.16 25.31,17.528 62.35,26.078 114.78,22.028 143.32,-11.188 40.06,31.199 -102.06,135.949 24.34,16.281 63.53,23.742 122.38,18.39 300.4,-27.25 -488.4,159.911 -455.28,565.871 22.62,239.61 215.43,543.88 755.28,920.59 0.53,0.43 1.12,0.81 1.71,1.21 717.77,501.79 457.74,905.02 363.51,1004.42 z m -2869.48,371.98 c -116.48,-72.11 -471.59,-396.1 96.07,-1065.38 0.32,-0.39 0.58,-0.7 0.9,-1.08 425.06,-501.29 533.6,-844.4 494.34,-1081.72 -71.75,-400.88 -882.31,-380.74 -584.88,-430.96 58.09,-9.8 94.22,-27.02 113.47,-48.92 -163.96,-64.96 -274.78,-79.741 -133.25,-105.499 51.79,-9.402 85.28,-27.16 105.24,-50.629 -86.72,-117.601 -263.13,-240.523 -244.07,-242.801 1.4,-0.242 4,0.219 7.74,1.469 29.3,9.809 130.54,81.332 259.39,178.129 5.53,-183.687 -370.03,-507.469 -297.2,-473.937 81.95,37.73 729.73,708.608 986.02,975.828 35.79,37.36 64.02,66.9 81.92,85.64 7.45,8.18 14.79,16.69 22.16,25.05 3.87,546.87 -580.47,2437.11 -907.85,2234.81"/></g></g><g id="g4203"><g clip-path="url(#clipPath4207)" id="g4205"><path id="path4219" style="fill:url(#radialGradient4211);fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 5806.05,2781.78 c -8.81,4.76 -18.43,7.86 -28.96,9.31 -284.8,37.42 -1184.87,-1153.28 -1336.27,-1412.09 -7.48,-15.51 -16.15,-36.1 -20.15,-46.26 28.42,-38.39 375.98,-498.119 609.57,-793.931 6.83,23.023 19.1,41.722 38.66,55.121 -26.57,67.242 -32.15,127.761 12.72,157.89 -156.67,115.52 -360.41,306.99 -332.82,586.49 0.41,4.86 1,9.89 1.67,14.92 30.22,236.79 226.67,535.62 753.61,903.34 1.83,1.15 3.42,2.27 5.12,3.47 204.88,143.74 331.33,281.26 404.65,406.02 -30.07,56.93 -74.58,97.37 -107.8,115.72 z m -2837.39,373.36 c -10.52,1.32 -20.63,0.75 -30.3,-1.55 -36.86,-9.28 -90.36,-36.95 -133.88,-84.43 38.98,-139.25 126.11,-304.58 287.54,-495.78 1.31,-1.6 2.57,-3.08 3.87,-4.58 415.58,-489.92 529.27,-828.94 498.02,-1065.59 -0.71,-5.04 -1.51,-10.07 -2.2,-15.02 -44.81,-277.14 -290.91,-410.27 -471.81,-482.2 35.74,-40.361 14.88,-97.459 -27.96,-155.728 15.37,-17.973 22.47,-39.242 23.28,-63.114 301.48,226.402 755.31,582.272 792.45,612.222 -1.21,10.88 -4.35,32.81 -7.55,49.71 -80.39,288.9 -646.48,1669.53 -931.46,1706.06"/></g></g><path id="path4221" style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 3491.42,2798.59 c -20.95,1.6 -38.85,-4.4 -53.95,-18.52 -15.33,-13.82 -23.73,-31 -25.27,-50.73 -1.57,-20.8 4.01,-38.67 16.99,-53.84 12.82,-15.26 29.59,-23.51 50.58,-25.29 19.7,-1.48 36.83,4.12 50.9,17.2 14.2,13.05 21.8,30.03 23.42,50.79 1.53,19.68 -3.28,37.86 -15.2,53.8 -11.74,16.3 -27.73,24.95 -47.47,26.59"/><path id="path4237" style="fill:#161315;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 5191.86,2575.13 c -20.96,1.6 -38.9,-4.47 -54.09,-18.57 -15.28,-13.77 -23.6,-30.99 -25.18,-50.7 -1.62,-20.78 3.96,-38.69 16.91,-53.86 12.81,-15.24 29.71,-23.58 50.62,-25.27 19.69,-1.46 36.82,4.1 50.84,17.18 14.21,13.08 21.95,30.03 23.52,50.79 1.57,19.66 -3.28,37.86 -15.2,53.78 -11.82,16.34 -27.78,25.01 -47.42,26.65"/></g></g></svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo.svg
deleted file mode 100644
index 0493ac7c..00000000
--- a/openwisp_utils/admin_theme/static/ui/openwisp/images/openwisp-logo.svg
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   version="1.1"
-   width="1377.5"
-   height="744.09998"
-   id="svg2"
-   xml:space="preserve"><metadata
-     id="metadata8"><rdf:RDF><cc:Work
-         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
-     id="defs6"><linearGradient
-       id="linearGradient3133"><stop
-         id="stop3135"
-         style="stop-color:#ffffff;stop-opacity:1"
-         offset="0" /><stop
-         id="stop3137"
-         style="stop-color:#ffffff;stop-opacity:0"
-         offset="1" /></linearGradient><clipPath
-       id="clipPath20"><path
-         d="M 9169.55,5390.38 C 8629.64,5620.56 7567.6,3852.27 7070.11,2319.85 c 0,0 -157.36,397.54 -172.33,863.1 -8.76,270.49 64.66,188.1 94.66,170.06 l 10.8,80.58 -142.3,20.28 0,0.08 -147.19,17.16 -10.45,-80.7 c 33.74,9.95 125.67,70.85 48.15,-188.51 -133.41,-446.21 -387.1,-790.54 -387.1,-790.54 -89.64,1608.59 -664.72,3589.05 -1245.63,3504.08 -207.06,-30.28 -953.38,-460.39 -550.91,-1291.39 -0.15,-0.09 -0.35,-0.44 -0.42,-0.7 5.64,-11.81 12.22,-23.82 18.47,-35.76 4.41,-8.4 8.28,-16.45 12.82,-24.86 14.68,-27.22 30.75,-54.59 48,-82.56 5.04,-8.14 10.53,-16.6 16.09,-24.75 13.93,-22.23 29.2,-44.65 45.01,-67.32 6.12,-8.47 11.95,-17.27 18.26,-25.93 21.32,-29.43 43.99,-59.31 68.1,-89.37 4.75,-6.01 10.04,-12.02 15,-18.05 20.98,-25.4 43.04,-51.26 66.19,-77.46 8.01,-8.93 16.03,-18.01 24.3,-27.07 29.01,-31.69 59,-63.97 91.39,-96.37 30.34,-30.51 57.56,-59.22 86.37,-88.9 -0.49,0.58 -0.9,1.06 -1.38,1.64 -857.23,1010.69 -320.97,1499.92 -145.08,1608.81 494.37,305.49 1376.78,-2548.93 1370.95,-3374.75 192.41,217.5 367.55,474.1 500.88,823.21 39.72,-371.64 143.36,-664.37 273.8,-923.86 205.42,799.73 1787.56,3335 2187.57,2913.7 142.31,-150.09 534.94,-759.03 -548.95,-1516.77 33.38,20.13 67.27,40.29 102.17,60.72 39.58,23.32 76.57,46.58 112.85,70 10.38,6.76 20.42,13.33 30.6,19.99 29.07,19.49 56.96,38.73 83.58,57.98 6.31,4.58 12.91,9.03 19.07,13.67 31.22,23 60.68,46.04 88.87,68.99 8.36,6.79 16.01,13.71 24.31,20.35 21.05,17.96 41.47,35.85 60.82,53.57 7.19,6.69 14.79,13.38 21.64,19.93 23.86,22.59 46.46,45.01 67.63,67.62 6.45,6.96 12.23,13.77 18.74,20.88 8.95,9.76 18.52,19.86 27.07,29.87 -0.11,0.17 -0.31,0.58 -0.31,0.86 601.57,700.59 -10.33,1306.91 -202.67,1389.02 z"
-         id="path22" /></clipPath><radialGradient
-       cx="0"
-       cy="0"
-       r="1"
-       fx="0"
-       fy="0"
-       id="radialGradient24"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(29.6215,339.49,339.49,-29.6215,685.579,327.614)"
-       spreadMethod="pad"><stop
-         id="stop26"
-         style="stop-color:#ffffff;stop-opacity:1"
-         offset="0" /><stop
-         id="stop28"
-         style="stop-color:#1e1a1b;stop-opacity:1"
-         offset="1" /></radialGradient><clipPath
-       id="clipPath36"><path
-         d="M 9264.13,5013.7 C 8864.12,5435 7281.98,2899.73 7076.56,2100 c 7.19,-14.23 14.41,-28.77 21.72,-42.95 19.01,-34.55 49.69,-90.16 89.12,-161.16 C 7459.24,1405.24 8143.76,180.539 8248.59,94.0586 8341.98,17.0625 7918.51,634.57 7997.46,900.551 c 150.86,-190.969 271.01,-334.469 309.91,-360 5.03,-3.18 8.77,-4.871 10.91,-5.219 28.74,-3.902 -181.51,243.379 -262.71,448.731 38.23,26.487 94.16,39.387 173.33,33.257 216.43,-16.89 60.49,47.12 -154.12,205.3 36.74,24.58 95.92,35.84 184.79,27.77 453.63,-41.13 -737.51,241.5 -687.5,854.52 34.16,361.84 325.3,821.31 1140.54,1390.19 0.81,0.64 1.69,1.22 2.57,1.83 1083.89,757.74 691.26,1366.68 548.95,1516.77 z m -4333.2,561.7 c -175.89,-108.89 -712.15,-598.12 145.08,-1608.81 0.48,-0.58 0.89,-1.06 1.38,-1.64 641.87,-756.99 805.77,-1275.09 746.48,-1633.51 -108.35,-605.35 -1332.37,-574.93 -883.22,-650.77 87.71,-14.78 142.29,-40.8 171.35,-73.87 -247.6,-98.08 -414.95,-120.41 -201.22,-159.31 78.2,-14.2 128.77,-41.01 158.92,-76.46 -130.96,-177.58 -397.36,-363.2 -368.57,-366.64 2.1,-0.38 6.05,0.3 11.68,2.22 44.27,14.8 197.14,122.81 391.71,268.97 8.36,-277.381 -558.78,-766.33 -448.8,-715.678 123.75,56.95 1101.98,1070.048 1489,1473.578 54.03,56.44 96.68,101.04 123.7,129.33 11.25,12.36 22.34,25.19 33.46,37.84 5.83,825.82 -876.58,3680.24 -1370.95,3374.75 z"
-         id="path38" /></clipPath><radialGradient
-       cx="0"
-       cy="0"
-       r="1"
-       fx="0"
-       fy="0"
-       id="radialGradient40"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(259.498,0,0,-259.498,702.739,284.282)"
-       spreadMethod="pad"><stop
-         id="stop42"
-         style="stop-color:#fde3c3;stop-opacity:1"
-         offset="0" /><stop
-         id="stop44"
-         style="stop-color:#f7921a;stop-opacity:1"
-         offset="1" /></radialGradient><clipPath
-       id="clipPath52"><path
-         d="m 9168.6,4288.21 c -13.3,7.21 -27.81,11.88 -43.72,14.05 -430.07,56.53 -1789.26,-1741.53 -2017.92,-2132.37 -11.27,-23.43 -24.36,-54.51 -30.4,-69.89 42.91,-57.96 567.75,-752.17 920.5,-1198.891 10.31,34.77 28.86,62.981 58.37,83.231 -40.11,101.56 -48.52,192.94 19.23,238.44 -236.59,174.47 -544.27,463.57 -502.59,885.66 0.62,7.35 1.49,14.93 2.51,22.53 45.63,357.58 342.3,808.84 1138.03,1364.13 2.78,1.73 5.16,3.45 7.74,5.23 309.39,217.06 500.33,424.76 611.07,613.12 -45.42,85.99 -112.64,147.05 -162.82,174.76 z m -4284.71,563.82 c -15.89,1.99 -31.16,1.12 -45.76,-2.33 -55.66,-14.03 -136.45,-55.83 -202.17,-127.52 58.85,-210.26 190.44,-459.96 434.21,-748.67 1.98,-2.41 3.89,-4.64 5.84,-6.92 627.56,-739.83 799.26,-1251.77 752.06,-1609.13 -1.07,-7.61 -2.3,-15.21 -3.31,-22.68 -67.68,-418.52 -439.32,-619.55 -712.49,-728.18 53.97,-60.96 22.46,-147.17 -42.23,-235.16 23.21,-27.14 33.95,-59.27 35.17,-95.33 455.25,341.9 1140.58,879.32 1196.67,924.54 -1.84,16.42 -6.58,49.53 -11.41,75.06 -121.4,436.26 -976.25,2521.15 -1406.58,2576.32 z"
-         id="path54" /></clipPath><radialGradient
-       cx="0"
-       cy="0"
-       r="1"
-       fx="0"
-       fy="0"
-       id="radialGradient56"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(316.669,-49.216,-14.4726,-93.1204,680.989,292.924)"
-       spreadMethod="pad"><stop
-         id="stop58"
-         style="stop-color:#f9b2b4;stop-opacity:1"
-         offset="0" /><stop
-         id="stop60"
-         style="stop-color:#c4161d;stop-opacity:1"
-         offset="1" /></radialGradient><linearGradient
-       x1="2337.2021"
-       y1="1799.646"
-       x2="2290.4583"
-       y2="5340.5073"
-       id="linearGradient3139"
-       xlink:href="#linearGradient3133"
-       gradientUnits="userSpaceOnUse" /></defs><g
-     transform="matrix(1.25,0,0,-1.25,0,744.1)"
-     id="g10"><g
-       transform="scale(0.1,0.1)"
-       id="g12"><g
-         id="g16"
-         style="fill:url(#linearGradient3139);fill-opacity:1"><g
-           clip-path="url(#clipPath20)"
-           id="g18"
-           style="fill:url(#linearGradient3139);fill-opacity:1"><path
-             d="M 9169.55,5390.38 C 8629.64,5620.56 7567.6,3852.27 7070.11,2319.85 c 0,0 -157.36,397.54 -172.33,863.1 -8.76,270.49 64.66,188.1 94.66,170.06 l 10.8,80.58 -142.3,20.28 0,0.08 -147.19,17.16 -10.45,-80.7 c 33.74,9.95 125.67,70.85 48.15,-188.51 -133.41,-446.21 -387.1,-790.54 -387.1,-790.54 -89.64,1608.59 -664.72,3589.05 -1245.63,3504.08 -207.06,-30.28 -953.38,-460.39 -550.91,-1291.39 -0.15,-0.09 -0.35,-0.44 -0.42,-0.7 5.64,-11.81 12.22,-23.82 18.47,-35.76 4.41,-8.4 8.28,-16.45 12.82,-24.86 14.68,-27.22 30.75,-54.59 48,-82.56 5.04,-8.14 10.53,-16.6 16.09,-24.75 13.93,-22.23 29.2,-44.65 45.01,-67.32 6.12,-8.47 11.95,-17.27 18.26,-25.93 21.32,-29.43 43.99,-59.31 68.1,-89.37 4.75,-6.01 10.04,-12.02 15,-18.05 20.98,-25.4 43.04,-51.26 66.19,-77.46 8.01,-8.93 16.03,-18.01 24.3,-27.07 29.01,-31.69 59,-63.97 91.39,-96.37 30.34,-30.51 57.56,-59.22 86.37,-88.9 -0.49,0.58 -0.9,1.06 -1.38,1.64 -857.23,1010.69 -320.97,1499.92 -145.08,1608.81 494.37,305.49 1376.78,-2548.93 1370.95,-3374.75 192.41,217.5 367.55,474.1 500.88,823.21 39.72,-371.64 143.36,-664.37 273.8,-923.86 205.42,799.73 1787.56,3335 2187.57,2913.7 142.31,-150.09 534.94,-759.03 -548.95,-1516.77 33.38,20.13 67.27,40.29 102.17,60.72 39.58,23.32 76.57,46.58 112.85,70 10.38,6.76 20.42,13.33 30.6,19.99 29.07,19.49 56.96,38.73 83.58,57.98 6.31,4.58 12.91,9.03 19.07,13.67 31.22,23 60.68,46.04 88.87,68.99 8.36,6.79 16.01,13.71 24.31,20.35 21.05,17.96 41.47,35.85 60.82,53.57 7.19,6.69 14.79,13.38 21.64,19.93 23.86,22.59 46.46,45.01 67.63,67.62 6.45,6.96 12.23,13.77 18.74,20.88 8.95,9.76 18.52,19.86 27.07,29.87 -0.11,0.17 -0.31,0.58 -0.31,0.86 601.57,700.59 -10.33,1306.91 -202.67,1389.02"
-             id="path30"
-             style="fill:url(#linearGradient3139);fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g><g
-         id="g3130"><g
-           id="g32"><g
-             clip-path="url(#clipPath36)"
-             id="g34"><path
-               d="M 9264.13,5013.7 C 8864.12,5435 7281.98,2899.73 7076.56,2100 c 7.19,-14.23 14.41,-28.77 21.72,-42.95 19.01,-34.55 49.69,-90.16 89.12,-161.16 C 7459.24,1405.24 8143.76,180.539 8248.59,94.0586 8341.98,17.0625 7918.51,634.57 7997.46,900.551 c 150.86,-190.969 271.01,-334.469 309.91,-360 5.03,-3.18 8.77,-4.871 10.91,-5.219 28.74,-3.902 -181.51,243.379 -262.71,448.731 38.23,26.487 94.16,39.387 173.33,33.257 216.43,-16.89 60.49,47.12 -154.12,205.3 36.74,24.58 95.92,35.84 184.79,27.77 453.63,-41.13 -737.51,241.5 -687.5,854.52 34.16,361.84 325.3,821.31 1140.54,1390.19 0.81,0.64 1.69,1.22 2.57,1.83 1083.89,757.74 691.26,1366.68 548.95,1516.77 z m -4333.2,561.7 c -175.89,-108.89 -712.15,-598.12 145.08,-1608.81 0.48,-0.58 0.89,-1.06 1.38,-1.64 641.87,-756.99 805.77,-1275.09 746.48,-1633.51 -108.35,-605.35 -1332.37,-574.93 -883.22,-650.77 87.71,-14.78 142.29,-40.8 171.35,-73.87 -247.6,-98.08 -414.95,-120.41 -201.22,-159.31 78.2,-14.2 128.77,-41.01 158.92,-76.46 -130.96,-177.58 -397.36,-363.2 -368.57,-366.64 2.1,-0.38 6.05,0.3 11.68,2.22 44.27,14.8 197.14,122.81 391.71,268.97 8.36,-277.381 -558.78,-766.33 -448.8,-715.678 123.75,56.95 1101.98,1070.048 1489,1473.578 54.03,56.44 96.68,101.04 123.7,129.33 11.25,12.36 22.34,25.19 33.46,37.84 5.83,825.82 -876.58,3680.24 -1370.95,3374.75"
-               id="path46"
-               style="fill:url(#radialGradient40);fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g><g
-           id="g48"><g
-             clip-path="url(#clipPath52)"
-             id="g50"><path
-               d="m 9168.6,4288.21 c -13.3,7.21 -27.81,11.88 -43.72,14.05 -430.07,56.53 -1789.26,-1741.53 -2017.92,-2132.37 -11.27,-23.43 -24.36,-54.51 -30.4,-69.89 42.91,-57.96 567.75,-752.17 920.5,-1198.891 10.31,34.77 28.86,62.981 58.37,83.231 -40.11,101.56 -48.52,192.94 19.23,238.44 -236.59,174.47 -544.27,463.57 -502.59,885.66 0.62,7.35 1.49,14.93 2.51,22.53 45.63,357.58 342.3,808.84 1138.03,1364.13 2.78,1.73 5.16,3.45 7.74,5.23 309.39,217.06 500.33,424.76 611.07,613.12 -45.42,85.99 -112.64,147.05 -162.82,174.76 z m -4284.71,563.82 c -15.89,1.99 -31.16,1.12 -45.76,-2.33 -55.66,-14.03 -136.45,-55.83 -202.17,-127.52 58.85,-210.26 190.44,-459.96 434.21,-748.67 1.98,-2.41 3.89,-4.64 5.84,-6.92 627.56,-739.83 799.26,-1251.77 752.06,-1609.13 -1.07,-7.61 -2.3,-15.21 -3.31,-22.68 -67.68,-418.52 -439.32,-619.55 -712.49,-728.18 53.97,-60.96 22.46,-147.17 -42.23,-235.16 23.21,-27.14 33.95,-59.27 35.17,-95.33 455.25,341.9 1140.58,879.32 1196.67,924.54 -1.84,16.42 -6.58,49.53 -11.41,75.06 -121.4,436.26 -976.25,2521.15 -1406.58,2576.32"
-               id="path62"
-               style="fill:url(#radialGradient56);fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g><path
-         d="m 5673.29,4313.59 c -31.63,2.42 -58.64,-6.65 -81.45,-27.97 -23.18,-20.87 -35.86,-46.8 -38.15,-76.59 -2.4,-31.4 6.03,-58.4 25.66,-81.3 19.33,-23.06 44.67,-35.5 76.34,-38.18 29.76,-2.25 55.62,6.2 76.88,25.94 21.43,19.74 32.92,45.37 35.36,76.72 2.31,29.72 -4.97,57.16 -22.93,81.22 -17.73,24.61 -41.9,37.68 -71.71,40.16"
-         id="path64"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 576.746,3089.54 c 1.512,-64.26 11.621,-136.47 30.094,-216.65 18.394,-80.33 48.465,-157.73 90.223,-232.35 41.675,-74.67 97.074,-140.5 166.191,-197.4 68.973,-57.04 154.846,-93.56 257.576,-109.59 96.32,-14.38 182.07,-12.87 257.56,4.83 75.43,17.57 141.29,46.5 197.35,86.71 56.29,40.03 103.54,87.82 142.17,143.24 38.42,55.39 70.13,113.51 95.04,174.46 24.85,60.97 42.97,122 54.11,183.03 11.26,61.01 17.65,116.35 19.27,166.09 1.56,123.59 -14.05,232.31 -46.9,326.19 -32.93,93.94 -77.87,173.33 -134.83,238.36 -56.96,65 -123.62,115.59 -199.81,151.71 -76.23,36.04 -157.69,58.13 -244.45,66.19 -89.76,0 -176.51,-16.51 -259.87,-49.36 -83.458,-32.91 -156.974,-82.28 -220.236,-148.05 -63.492,-65.82 -114.058,-147.7 -151.734,-245.6 -37.687,-97.86 -55.066,-211.81 -51.754,-341.81 z m -175.824,4.79 c 0,134.78 19.281,257.18 57.848,367.13 38.503,109.96 92.199,204.21 161.293,282.89 68.906,78.66 150.855,140.38 245.574,185.37 94.558,44.93 197.343,69.79 308.073,74.61 125.26,9.64 241.55,-4.82 349.14,-43.3 107.55,-38.54 201.02,-97.5 280.45,-176.96 79.5,-79.43 141.62,-177.35 186.64,-293.73 44.86,-116.37 67.33,-247.58 67.33,-393.6 0,-134.84 -20.03,-257.21 -60.14,-367.12 -40.19,-109.97 -95.51,-204.33 -166.12,-282.89 -70.6,-78.67 -154.11,-140.04 -250.44,-184.18 -96.27,-44.19 -200.62,-66.93 -312.9,-68.58 -122.01,-8 -235.58,7.61 -340.74,46.87 -105.078,39.35 -196.532,98.77 -274.325,178.27 -77.937,79.42 -139.242,176.09 -184.191,290.01 -45.012,113.91 -67.492,242.33 -67.492,385.21"
-         id="path66"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 2813.15,3320.63 c -65.79,0 -121.6,-16.09 -167.28,-48.14 -45.68,-32.13 -82.69,-73.05 -110.72,-122.81 -28.12,-49.74 -48.14,-104.71 -60.22,-164.9 -12.02,-60.15 -17.99,-117.61 -17.99,-172.14 0,-54.57 5.57,-111.52 16.76,-170.94 11.27,-59.4 30.97,-113.98 58.94,-163.69 28.16,-49.75 65.11,-90.69 110.85,-122.72 45.69,-32.17 102.25,-48.18 169.66,-48.18 70.68,0 128.85,15.18 174.55,45.72 45.75,30.5 82.29,70.22 109.63,119.23 27.23,48.87 46.03,103.46 56.55,163.69 10.32,60.14 15.56,119.12 15.56,176.89 0,57.79 -5.24,116.77 -15.56,176.97 -10.52,60.2 -29.32,114.75 -56.55,163.7 -27.34,48.96 -63.88,89.06 -109.63,120.36 -45.7,31.31 -103.87,46.96 -174.55,46.96 z M 2127,1719.65 c 24.1,3.28 51.38,7.66 81.88,13.24 30.48,5.7 54.64,21.31 72.3,47 l 0,1533.55 c -17.66,25.59 -41.01,41.23 -69.93,46.9 -28.86,5.63 -55.33,10.03 -79.43,13.25 l 0,65 325.12,0 0,-214.26 4.81,0 c 40.13,77.04 90.98,133.65 152.83,169.75 61.71,36.05 136.05,54.18 222.67,54.18 81.88,0 154.43,-16.49 217.85,-49.39 63.41,-32.9 116.42,-77.84 158.94,-134.82 42.48,-56.96 74.67,-124.37 96.34,-202.21 21.57,-77.86 32.45,-160.87 32.45,-249.2 0,-91.43 -9.65,-175.76 -28.87,-252.74 -19.28,-77.06 -49.36,-143.66 -90.28,-199.85 -40.94,-56.21 -93.55,-100.36 -157.78,-132.4 -64.16,-32.03 -140.4,-48.2 -228.65,-48.2 -59.34,0 -111.13,9.64 -155.27,28.93 -44.12,19.27 -81.79,41.67 -113.09,67.4 -31.29,25.68 -55.87,51.81 -73.47,78.28 -17.64,26.47 -28.91,46.85 -33.67,61.38 l -4.81,0 0,-751.14 -329.94,0 0,55.35"
-         id="path68"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 3985.67,3337.47 c -54.6,0 -103.55,-12.44 -146.86,-37.29 -43.31,-24.89 -79.9,-56.98 -109.57,-96.32 -29.66,-39.34 -52.55,-83.45 -68.57,-132.37 -16.09,-49 -24.17,-97.54 -24.17,-145.67 l 652.54,0 c 0,51.32 -5.68,101.91 -16.9,151.67 -11.2,49.71 -28.92,93.88 -52.95,132.38 -24.1,38.56 -55.4,69.37 -93.89,92.73 -38.54,23.22 -85.05,34.87 -139.63,34.87 z m 329.85,-1088.16 c -27.35,-9.64 -62.66,-22.88 -105.91,-39.71 -43.43,-16.85 -100.4,-25.28 -171.01,-25.28 -89.89,0 -171.34,12.85 -244.32,38.53 -73.05,25.66 -134.83,65.38 -185.41,119.12 -50.57,53.77 -89.41,121.94 -116.7,204.61 -27.37,82.68 -40.13,181.01 -38.64,294.94 1.65,91.5 16.51,174.95 44.62,250.39 28.1,75.41 65.84,140.85 113.17,196.25 47.25,55.35 103.52,98.21 168.56,128.76 64.91,30.46 135.16,45.77 210.66,45.77 83.37,0 155.59,-15.64 216.64,-46.96 60.95,-31.27 110.78,-75.84 149.21,-133.63 38.57,-57.77 66.6,-127.2 84.26,-208.21 17.64,-81.11 25.71,-172.16 24.1,-273.25 l -830.64,0 c -4.79,-101.16 7.69,-188.61 37.41,-262.47 29.69,-73.8 74.21,-131.15 133.62,-172.1 59.26,-40.93 131.98,-65.43 217.84,-73.47 85.83,-8.06 183.39,2.39 292.54,31.32 l 0,-74.61"
-         id="path70"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 5601.06,2328.83 c 17.57,-25.82 41.67,-41.43 72.23,-47.01 30.43,-5.63 57.72,-10.05 81.82,-13.25 l 0,-60.19 -329.81,0 0,739.1 c 0,115.55 -22.07,207.02 -66.25,274.44 -44.14,67.42 -117.59,101.08 -220.24,101.08 -68.97,0 -126.48,-14.79 -172.09,-44.5 -45.76,-29.7 -82.77,-67 -110.81,-111.94 -28.03,-44.96 -47.78,-95.07 -58.98,-150.51 -11.29,-55.38 -16.86,-107.88 -16.86,-157.63 l 0,-647.6 -173.3,0 0,1097.76 c -17.73,25.66 -41.76,41.31 -72.31,46.97 -30.47,5.6 -57.76,9.99 -81.8,13.24 l 0,69.8 325.05,0 0,-226.28 c 11.2,27.29 27.71,54.96 49.28,83.02 21.74,28.09 48.96,53.81 81.81,77.05 32.93,23.26 72.3,42.13 118.06,56.56 45.75,14.47 99.05,21.69 160.08,21.69 150.85,0 257.57,-34.52 320.18,-103.53 62.58,-69.04 93.94,-170.94 93.94,-305.74 l 0,-712.53"
-         id="path72"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 8309.74,3438.59 0,-1230.21 -175.75,0 0,1105.06 c -17.64,25.59 -41.67,41.23 -72.22,46.9 -30.51,5.63 -57.72,10.03 -81.83,13.25 l 0,65 329.8,0"
-         id="path74"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 9195.63,2523.79 c -22.48,-77.06 -60.55,-139.31 -114.34,-186.57 -53.81,-47.38 -115.13,-81.54 -184.18,-102.37 -68.97,-20.84 -140.45,-28.51 -214.25,-22.88 -73.8,5.64 -141.21,22.07 -202.18,49.36 l 0,77.05 c 36.86,-19.21 85.48,-31.69 145.62,-37.28 60.16,-5.7 119.14,-1.22 176.99,13.18 57.74,14.55 107.48,40.2 149.24,77.13 41.67,36.85 62.52,88.19 62.52,153.97 0,48.19 -14.39,87.51 -43.31,117.98 -28.81,30.55 -65.31,56.63 -109.51,78.28 -44.13,21.67 -91.86,42.17 -143.26,61.37 -51.38,19.27 -99.11,42.15 -143.24,68.64 -44.11,26.47 -80.63,58.14 -109.5,95.11 -28.85,36.9 -43.37,85 -43.37,144.44 0,59.33 10.44,111.53 31.37,156.43 20.82,44.95 49.28,81.89 85.39,110.8 36.11,28.91 78.29,50.51 126.4,64.98 48.14,14.41 99.48,21.69 154.07,21.69 73.76,0 132.44,-4.04 175.8,-12.06 43.24,-8.07 79.44,-17.69 108.29,-28.87 l -2.38,-72.2 c -62.67,25.62 -124.04,40.06 -184.17,43.29 -60.23,3.16 -113.99,-5.22 -161.3,-25.29 -47.38,-20.08 -85.48,-51.74 -114.33,-95.08 -28.98,-43.31 -43.37,-97.92 -43.37,-163.69 0,-36.94 15.73,-67.47 46.96,-91.49 31.3,-24.09 70.21,-46.16 116.71,-66.22 46.55,-20.1 96.32,-40.57 149.35,-61.34 52.89,-20.91 101.42,-46.99 145.64,-78.33 44.11,-31.23 79.75,-69.81 107.11,-115.47 27.23,-45.85 37.68,-103.98 31.23,-174.56"
-         id="path76"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 10305.5,3563.77 c 0,40.08 -7.2,79.43 -21.6,117.95 -14.4,38.56 -35.8,72.61 -63.8,102.35 -28.1,29.66 -63,53.32 -104.8,71 -41.7,17.67 -89,26.52 -142.01,26.52 l -380.3,0 0,-674.09 351.45,0 c 51.32,0 99.06,9.18 143.16,27.68 44.2,18.45 82.2,43.7 114.4,75.81 32.1,32.07 57.4,69.86 75.8,113.18 18.5,43.33 27.7,89.85 27.7,139.6 z m -712.51,-529.6 0,-828.18 -175.78,0 0,1689.98 c -19.28,22.48 -43.44,36.53 -72.23,42.17 -28.91,5.6 -54.63,10.02 -77.05,13.2 l 0,65.04 741.47,0 c 73.8,0 139.6,-12.42 197.4,-37.33 57.9,-24.89 106.8,-58.18 146.9,-99.87 40.2,-41.79 70.6,-90.7 91.4,-146.87 21,-56.19 31.4,-116.41 31.4,-180.61 0,-60.96 -10.4,-120.77 -31.4,-179.32 -20.8,-58.61 -49.7,-111.94 -86.6,-160.07 -36.9,-48.16 -81.8,-88.28 -134.8,-120.4 -53,-32.11 -111.6,-51.36 -175.6,-57.74 l -455.11,0"
-         id="path78"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
-         d="m 8241.12,3976.16 c -31.65,2.42 -58.72,-6.75 -81.68,-28.03 -23.08,-20.82 -35.63,-46.81 -38,-76.59 -2.47,-31.36 5.96,-58.4 25.52,-81.33 19.36,-23.02 44.88,-35.59 76.43,-38.15 29.74,-2.21 55.6,6.17 76.8,25.94 21.43,19.75 33.14,45.35 35.49,76.7 2.39,29.66 -4.96,57.16 -22.96,81.22 -17.85,24.66 -41.94,37.74 -71.6,40.24"
-         id="path80"
-         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/org-owner.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/org-owner.svg
new file mode 100644
index 00000000..7745c532
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/org-owner.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <rect fill="none" height="24" width="24"/>
+  <path d="M1,22h4V11H1V22z M20,17h-7l-2.09-0.73l0.33-0.94L13,16h2.82c0.65,0,1.18-0.53,1.18-1.18l0,0c0-0.49-0.31-0.93-0.77-1.11 L8.97,11H7v9.02L14,22l8-3l0,0C21.99,17.9,21.11,17,20,17z M14,1.5l-7,5V9h2l8.14,3.26C18.26,12.71,19,13.79,19,15h2V6.5L14,1.5z M13.5,10h-1V9h1V10z M13.5,8h-1V7h1V8z M15.5,10h-1V9h1V10z M15.5,8h-1V7h1V8z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/org-user.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/org-user.svg
new file mode 100644
index 00000000..aa608303
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/org-user.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0z" fill="none"/>
+  <path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/org.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/org.svg
new file mode 100644
index 00000000..cceda127
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/org.svg
@@ -0,0 +1,12 @@
+<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.5922 7.50006C11.5922 9.76007 9.76007 11.5922 7.50006 11.5922C5.24006 11.5922 3.40796 9.76007 3.40796 7.50006C3.40796 5.24006 5.24006 3.40796 7.50006 3.40796C9.76007 3.40796 11.5922 5.24006 11.5922 7.50006Z" stroke="black" stroke-width="0.5"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.68421 1.18421C8.68421 1.75799 8.27613 2.23646 7.73437 2.34523V3.16411C7.65677 3.15999 7.57863 3.15789 7.5 3.15789C7.44631 3.15789 7.39285 3.15887 7.33964 3.1608V2.35766C6.76146 2.27938 6.31579 1.78384 6.31579 1.18421C6.31579 0.530189 6.84598 0 7.5 0C8.15402 0 8.68421 0.530189 8.68421 1.18421ZM4.57611 4.28986L2.8255 2.54818C3.03382 2.28064 3.15789 1.94429 3.15789 1.57895C3.15789 0.706919 2.45098 0 1.57895 0C0.706919 0 0 0.706919 0 1.57895C0 2.45098 0.706919 3.15789 1.57895 3.15789C1.94336 3.15789 2.27894 3.03444 2.54615 2.82708L4.29666 4.56866C4.38556 4.47157 4.47881 4.37853 4.57611 4.28986ZM3.1623 7.30263H2.35205C2.25808 6.74256 1.77099 6.31579 1.18421 6.31579C0.530189 6.31579 0 6.84598 0 7.5C0 8.15402 0.530189 8.68421 1.18421 8.68421C1.77099 8.68421 2.25809 8.25744 2.35205 7.69737H3.1623C3.15937 7.63195 3.15789 7.56615 3.15789 7.5C3.15789 7.43386 3.15937 7.36805 3.1623 7.30263ZM4.29301 10.4273L2.54226 12.1699C2.27569 11.9644 1.9416 11.8421 1.57895 11.8421C0.706919 11.8421 0 12.549 0 13.4211C0 14.2931 0.706919 15 1.57895 15C2.45098 15 3.15789 14.2931 3.15789 13.4211C3.15789 13.0539 3.03261 12.7161 2.82248 12.4479L4.57211 10.7065C4.47492 10.6177 4.38178 10.5245 4.29301 10.4273ZM7.33964 11.8392V12.6423C6.76146 12.7206 6.31579 13.2162 6.31579 13.8158C6.31579 14.4698 6.84598 15 7.5 15C8.15402 15 8.68421 14.4698 8.68421 13.8158C8.68421 13.242 8.27613 12.7635 7.73438 12.6548V11.8359C7.65677 11.84 7.57863 11.8421 7.5 11.8421C7.44631 11.8421 7.39285 11.8411 7.33964 11.8392ZM10.4477 10.6883L12.1947 12.4264C11.9742 12.6979 11.8421 13.0441 11.8421 13.4211C11.8421 14.2931 12.549 15 13.4211 15C14.2931 15 15 14.2931 15 13.4211C15 12.549 14.2931 11.8421 13.4211 11.8421C13.0683 11.8421 12.7426 11.9578 12.4798 12.1532L10.7251 10.4074C10.6369 10.5052 10.5443 10.5989 10.4477 10.6883ZM11.8377 7.69737H12.648C12.7419 8.25744 13.229 8.68421 13.8158 8.68421C14.4698 8.68421 15 8.15402 15 7.5C15 6.84598 14.4698 6.31579 13.8158 6.31579C13.229 6.31579 12.7419 6.74256 12.648 7.30263H11.8377C11.8406 7.36805 11.8421 7.43386 11.8421 7.5C11.8421 7.56615 11.8406 7.63195 11.8377 7.69737ZM10.7202 4.58715L12.4735 2.84205C12.7374 3.04037 13.0655 3.15789 13.4211 3.15789C14.2931 3.15789 15 2.45098 15 1.57895C15 0.706919 14.2931 0 13.4211 0C12.549 0 11.8421 0.706919 11.8421 1.57895C11.8421 1.95312 11.9723 2.2969 12.1898 2.56747L10.4423 4.30675C10.5391 4.39598 10.6318 4.48954 10.7202 4.58715ZM13.4211 2.65789C14.0169 2.65789 14.5 2.17483 14.5 1.57895C14.5 0.983061 14.0169 0.5 13.4211 0.5C12.8252 0.5 12.3421 0.983061 12.3421 1.57895C12.3421 2.17483 12.8252 2.65789 13.4211 2.65789ZM1.57895 2.65789C2.17483 2.65789 2.65789 2.17483 2.65789 1.57895C2.65789 0.983061 2.17483 0.5 1.57895 0.5C0.983061 0.5 0.5 0.983061 0.5 1.57895C0.5 2.17483 0.983061 2.65789 1.57895 2.65789ZM14.5 13.4211C14.5 14.0169 14.0169 14.5 13.4211 14.5C12.8252 14.5 12.3421 14.0169 12.3421 13.4211C12.3421 12.8252 12.8252 12.3421 13.4211 12.3421C14.0169 12.3421 14.5 12.8252 14.5 13.4211ZM1.57895 14.5C2.17483 14.5 2.65789 14.0169 2.65789 13.4211C2.65789 12.8252 2.17483 12.3421 1.57895 12.3421C0.983061 12.3421 0.5 12.8252 0.5 13.4211C0.5 14.0169 0.983061 14.5 1.57895 14.5Z" fill="black"/>
+<g clip-path="url(#clip0)">
+<path d="M7.50009 7.50009C7.93627 7.50009 8.28956 7.1468 8.28956 6.71062C8.28956 6.27443 7.93627 5.92114 7.50009 5.92114C7.06391 5.92114 6.71062 6.27443 6.71062 6.71062C6.71062 7.1468 7.06391 7.50009 7.50009 7.50009ZM7.50009 7.89483C6.97312 7.89483 5.92114 8.1593 5.92114 8.6843V9.07904H9.07904V8.6843C9.07904 8.1593 8.02706 7.89483 7.50009 7.89483Z" fill="black"/>
+</g>
+<defs>
+<clipPath id="clip0">
+<rect width="4.73684" height="4.73684" fill="white" transform="translate(5.13159 5.13159)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/password.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/password.svg
new file mode 100644
index 00000000..975e1389
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/password.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <g><path d="M0,0h24v24H0V0z" fill="none"/></g>
+  <g><g><path d="M2,17h20v2H2V17z M3.15,12.95L4,11.47l0.85,1.48l1.3-0.75L5.3,10.72H7v-1.5H5.3l0.85-1.47L4.85,7L4,8.47L3.15,7l-1.3,0.75 L2.7,9.22H1v1.5h1.7L1.85,12.2L3.15,12.95z M9.85,12.2l1.3,0.75L12,11.47l0.85,1.48l1.3-0.75l-0.85-1.48H15v-1.5h-1.7l0.85-1.47 L12.85,7L12,8.47L11.15,7l-1.3,0.75l0.85,1.47H9v1.5h1.7L9.85,12.2z M23,9.22h-1.7l0.85-1.47L20.85,7L20,8.47L19.15,7l-1.3,0.75 l0.85,1.47H17v1.5h1.7l-0.85,1.48l1.3,0.75L20,11.47l0.85,1.48l1.3-0.75l-0.85-1.48H23V9.22z"/></g></g>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/permission.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/permission.svg
new file mode 100644
index 00000000..2af8561c
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/permission.svg
@@ -0,0 +1,4 @@
+<svg width="22" height="13" viewBox="0 0 22 13" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17.05 12.1H17.6V10.45C17.6 9.17584 16.1176 8.26879 14.4431 7.7321C15.357 7.43608 16.3509 7.2876 17.05 7.2876C18.7021 7.2876 22 8.11672 22 9.7626L22 12.1001H17.05H12.1V12.1H17.05ZM9.9 12.1H4.95H4.4V10.45C4.4 9.17584 5.88238 8.26879 7.55691 7.7321C6.64297 7.43608 5.64912 7.2876 4.95 7.2876C3.29794 7.2876 0 8.11672 0 9.7626V12.1001H4.95H9.9V12.1ZM4.95 6.0501C6.31744 6.0501 7.425 4.94254 7.425 3.5751C7.425 2.20766 6.31744 1.1001 4.95 1.1001C3.58256 1.1001 2.475 2.20766 2.475 3.5751C2.475 4.94254 3.58256 6.0501 4.95 6.0501ZM17.05 6.0501C18.4174 6.0501 19.525 4.94254 19.525 3.5751C19.525 2.20766 18.4174 1.1001 17.05 1.1001C15.6826 1.1001 14.575 2.20766 14.575 3.5751C14.575 4.94254 15.6826 6.0501 17.05 6.0501Z" fill="black"/>
+<path d="M11 6.05C12.6713 6.05 14.025 4.69631 14.025 3.025C14.025 1.35369 12.6713 0 11 0C9.32864 0 7.97495 1.35369 7.97495 3.025C7.97495 4.69631 9.32864 6.05 11 6.05ZM11 7.5625C8.98076 7.5625 4.94995 8.57588 4.94995 10.5875V12.1H17.05V10.5875C17.05 8.57588 13.0191 7.5625 11 7.5625Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/radius-group.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/radius-group.svg
new file mode 100644
index 00000000..e021a5c1
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/radius-group.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <g><rect fill="none" height="24" width="24"/></g><g><g/><g><g>
+  <path d="M16.67,13.13C18.04,14.06,19,15.32,19,17v3h4v-3 C23,14.82,19.43,13.53,16.67,13.13z" fill-rule="evenodd"/></g><g><circle cx="9" cy="8" fill-rule="evenodd" r="4"/></g><g>
+  <path d="M15,12c2.21,0,4-1.79,4-4c0-2.21-1.79-4-4-4c-0.47,0-0.91,0.1-1.33,0.24 C14.5,5.27,15,6.58,15,8s-0.5,2.73-1.33,3.76C14.09,11.9,14.53,12,15,12z" fill-rule="evenodd"/></g><g>
+  <path d="M9,13c-2.67,0-8,1.34-8,4v3h16v-3C17,14.34,11.67,13,9,13z" fill-rule="evenodd"/></g></g></g>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/radius.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/radius.svg
new file mode 100644
index 00000000..34856eeb
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/radius.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g>
+  <rect fill="none" height="24" width="24"/></g><g><g>
+  <path d="M17,11c0.34,0,0.67,0.04,1,0.09V6.27L10.5,3L3,6.27v4.91c0,4.54,3.2,8.79,7.5,9.82c0.55-0.13,1.08-0.32,1.6-0.55 C11.41,19.47,11,18.28,11,17C11,13.69,13.69,11,17,11z"/><path d="M17,13c-2.21,0-4,1.79-4,4c0,2.21,1.79,4,4,4s4-1.79,4-4C21,14.79,19.21,13,17,13z M17,14.38c0.62,0,1.12,0.51,1.12,1.12 s-0.51,1.12-1.12,1.12s-1.12-0.51-1.12-1.12S16.38,14.38,17,14.38z M17,19.75c-0.93,0-1.74-0.46-2.24-1.17 c0.05-0.72,1.51-1.08,2.24-1.08s2.19,0.36,2.24,1.08C18.74,19.29,17.93,19.75,17,19.75z"/></g></g>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/replies.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/replies.svg
new file mode 100644
index 00000000..1aaac24f
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/replies.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0z" fill="none"/>
+  <path d="M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/subnet.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/subnet.svg
new file mode 100644
index 00000000..43493a96
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/subnet.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C12 2.74028 11.5978 3.38663 11 3.73244V4.55556L19 9L18.934 9.03299L19.0244 9.03333L19.0049 14.2704C19.6 14.6169 20 15.2617 20 16C20 17.1046 19.1046 18 18 18C16.8954 18 16 17.1046 16 16C16 15.2577 16.4044 14.6098 17.0049 14.2647L17.0208 9.98959L17 10L11 6.57143V14.2676C11.5978 14.6134 12 15.2597 12 16C12 17.1046 11.1046 18 10 18C8.89543 18 8 17.1046 8 16C8 15.2597 8.4022 14.6134 9 14.2676V6.57143L3.02074 9.98815L3.00479 14.2703C3.59995 14.6168 4 15.2617 4 16C4 17.1046 3.10457 18 2 18C0.895431 18 0 17.1046 0 16C0 15.2577 0.404352 14.6099 1.0048 14.2648L1.02436 9.01218L1 9L1.02446 8.98641L1.02454 8.96606L1.06084 8.9662L9 4.55556V3.73244C8.4022 3.38663 8 2.74028 8 2C8 0.895431 8.89543 0 10 0C11.1046 0 12 0.895431 12 2Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/template.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/template.svg
new file mode 100644
index 00000000..e64c8703
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/template.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0z" fill="none"/>
+  <path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/token.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/token.svg
new file mode 100644
index 00000000..a04af904
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/token.svg
@@ -0,0 +1,4 @@
+<svg width="23" height="24" viewBox="0 0 23 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path d="M6.52224 8.61598C6.58317 8.88532 6.8509 9.05426 7.12024 8.99333C7.38957 8.9324 7.55852 8.66467 7.49759 8.39533L6.52224 8.61598ZM20.5363 15.5792L20.9444 15.868L20.9444 15.868L20.5363 15.5792ZM16.796 18.8342L16.6052 18.372L16.6052 18.372L16.796 18.8342ZM16.5646 18.3888C16.3093 18.4941 16.1878 18.7865 16.2932 19.0417C16.3986 19.297 16.6909 19.4185 16.9462 19.3131L16.5646 18.3888ZM7.49759 8.39533C7.27217 7.39886 7.24327 5.8947 7.85106 4.62134C8.43819 3.39127 9.6506 2.30631 12.0779 2.13654L12.0081 1.13898C9.24809 1.33202 7.7021 2.61194 6.9486 4.19058C6.21575 5.72594 6.26397 7.47433 6.52224 8.61598L7.49759 8.39533ZM12.0779 2.13654C15.0897 1.9259 18.0843 3.82482 19.8411 6.53515C21.5932 9.23806 22.0274 12.6068 20.1282 15.2903L20.9444 15.868C23.1505 12.751 22.5802 8.92225 20.6803 5.99122C18.7852 3.06763 15.4805 0.896125 12.0081 1.13898L12.0779 2.13654ZM20.1282 15.2903C19.2789 16.4903 18.7341 17.1096 18.2476 17.5024C17.7694 17.8883 17.3274 18.0739 16.6052 18.372L16.9868 19.2963C17.6966 19.0033 18.2693 18.77 18.8757 18.2805C19.4736 17.7978 20.083 17.0852 20.9444 15.868L20.1282 15.2903ZM16.6052 18.372L16.5646 18.3888L16.9462 19.3131L16.9868 19.2963L16.6052 18.372Z" fill="black"/>
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M3.77876 6.90353C4.11638 5.8562 5.23613 5.27908 6.28401 5.6098C6.18034 6.18109 6.14839 6.7387 6.16393 7.24334C5.7541 7.5111 5.48329 7.97393 5.48329 8.49999C5.48329 9.32842 6.15486 9.99999 6.98329 9.99999C7.81172 9.99999 8.48329 9.32842 8.48329 8.49999C8.48329 7.91583 8.14934 7.40966 7.66194 7.16195C7.6533 6.81976 7.67198 6.45086 7.72749 6.0751L14.968 8.40914C16.0192 8.74804 16.5968 9.87502 16.2579 10.9263L12.5761 22.3476C12.2373 23.3988 11.1102 23.9763 10.059 23.6374L1.38692 20.8419C0.335617 20.503 -0.241898 19.3761 0.097 18.3248L3.77876 6.90353ZM6.04185 18.6833L6.283 18.0761L5.95216 17.9447L5.3109 19.5594L5.64171 19.6907L5.87962 19.0917L7.53099 19.7476L7.69322 19.3392L6.04185 18.6833ZM8.18489 16.8392C8.06526 16.7119 7.90788 16.6094 7.71275 16.5319L7.62425 16.4968C7.43004 16.4196 7.24489 16.3871 7.06883 16.3991C6.89223 16.4099 6.73885 16.464 6.60872 16.5615C6.47801 16.6578 6.37987 16.7885 6.31425 16.9537C6.24864 17.1189 6.23018 17.2818 6.25887 17.4424C6.287 17.6017 6.36143 17.7463 6.48216 17.8762C6.60234 18.0049 6.75999 18.108 6.95515 18.1854L7.05318 18.2244C7.24413 18.2992 7.42717 18.3304 7.60231 18.318C7.77657 18.3052 7.92876 18.2501 8.05891 18.1526C8.18904 18.055 8.28676 17.9242 8.352 17.7599C8.41795 17.5938 8.43642 17.4309 8.40736 17.2712C8.37871 17.1106 8.30455 16.9666 8.18489 16.8392ZM6.94041 16.8336C7.07799 16.8021 7.25069 16.8276 7.45851 16.9101L7.55519 16.9485C7.76085 17.0312 7.90309 17.1308 7.98189 17.2472C8.0598 17.3633 8.07152 17.4898 8.01707 17.6269C7.96156 17.7666 7.86324 17.8516 7.72203 17.8816C7.58083 17.9117 7.40904 17.8866 7.20665 17.8062L7.11 17.7678C6.90431 17.6851 6.76317 17.5854 6.68654 17.4688C6.60899 17.3519 6.59746 17.2248 6.65187 17.0878C6.70668 16.9499 6.80284 16.8651 6.94041 16.8336ZM8.37267 15.9776L8.22829 15.6744L9.22557 15.481L9.41862 14.995L8.02959 15.2818L7.4283 14.2281L7.22877 14.7305L7.68028 15.4945L7.85533 15.7721L6.9568 15.4152L6.7946 15.8237L8.77678 16.6109L8.93901 16.2025L8.37267 15.9776ZM8.78288 14.0915L9.09434 13.3073L8.7744 13.1803L8.46297 13.9644L7.99055 13.7768L8.355 12.8592L8.02415 12.7278L7.49751 14.0539L9.47972 14.8411L10.0075 13.5124L9.6794 13.3821L9.31383 14.3024L8.78288 14.0915ZM10.5806 12.0693L10.7428 11.6609L8.7606 10.8736L8.59895 11.2807L9.9059 11.7998L8.28264 12.0771L8.12041 12.4855L10.1026 13.2728L10.2648 12.8644L8.96062 12.3464L10.5806 12.0693ZM8.43864 20.7966L11.981 11.9999L12.8184 12.337L9.27596 21.1338L8.43864 20.7966Z" fill="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/user-and-org.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/user-and-org.svg
new file mode 100644
index 00000000..4f84d05a
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/user-and-org.svg
@@ -0,0 +1,12 @@
+<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0)">
+<path d="M11 6C12.3812 6 13.5 4.88125 13.5 3.5C13.5 2.11875 12.3812 1 11 1C9.61875 1 8.5 2.11875 8.5 3.5C8.5 4.88125 9.61875 6 11 6ZM11 7.25C9.33125 7.25 6 8.0875 6 9.75V10.375C6 10.7187 6.28125 11 6.625 11H15.375C15.7187 11 16 10.7187 16 10.375V9.75C16 8.0875 12.6687 7.25 11 7.25Z" fill="black"/>
+</g>
+<path d="M10.9844 12V16.5M19.5 16.5V14H2.5V16.5" stroke="black" stroke-linejoin="round"/>
+<path d="M21.5 19.45C21.5 20.5546 20.6046 21.45 19.5 21.45C18.3954 21.45 17.5 20.5546 17.5 19.45C17.5 18.3455 18.3954 17.45 19.5 17.45C20.6046 17.45 21.5 18.3455 21.5 19.45ZM13 19.45C13 20.5545 12.1046 21.45 11 21.45C9.89543 21.45 9 20.5545 9 19.45C9 18.3454 9.89543 17.45 11 17.45C12.1046 17.45 13 18.3454 13 19.45ZM4.5 19.45C4.5 20.5546 3.60457 21.45 2.5 21.45C1.39543 21.45 0.5 20.5546 0.5 19.45C0.5 18.3454 1.39543 17.45 2.5 17.45C3.60457 17.45 4.5 18.3454 4.5 19.45Z" stroke="black"/>
+<defs>
+<clipPath id="clip0">
+<rect width="14" height="14" fill="white" transform="translate(3)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/user.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/user.svg
index bdeff17a..8f289adb 100644
--- a/openwisp_utils/admin_theme/static/ui/openwisp/images/user.svg
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/user.svg
@@ -1,3 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
-  <path fill="#fff" d="M4 0c-1.1 0-2 1.12-2 2.5s.9 2.5 2 2.5 2-1.12 2-2.5-.9-2.5-2-2.5zm-2.09 5c-1.06.05-1.91.92-1.91 2v1h8v-1c0-1.08-.84-1.95-1.91-2-.54.61-1.28 1-2.09 1-.81 0-1.55-.39-2.09-1z" />
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0V0z" fill="none"/><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v1c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-1c0-2.66-5.33-4-8-4z"/>
 </svg>
diff --git a/openwisp_utils/admin_theme/static/ui/openwisp/images/vpn.svg b/openwisp_utils/admin_theme/static/ui/openwisp/images/vpn.svg
new file mode 100644
index 00000000..33914d26
--- /dev/null
+++ b/openwisp_utils/admin_theme/static/ui/openwisp/images/vpn.svg
@@ -0,0 +1,9 @@
+<svg width="23" height="13" viewBox="0 0 23 13" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="1.5" y="0.5" width="20" height="5" rx="0.5" stroke="black"/>
+<path d="M8.97852 3.47119L9.46191 1.86719H9.95117L9.2085 4H8.75L8.01025 1.86719H8.49805L8.97852 3.47119ZM10.5928 3.24854V4H10.1533V1.86719H10.9854C11.1455 1.86719 11.2861 1.89648 11.4072 1.95508C11.5293 2.01367 11.623 2.09717 11.6885 2.20557C11.7539 2.31299 11.7866 2.43555 11.7866 2.57324C11.7866 2.78223 11.7148 2.94727 11.5713 3.06836C11.4287 3.18848 11.231 3.24854 10.978 3.24854H10.5928ZM10.5928 2.89258H10.9854C11.1016 2.89258 11.1899 2.86523 11.2505 2.81055C11.312 2.75586 11.3428 2.67773 11.3428 2.57617C11.3428 2.47168 11.312 2.38721 11.2505 2.32275C11.189 2.2583 11.104 2.2251 10.9956 2.22314H10.5928V2.89258ZM13.8242 4H13.3848L12.5293 2.59668V4H12.0898V1.86719H12.5293L13.3862 3.27344V1.86719H13.8242V4Z" fill="black"/>
+<path d="M5 6H18V6.5C18 6.77614 17.7761 7 17.5 7H5.5C5.22386 7 5 6.77614 5 6.5V6Z" fill="black"/>
+<circle cx="11" cy="11" r="1" stroke="black" stroke-width="0.5"/>
+<circle cx="2" cy="11" r="1" stroke="black" stroke-width="0.5"/>
+<circle cx="21" cy="11" r="1" stroke="black" stroke-width="0.5"/>
+<path d="M11 6V10M12 11H16H20M3 11H10" stroke="black"/>
+</svg>
diff --git a/openwisp_utils/admin_theme/templates/admin/base.html b/openwisp_utils/admin_theme/templates/admin/base.html
new file mode 100644
index 00000000..67ad5b60
--- /dev/null
+++ b/openwisp_utils/admin_theme/templates/admin/base.html
@@ -0,0 +1,96 @@
+{% load i18n static %}<!DOCTYPE html>
+{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %}
+<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" dir="{{ LANGUAGE_BIDI|yesno:'rtl,ltr,auto' }}">
+<head>
+<title>{% block title %}{% endblock %}</title>
+<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}">
+{% if not is_popup and is_nav_sidebar_enabled %}
+  <link rel="stylesheet" type="text/css" href="{% static "admin/css/nav_sidebar.css" %}">
+  <script src="{% static 'admin/js/nav_sidebar.js' %}" defer></script>
+{% endif %}
+{% block extrastyle %}{% endblock %}
+{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}">{% endif %}
+{% block extrahead %}{% endblock %}
+{% block responsive %}
+    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
+    <link rel="stylesheet" type="text/css" href="{% static "admin/css/responsive.css" %}">
+    {% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% static "admin/css/responsive_rtl.css" %}">{% endif %}
+{% endblock %}
+{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE">{% endblock %}
+</head>
+
+<body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}"
+  data-admin-utc-offset="{% now "Z" %}">
+
+<!-- Container -->
+<div id="container" class="toggle-menu {% if not user.is_authenticated %}no-auth{% endif %}" >
+  <div class="menu-backdrop"></div>
+  {% if not is_popup %}
+    <div id="menu">
+      <div class="menu-bar">
+        {% block menu-bar %}{% endblock %}
+      </div>
+      {% if user.is_authenticated  %}
+      {% block menu %}{% endblock %}
+      {% endif %}
+    </div>
+  {% endif %}
+  <div id="main-content" {% if not user.is_authenticated %}class="m-0"{% endif %}>
+    {% if not is_popup %}
+    <!-- Header -->
+    {% block header %}
+      <div id="header">
+        {% block nav-global %}{% endblock %}
+        {% if user.is_authenticated %}
+          <div id="ow-user-tools">
+          {% block user-tools %}{% endblock  %}
+          </div>
+        {% else %}
+        {% endif %}
+      </div>
+    {% endblock %}
+    <!-- END Header -->
+    {% block breadcrumbs %}
+    <div class="breadcrumbs">
+    <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+    {% if title %} &rsaquo; {{ title }}{% endif %}
+    </div>
+    {% endblock %}
+    {% endif %}
+    <div class="main" id="main">
+      {% if not is_popup and is_nav_sidebar_enabled %}
+        {% block nav-sidebar %}
+          {% include "admin/nav_sidebar.html" %}
+        {% endblock %}
+      {% endif %}
+      <div class="content">
+        {% block messages %}
+          {% if messages %}
+            <ul class="messagelist">{% for message in messages %}
+              <li {% if message.tags %}class="{{ message.tags }}"{% endif %}>{{ message|capfirst }}</li>
+            {% endfor %}</ul>
+          {% endif %}
+        {% endblock messages %}
+        <!-- Content -->
+        <div id="content" class="{% block coltype %}colM{% endblock %}">
+          <div class="title-wrapper">
+            {% block pretitle %}{% endblock %}
+            {% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
+            {% block content_subtitle %}{% if subtitle %}<h2>{{ subtitle }}</h2>{% endif %}{% endblock %}
+            {% block object-tools %}{% endblock %}
+          </div>
+          {% block content %}
+            {{ content }}
+          {% endblock %}
+          {% block sidebar %}{% endblock %}
+          <br class="clear">
+        </div>
+        <!-- END Content -->
+        {% block footer %}<div id="footer"></div>{% endblock %}
+      </div>
+    </div>
+    </div>
+</div>
+<!-- END Container -->
+</body>
+</html>
diff --git a/openwisp_utils/admin_theme/templates/admin/base_site.html b/openwisp_utils/admin_theme/templates/admin/base_site.html
index 87c034d1..aa1f35d0 100644
--- a/openwisp_utils/admin_theme/templates/admin/base_site.html
+++ b/openwisp_utils/admin_theme/templates/admin/base_site.html
@@ -1,4 +1,4 @@
-{% extends "admin/base.html" %}
+{% extends "base.html" %}
 {% load static i18n %}
 
 {% block title %}{{ title }} | {{ site_title }}{% endblock %}
@@ -16,46 +16,42 @@
 {% endif %}
 {% endblock %}
 
-{% block branding %}
-<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header }}</a></h1>
+{% block menu-bar %}
+  <div class="head">
+    <span class="hamburger"><span></span></span>
+    <h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header }}</a></h1>
+  </div>
 {% endblock %}
 
-{% block welcome-msg %}
-    <span class="user">
+{% block user-tools %}
+  <div  class="account">
+    <button title="account" type="button" class="account-button toggle-btn tooltip-sm">
+      <span class="user"></span>
+      <strong>{% firstof user.get_short_name user.get_username %}</strong>
+    </button>
+    <ul class="account-menu hide">
+      <li class="account-menu-username">
+        <span class="user"></span>
         <strong>{% firstof user.get_short_name user.get_username %}</strong>
-    </span>
-{% endblock %}
-{% block userlinks %}
-  {% if show_userlinks_block %}
-    {{ block.super }}
-  {% endif %}
-{% endblock %}
-
-{% block nav-global %}
-{% if has_permission %}
-<label for="menu-toggle" tabindex="-1" id="nav-activate">
-    <img class="nav-icon" src="{% static "ui/openwisp/images/menu.svg" %}" alt="" />
-</label>
-<input type="checkbox" id="menu-toggle" tabindex="-1" />
-
-<div id="main-menu">
-    <a href="{% url 'admin:index' %}"
-       class="home">{% trans 'Home' %}</a>
-    {% for item in openwisp_menu_items %}
-    <a href="{{ item.url }}"
-       class="{{ item.class }}">{{ item.label }}</a>
-    {% endfor %}
-    <div class="account">
-        {% if user.has_usable_password %}
-        <a href="{% url 'admin:password_change' %}"
-           class="change-password">{% trans 'Change password' %}</a>
-        {% endif %}
-        <a href="{% url 'admin:logout' %}"
-           class="logout">{% trans 'Log out' %}</a>
-    </div>
-</div>
-{% endif %}
-{% endblock %}
+      </li>
+      {% if user.has_usable_password %}
+      <li>
+        <a href="{% url 'admin:password_change' %}">
+          <span class="password"></span>
+          {% trans 'Change password' %}
+        </a>
+      </li>
+      {% endif %}
+      <li>
+        <a class="menu-link" href="{% url 'admin:logout' %}">
+          <span class="logout"></span>
+          {% trans 'Log out' %}
+        </a>
+      </li>
+    </ul>
+  </div>
+{% endblock  %}
+{% block menu %}{% include "./menu.html" %}{% endblock %}
 
 {% block footer %}
 <div id="ow-loading" class="ow-overlay">
@@ -63,6 +59,7 @@ <h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header }}</a></h1>
     <div class="ow-loading-spinner"></div>
   </div>
 </div>
+
 {% comment %}
     we need to put the JS here otherwise
     if we put it in extrahead it will be
diff --git a/openwisp_utils/admin_theme/templates/admin/index.html b/openwisp_utils/admin_theme/templates/admin/index.html
index 897c7f7b..eec2c5ef 100644
--- a/openwisp_utils/admin_theme/templates/admin/index.html
+++ b/openwisp_utils/admin_theme/templates/admin/index.html
@@ -21,12 +21,6 @@
 {{ block.super }}
 
 {% if not app_label and dashboard_enabled %}
-<div id="quick-menu">
-  {% for item in openwisp_menu_items %}
-  <a href="{{ item.url }}"
-     class="button {{ item.class }}">{{ item.label }}</a>
-  {% endfor %}
-</div>
 
 {% for template in dashboard_templates %}
 {% include template %}
diff --git a/openwisp_utils/admin_theme/templates/admin/menu.html b/openwisp_utils/admin_theme/templates/admin/menu.html
new file mode 100644
index 00000000..845624c2
--- /dev/null
+++ b/openwisp_utils/admin_theme/templates/admin/menu.html
@@ -0,0 +1,35 @@
+{% load i18n %}
+<button class="menu-toggle">
+  <span></span>
+</button>
+<div class="nav">
+  {% for item in openwisp_menu_groups %} {% if item.sub_items %}
+  <div class="menu-group">
+    <div class="mg-head">
+      <div class="mg-heading">
+        <span class="{{ item.icon }} icon"></span>
+        <span class="label">{{ item.label }}</span>
+      </div>
+      <span class="mg-arrow"></span>
+    </div>
+    <div class="mg-dropdown">
+      <div class="mg-dropdown-label">{{ item.label }}</div>
+      <ul class="mg-list">
+        {% for sub_item in item.sub_items %}
+        <li>
+          <a class="mg-link" href="{{ sub_item.url }}">
+            <span class="{{ sub_item.icon }} icon"></span>
+            <span class="label">{{ sub_item.label }}</span>
+          </a>
+        </li>
+        {% endfor %}
+      </ul>
+    </div>
+  </div>
+  {% else %}
+  <a class="menu-item" href="{{ item.url }}">
+    <span class="{{ item.icon }} icon"></span>
+    <span class="label">{{ item.label }}</span>
+  </a>
+  {% endif %} {% endfor %}
+</div>


Test patch:
diff --git a/tests/settings.py b/tests/settings.py
index 515afe96..f0e7a0b7 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -67,7 +67,7 @@
                 'django.template.context_processors.request',
                 'django.contrib.auth.context_processors.auth',
                 'django.contrib.messages.context_processors.messages',
-                'openwisp_utils.admin_theme.context_processor.menu_items',
+                'openwisp_utils.admin_theme.context_processor.menu_groups',
                 'openwisp_utils.admin_theme.context_processor.admin_theme_settings',
             ],
         },
@@ -99,6 +99,26 @@
 CACHES = {'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}}
 OPENWISP_TEST_ADMIN_MENU_ITEMS = [{'model': 'test_project.Project'}]
 
+OPENWISP_ADMIN_THEME_LINKS = [
+    {
+        'type': 'text/css',
+        'href': '/static/admin/css/openwisp.css',
+        'rel': 'stylesheet',
+        'media': 'all',
+    },
+    {
+        'type': 'text/css',
+        'href': '/static/menu-test.css',
+        'rel': 'stylesheet',
+        'media': 'all',
+    },  # custom css for testing menu icons
+    {
+        'type': 'image/x-icon',
+        'href': '/static/ui/openwisp/images/favicon.png',
+        'rel': 'icon',
+    },
+]
+
 # local settings must be imported before test runner otherwise they'll be ignored
 try:
     from local_settings import *
diff --git a/tests/test_project/apps.py b/tests/test_project/apps.py
index 2f5b81e9..5a1a4833 100644
--- a/tests/test_project/apps.py
+++ b/tests/test_project/apps.py
@@ -4,6 +4,7 @@
     register_dashboard_chart,
     register_dashboard_template,
 )
+from openwisp_utils.admin_theme.menu import register_menu_group
 from openwisp_utils.api.apps import ApiAppConfig
 from openwisp_utils.utils import register_menu_items
 
@@ -22,6 +23,7 @@ def ready(self, *args, **kwargs):
         super().ready(*args, **kwargs)
         self.register_default_menu_items()
         self.register_dashboard_charts()
+        self.register_menu_groups()
 
     def register_default_menu_items(self):
         items = [{'model': 'test_project.Shelf'}]
@@ -87,3 +89,50 @@ def register_dashboard_charts(self):
             },
             extra_config={'test_extra_config': 'dashboard-test.config'},
         )
+
+    def register_menu_groups(self):
+        auth_config = {
+            'label': _('Authentication And Authorization'),
+            'items': {
+                2: {
+                    'label': 'Add user',
+                    'model': 'auth.User',
+                    'name': 'add',
+                    'icon': 'add-user',
+                },
+                1: {
+                    'model': 'auth.User',
+                    'name': 'changelist',
+                    'icon': 'user',
+                    'label': _('Users'),
+                },
+            },
+            'icon': 'auth',
+        }
+        docs_config = {
+            'label': _('Docs'),
+            'items': {
+                1: {
+                    'label': _('OpenWISP'),
+                    'url': 'https://openwisp.org/',
+                    'icon': 'link',
+                },
+                2: {
+                    'label': _('Code'),
+                    'url': 'https://openwisp.org/thecode.html',
+                    'icon': 'code',
+                },
+            },
+            'icon': 'docs',
+        }
+        register_menu_group(
+            position=31,
+            config={
+                'model': 'test_project.Shelf',
+                'name': 'changelist',
+                'label': _('Shelfs'),
+                'icon': 'shelf',
+            },
+        )
+        register_menu_group(position=32, config=auth_config)
+        register_menu_group(position=33, config=docs_config)
diff --git a/tests/test_project/static/icons/add-user.svg b/tests/test_project/static/icons/add-user.svg
new file mode 100644
index 00000000..678e5fca
--- /dev/null
+++ b/tests/test_project/static/icons/add-user.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0V0z" fill="none"/>
+  <path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V8c0-.55-.45-1-1-1s-1 .45-1 1v2H2c-.55 0-1 .45-1 1s.45 1 1 1h2v2c0 .55.45 1 1 1s1-.45 1-1v-2h2c.55 0 1-.45 1-1s-.45-1-1-1H6zm9 4c-2.67 0-8 1.34-8 4v1c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-1c0-2.66-5.33-4-8-4z"/>
+</svg>
diff --git a/tests/test_project/static/icons/auth.svg b/tests/test_project/static/icons/auth.svg
new file mode 100644
index 00000000..82a1a7a5
--- /dev/null
+++ b/tests/test_project/static/icons/auth.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <g><rect fill="none" height="24" width="24"/></g><g><g><path d="M17,11c0.34,0,0.67,0.04,1,0.09V6.27L10.5,3L3,6.27v4.91c0,4.54,3.2,8.79,7.5,9.82c0.55-0.13,1.08-0.32,1.6-0.55 C11.41,19.47,11,18.28,11,17C11,13.69,13.69,11,17,11z"/><path d="M17,13c-2.21,0-4,1.79-4,4c0,2.21,1.79,4,4,4s4-1.79,4-4C21,14.79,19.21,13,17,13z M17,14.38c0.62,0,1.12,0.51,1.12,1.12 s-0.51,1.12-1.12,1.12s-1.12-0.51-1.12-1.12S16.38,14.38,17,14.38z M17,19.75c-0.93,0-1.74-0.46-2.24-1.17 c0.05-0.72,1.51-1.08,2.24-1.08s2.19,0.36,2.24,1.08C18.74,19.29,17.93,19.75,17,19.75z"/></g></g>
+</svg>
diff --git a/tests/test_project/static/icons/code.svg b/tests/test_project/static/icons/code.svg
new file mode 100644
index 00000000..b2feaa2e
--- /dev/null
+++ b/tests/test_project/static/icons/code.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <path d="M0 0h24v24H0V0z" fill="none"/><path d="M8.7 15.9L4.8 12l3.9-3.9c.39-.39.39-1.01 0-1.4-.39-.39-1.01-.39-1.4 0l-4.59 4.59c-.39.39-.39 1.02 0 1.41l4.59 4.6c.39.39 1.01.39 1.4 0 .39-.39.39-1.01 0-1.4zm6.6 0l3.9-3.9-3.9-3.9c-.39-.39-.39-1.01 0-1.4.39-.39 1.01-.39 1.4 0l4.59 4.59c.39.39.39 1.02 0 1.41l-4.59 4.6c-.39.39-1.01.39-1.4 0-.39-.39-.39-1.01 0-1.4z"/>
+</svg>
diff --git a/tests/test_project/static/icons/docs.svg b/tests/test_project/static/icons/docs.svg
new file mode 100644
index 00000000..339cf9ab
--- /dev/null
+++ b/tests/test_project/static/icons/docs.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <g><rect fill="none" height="24" width="24"/><path d="M20.41,8.41l-4.83-4.83C15.21,3.21,14.7,3,14.17,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V9.83 C21,9.3,20.79,8.79,20.41,8.41z M7,7h7v2H7V7z M17,17H7v-2h10V17z M17,13H7v-2h10V13z"/></g>
+</svg>
diff --git a/tests/test_project/static/icons/link.svg b/tests/test_project/static/icons/link.svg
new file mode 100644
index 00000000..e38356fe
--- /dev/null
+++ b/tests/test_project/static/icons/link.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
+  <g><rect fill="none" height="24" width="24"/></g><g><g><path d="M17,7h-3c-0.55,0-1,0.45-1,1s0.45,1,1,1h3c1.65,0,3,1.35,3,3s-1.35,3-3,3h-3c-0.55,0-1,0.45-1,1c0,0.55,0.45,1,1,1h3 c2.76,0,5-2.24,5-5S19.76,7,17,7z M8,12c0,0.55,0.45,1,1,1h6c0.55,0,1-0.45,1-1s-0.45-1-1-1H9C8.45,11,8,11.45,8,12z M10,15H7 c-1.65,0-3-1.35-3-3s1.35-3,3-3h3c0.55,0,1-0.45,1-1s-0.45-1-1-1H7c-2.76,0-5,2.24-5,5s2.24,5,5,5h3c0.55,0,1-0.45,1-1 C11,15.45,10.55,15,10,15z"/></g></g>
+</svg>
diff --git a/tests/test_project/static/icons/shelf.svg b/tests/test_project/static/icons/shelf.svg
new file mode 100644
index 00000000..e83d6067
--- /dev/null
+++ b/tests/test_project/static/icons/shelf.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/>
+  <path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9H9V9h10v2zm-4 4H9v-2h6v2zm4-8H9V5h10v2z"/>
+</svg>
diff --git a/tests/test_project/static/menu-test.css b/tests/test_project/static/menu-test.css
new file mode 100644
index 00000000..835cd281
--- /dev/null
+++ b/tests/test_project/static/menu-test.css
@@ -0,0 +1,24 @@
+.auth {
+  mask-image: url("./icons/auth.svg");
+  -webkit-mask-image: url("./icons/auth.svg");
+}
+.shelf {
+  mask-image: url("./icons/shelf.svg");
+  -webkit-mask-image: url("./icons/shelf.svg");
+}
+.docs {
+  mask-image: url("./icons/docs.svg");
+  -webkit-mask-image: url("./icons/docs.svg");
+}
+.code {
+  mask-image: url("./icons/code.svg");
+  -webkit-mask-image: url("./icons/code.svg");
+}
+.link {
+  mask-image: url("./icons/link.svg");
+  -webkit-mask-image: url("./icons/link.svg");
+}
+.add-user {
+  mask-image: url("./icons/add-user.svg");
+  -webkit-mask-image: url("./icons/add-user.svg");
+}
diff --git a/tests/test_project/tests/test_admin.py b/tests/test_project/tests/test_admin.py
index 30ed815f..6cbefbe0 100644
--- a/tests/test_project/tests/test_admin.py
+++ b/tests/test_project/tests/test_admin.py
@@ -105,12 +105,12 @@ class TestReadOnlyAdmin(ReadOnlyAdmin):
     def test_context_processor(self):
         url = reverse('admin:index')
         response = self.client.get(url)
-        self.assertContains(response, 'class="shelf"')
+        self.assertContains(response, '<span class="shelf icon">')
 
     def test_superuser_always_sees_menu_items(self):
         url = reverse('admin:index')
         r = self.client.get(url)
-        self.assertContains(r, 'class="shelf"')
+        self.assertContains(r, '<span class="shelf icon">')
 
     def test_operator_with_perm_can_see_menu_item(self):
         user = User.objects.create(
@@ -126,7 +126,7 @@ def test_operator_with_perm_can_see_menu_item(self):
         self.client.force_login(user)
         url = reverse('admin:index')
         r = self.client.get(url)
-        self.assertContains(r, 'class="shelf"')
+        self.assertContains(r, '<span class="shelf icon">')
 
     def test_operator_without_perm_cant_see_menu_item(self):
         user = User.objects.create(
@@ -139,7 +139,18 @@ def test_operator_without_perm_cant_see_menu_item(self):
         self.client.force_login(user)
         url = reverse('admin:index')
         r = self.client.get(url)
-        self.assertNotContains(r, 'class="shelf"')
+        self.assertNotContains(r, '<span class="shelf icon">')
+
+    def test_menu_items_visibility(self):
+        with self.subTest("Test menu items are visible when user is logged in"):
+            url = reverse('admin:index')
+            response = self.client.get(url)
+            self.assertContains(response, 'class="nav"')
+
+        with self.subTest("Test menu items are not visible when user is not logged in"):
+            self.client.logout()
+            response = self.client.get('/admin/login/')
+            self.assertNotContains(response, 'id="nav"')
 
     def test_uuid_field_in_change(self):
         p = Project.objects.create(name='test-project')
diff --git a/tests/test_project/tests/test_menu.py b/tests/test_project/tests/test_menu.py
new file mode 100644
index 00000000..89b69753
--- /dev/null
+++ b/tests/test_project/tests/test_menu.py
@@ -0,0 +1,318 @@
+from unittest.mock import patch
+
+from django.apps import registry
+from django.contrib.auth import get_user_model
+from django.core.exceptions import ImproperlyConfigured
+from django.test import RequestFactory, TestCase
+from django.urls import reverse
+from openwisp_utils.admin_theme.menu import (
+    MenuGroup,
+    MenuLink,
+    ModelLink,
+    register_menu_group,
+)
+from openwisp_utils.utils import SortedOrderedDict
+
+
+class TestMenuSchema(TestCase):
+    factory = RequestFactory()
+
+    def _get_model_link_config(
+        self,
+        label='test label',
+        model='test_project.Shelf',
+        name='add',
+        icon='test_icon',
+    ):
+        return {'label': label, 'model': model, 'name': name, 'icon': icon}
+
+    def _get_menu_link_config(
+        self, label='test label', url='testurl.com', icon='test-icon'
+    ):
+        return {'label': label, 'url': url, 'icon': icon}
+
+    def _get_menu_group_config(self, label='test label', items=None, icon='test icon'):
+        if items is None:
+            # set default items
+            model_link = self._get_model_link_config()
+            menu_link = self._get_menu_link_config()
+            items = {1: menu_link, 2: model_link}
+        return {
+            'label': label,
+            'items': items,
+            'icon': icon,
+        }
+
+    @patch('openwisp_utils.admin_theme.menu.MENU', SortedOrderedDict())
+    def test_register_menu_groups(self):
+
+        from openwisp_utils.admin_theme.menu import MENU
+
+        # create a menu
+        model_link_config = self._get_model_link_config()
+        menu_link_config = self._get_menu_link_config()
+        menu_group_config = self._get_menu_group_config()
+        test_menu_groups = {
+            3: menu_group_config,
+            2: model_link_config,
+            1: menu_link_config,
+        }
+        # save menu order to compare
+        items_order = [
+            MenuLink(config=menu_link_config),
+            ModelLink(config=model_link_config),
+            MenuGroup(config=menu_group_config),
+        ]
+        for position, config in test_menu_groups.items():
+            register_menu_group(position=position, config=config)
+
+        with self.subTest('Test ordering of menu groups'):
+            url = reverse('admin:index')
+            request = self.factory.get(url)
+            user = get_user_model().objects.create_superuser(
+                username='administrator', password='admin', email='test@test.org'
+            )
+            request.user = user
+            current_item_index = 0
+            for item in MENU.values():
+                item_context = item.get_context(request)
+                ordered_item_context = items_order[current_item_index].get_context(
+                    request
+                )
+                self.assertEqual(item_context, ordered_item_context)
+                current_item_index += 1
+
+        with self.subTest('Registering at an occupied position'):
+            with self.assertRaises(ImproperlyConfigured):
+                register_menu_group(position=1, config=model_link_config)
+
+        with self.subTest('Registering with invalid position'):
+            with self.assertRaises(ImproperlyConfigured):
+                register_menu_group(
+                    position='invalid_position', config=menu_link_config
+                )
+
+        with self.subTest('Registering with invalid config'):
+            with self.assertRaises(ImproperlyConfigured):
+                register_menu_group(position=-1, config=[])
+
+        with self.subTest('Registering with unknow menu group'):
+            with self.assertRaises(ImproperlyConfigured):
+                register_menu_group(position=-1, config={})
+
+    def test_menu_link(self):
+
+        with self.subTest('Menu Link with invalid config'):
+            with self.assertRaises(ImproperlyConfigured):
+                MenuLink(config=[])
+
+        with self.subTest('Menu Link without label'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_link_config(label=None)
+                MenuLink(config=_config)
+
+        with self.subTest('Menu Link without url'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_link_config(url=None)
+                MenuLink(config=_config)
+
+        with self.subTest('Menu Link with invalid url'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_link_config(url=123)
+                MenuLink(config=_config)
+
+        with self.subTest('Menu Link test create context'):
+            _config = self._get_menu_link_config()
+            menu_link = MenuLink(config=_config)
+            context = menu_link.create_context()
+            self.assertEqual(context.get('label'), _config['label'])
+            self.assertEqual(context.get('url'), _config['url'])
+            self.assertEqual(context.get('icon'), _config['icon'])
+
+        with self.subTest('Menu Link without icon'):
+            _config = self._get_menu_link_config(icon=None)
+            menu_link = MenuLink(config=_config)
+            context = menu_link.create_context()
+            self.assertEqual(context.get('icon'), None)
+
+    def test_model_link(self):
+
+        with self.subTest('Model Link without name'):
+            _config = self._get_model_link_config(name=None)
+            with self.assertRaises(ImproperlyConfigured):
+                ModelLink(config=_config)
+
+        with self.subTest('Model Link with invalid name'):
+            _config = self._get_model_link_config(name=123)
+            with self.assertRaises(ImproperlyConfigured):
+                ModelLink(config=_config)
+
+        with self.subTest('Model Link with invalid config'):
+            with self.assertRaises(ImproperlyConfigured):
+                ModelLink(config=[])
+
+        with self.subTest('Model Link without model'):
+            _config = self._get_model_link_config(model=None)
+            with self.assertRaises(ImproperlyConfigured):
+                ModelLink(config=_config)
+
+        with self.subTest('Model Link with invalid model'):
+            _config = self._get_model_link_config(model=123)
+            with self.assertRaises(ImproperlyConfigured):
+                ModelLink(config=_config)
+
+    def test_model_link_access(self):
+        url = reverse('admin:index')
+        request = self.factory.get(url)
+        user = get_user_model().objects.create_superuser(
+            username='administrator', password='admin', email='test@test.org'
+        )
+        request.user = user
+        _config = self._get_model_link_config()
+        model_link = ModelLink(config=_config)
+
+        with self.subTest('Model Link with label and icon'):
+            context = model_link.get_context(request=request)
+            self.assertEqual(context.get('label'), _config['label'])
+            self.assertEqual(context.get('icon'), _config['icon'])
+
+        with self.subTest('Model Link without label and icon'):
+            _config = self._get_model_link_config(label=None, icon=None)
+            model_link = ModelLink(config=_config)
+            context = model_link.get_context(request=request)
+            app_label, model = _config['model'].split('.')
+            model_class = registry.apps.get_model(app_label, model)
+            label = f'{model_class._meta.verbose_name_plural} {_config["name"]}'
+            self.assertEqual(context.get('label'), label)
+            self.assertEqual(context.get('icon'), None)
+
+        # testing with user having no access
+        user = get_user_model().objects.create(
+            username='operator',
+            password='pass',
+            email='email@email',
+            is_staff=True,
+            is_superuser=False,
+        )
+        request.user = user
+        with self.subTest('Model Link context when user do not have access'):
+            context = model_link.get_context(request)
+            self.assertEqual(context, None)
+
+    def test_menu_group(self):
+
+        with self.subTest('Menu Group with invalid config'):
+            with self.assertRaises(ImproperlyConfigured):
+                MenuGroup(config=[])
+
+        with self.subTest('Menu Group without label'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_group_config(label=None)
+                MenuGroup(config=_config)
+
+        with self.subTest('Menu Group without items'):
+            with self.assertRaises(ImproperlyConfigured):
+                MenuGroup(config={'label': "test label"})
+
+        with self.subTest('Menu Group with invalid items type'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_group_config(items=[])
+                MenuGroup(config=_config)
+
+        with self.subTest('Menu Group with unknown item'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_group_config(items={1: {}})
+                MenuGroup(config=_config)
+
+        with self.subTest('Menu Group with invalid items position'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_group_config(
+                    items={'1': self._get_menu_link_config()}
+                )
+                MenuGroup(config=_config)
+
+        with self.subTest('Menu Group with invalid items type'):
+            with self.assertRaises(ImproperlyConfigured):
+                _config = self._get_menu_group_config(items={1: []})
+                MenuGroup(config=_config)
+
+        url = reverse('admin:index')
+        request = self.factory.get(url)
+        user = get_user_model().objects.create_superuser(
+            username='administrator', password='admin', email='test@test.org'
+        )
+        request.user = user
+        with self.subTest('Menu Group items ordering test'):
+            link_config = self._get_menu_link_config()
+            model_link_config = self._get_model_link_config()
+            menu_group_items = {2: model_link_config, 1: link_config}
+            # save order
+            menu_group_items_order = [
+                MenuLink(config=link_config),
+                ModelLink(config=model_link_config),
+            ]
+            _config = self._get_menu_group_config(items=menu_group_items)
+            menu_group = MenuGroup(config=_config)
+            current_item_index = 0
+            for item in menu_group.items.values():
+                item_context = item.get_context(request)
+                ordered_item_context = menu_group_items_order[
+                    current_item_index
+                ].get_context(request)
+                self.assertEqual(item_context, ordered_item_context)
+                current_item_index += 1
+
+        with self.subTest('Menu Group with icon'):
+            _config = self._get_menu_group_config()
+            menu_group = MenuGroup(config=_config)
+            context = menu_group.get_context(request=request)
+            self.assertEqual(context.get('icon'), _config['icon'])
+
+        with self.subTest('Menu Group without icon'):
+            _config = self._get_menu_group_config(icon=None)
+            menu_group = MenuGroup(config=_config)
+            context = menu_group.get_context(request=request)
+            self.assertEqual(context.get('icon'), None)
+
+        with self.subTest(
+            'Test superuser access to all model links present in menu group'
+        ):
+            add_link_config = self._get_model_link_config(name='add')
+            change_link_config = self._get_model_link_config(name='changelist')
+            items = {1: add_link_config, 2: change_link_config}
+            menu_group_config = self._get_menu_group_config(items=items)
+            menu_group = MenuGroup(config=menu_group_config)
+            context = menu_group.create_context(request=request)
+            sub_items = context.get('sub_items')
+            self.assertEqual(len(sub_items), 2)
+
+        # testing with user having no access
+        user = get_user_model().objects.create(
+            username='operator',
+            password='pass',
+            email='email@email',
+            is_staff=True,
+            is_superuser=False,
+        )
+        request.user = user
+        with self.subTest('Menu Group content when user have no access of items'):
+            _items = {1: self._get_model_link_config()}
+            _config = self._get_menu_group_config(items=_items)
+            menu_group = MenuGroup(config=_config)
+            context = menu_group.get_context(request=request)
+            self.assertEqual(context, None)
+
+        with self.subTest('Menu Group content when user have no access of some items'):
+            link_config = (
+                self._get_menu_link_config()
+            )  # user have permission to see this link
+            _items = {1: self._get_model_link_config(), 2: link_config}
+            _config = self._get_menu_group_config(items=_items)
+            menu_group = MenuGroup(config=_config)
+            context = menu_group.get_context(request=request)
+            context_items = context.get('sub_items')
+            link = MenuLink(config=link_config)
+            link_context = link.get_context()
+            self.assertEqual(len(context_items), 1)
+            self.assertEqual(context_items[0].get('label'), link_context.get('label'))
+            self.assertEqual(context_items[0].get('url'), link_context.get('url'))