Verified Commit 88576b02 authored by Štěpán Henek's avatar Štěpán Henek 🌩

second level menu implemented

parent 3cd5901e
......@@ -22,8 +22,7 @@ import logging
import time
import uuid
from bottle import Bottle, request, template, response, jinja2_template
from urllib.parse import urlencode
from bottle import Bottle, request, template, response
import bottle
from foris import fapi
......@@ -43,10 +42,60 @@ from foris.state import current_state
logger = logging.getLogger(__name__)
class ConfigPageMixin(object):
# page url part /config/<slug>
slug: typing.Optional[str] = None
class BaseConfigPage(object):
menu_order = 50
slug: typing.Optional[str] = None
page_name: typing.Optional[str] = None
subpages: typing.Iterable[typing.Type['ConfigPageMixin']] = []
@staticmethod
def get_menu_tag_static(cls):
if current_state.guide.enabled and current_state.guide.current == cls.slug:
return {
"show": True,
"hint": "",
"text": "<i class='fas fa-reply'></i>",
}
else:
return {
"show": False,
"hint": "",
"text": "",
}
@classmethod
def get_menu_tag(cls):
return ConfigPageMixin.get_menu_tag_static(cls)
@staticmethod
def is_visible_static(cls):
if current_state.guide.enabled:
return cls.slug in current_state.guide.steps
return True
@classmethod
def is_visible(cls):
return ConfigPageMixin.is_visible_static(cls)
@staticmethod
def is_enabled_static(cls):
if current_state.guide.enabled:
return cls.slug in current_state.guide.available_tabs
return True
@classmethod
def is_enabled(cls):
return ConfigPageMixin.is_enabled_static(cls)
@classmethod
def subpage_slugs(cls):
return [e.slug for e in cls.subpages]
class ConfigPageMixin(BaseConfigPage):
# page url part /config/<slug>
template = "config/main"
template_type = "simple"
......@@ -114,46 +163,9 @@ class ConfigPageMixin(object):
messages.warning(_("There were some errors in your input."))
return result
@staticmethod
def get_menu_tag_static(cls):
if current_state.guide.enabled and current_state.guide.current == cls.slug:
return {
"show": True,
"hint": "",
"text": "<i class='fas fa-reply'></i>",
}
else:
return {
"show": False,
"hint": "",
"text": "",
}
@classmethod
def get_menu_tag(cls):
return ConfigPageMixin.get_menu_tag_static(cls)
@staticmethod
def is_visible_static(cls):
if current_state.guide.enabled:
return cls.slug in current_state.guide.steps
return True
@classmethod
def is_visible(cls):
return ConfigPageMixin.is_visible_static(cls)
@staticmethod
def is_enabled_static(cls):
if current_state.guide.enabled:
return cls.slug in current_state.guide.available_tabs
return True
@classmethod
def is_enabled(cls):
return ConfigPageMixin.is_enabled_static(cls)
class JoinedPages(BaseConfigPage):
userfriendly_title = None
class NotificationsConfigPage(ConfigPageMixin):
......@@ -434,10 +446,10 @@ class RemoteConfigPage(ConfigPageMixin, remote.RemoteHandler):
class SubordinatesConfigPage(ConfigPageMixin, subordinates.SubordinatesConfigHandler):
slug = "subordinates"
menu_order = 12
menu_order = 1 # submenu
template = "config/subordinates"
userfriendly_title = gettext("Managed devices")
userfriendly_title = gettext("Set up")
template_type = "jinja2"
def render(self, **kwargs):
......@@ -641,6 +653,15 @@ class SubordinatesConfigPage(ConfigPageMixin, subordinates.SubordinatesConfigHan
raise bottle.HTTPError(404, "No form '%s' not found." % form_name)
class SubordinatesJoinedPage(JoinedPages):
userfriendly_title = gettext("Managed devices")
name = "subordinates-main"
subpages: typing.Iterable[typing.Type['ConfigPageMixin']] = [
SubordinatesConfigPage,
]
class ProfileConfigPage(ConfigPageMixin, profile.ProfileHandler):
slug = "profile"
menu_order = 13
......@@ -1066,7 +1087,7 @@ config_pages = {
e.slug: e for e in [
NotificationsConfigPage,
RemoteConfigPage,
SubordinatesConfigPage,
SubordinatesJoinedPage,
PasswordConfigPage,
ProfileConfigPage,
NetworksConfigPage,
......@@ -1088,6 +1109,10 @@ def get_config_pages():
""" Returns sorted config pages
"""
res = sorted(config_pages.values(), key=lambda e: (e.menu_order, e.slug))
# sort subpages
for page in res:
page.subpages.sort(key=lambda e: (e.menu_order, e.slug))
return res
......@@ -1098,18 +1123,30 @@ def add_config_page(page_class):
"""
if page_class.slug is None:
raise Exception("Page %s doesn't define a propper slug" % page_class)
if page_class.slug in config_pages:
page_map = {k: v for k, v in config_pages.items()}
for page in config_pages.values():
for subpage in page.subpages:
page_map[subpage.slug] = subpage
if page_class.slug in page_map:
raise Exception("Error when adding page %s slug '%s' is already used in %s" % (
page_class, page_class.slug, config_pages[page_class.slug]
page_class, page_class.slug, page_map[page_class.slug]
))
config_pages[page_class.slug] = page_class
def get_config_page(page_name):
ConfigPage = config_pages.get(page_name, None)
if ConfigPage is None:
raise bottle.HTTPError(404, "Unknown configuration page.")
return ConfigPage
if ConfigPage:
return ConfigPage
# Try to iterate through subpages
for page in config_pages.values():
for subpage in page.subpages:
if subpage.slug == page_name:
return subpage
raise bottle.HTTPError(404, "Unknown configuration page.")
def _redirect_to_default_location():
......
......@@ -22,10 +22,12 @@ from foris import fapi
from foris.form import File, Hidden, Textbox
from foris.state import current_state
from foris.utils.translators import (
gettext_dummy as gettext,
gettext as _,
)
from .base import BaseConfigHandler
from .wifi import WifiEditForm
class SubordinatesConfigHandler(BaseConfigHandler):
......@@ -189,3 +191,11 @@ class SubsubordinatesEditForm(fapi.ForisAjaxForm):
sub_form.add_callback(form_cb)
return sub_form
class SubordinatesWifiHandler(BaseConfigHandler):
userfriendly_title = gettext("Wi-Fi")
def get_form(self):
ajax_form = WifiEditForm(self.data)
return ajax_form.foris_form
......@@ -60,6 +60,7 @@ Foris.initialize = function () {
Foris.initWsHandlers();
Foris.initWebsockets();
Foris.initRebootRequired();
Foris.initMenuExpand();
};
Foris.initParsley = function () {
......@@ -777,6 +778,25 @@ Foris.performBackendQuery = async (controller_id, module, action, data) => {
});
};
Foris.initMenuExpand = () => {
$("#menu nav li.nav-expandable").click((e) => {
e.preventDefault();
let current = $(e.currentTarget);
let self_slug = current.attr("data-self-name");
if (self_slug && !current.hasClass("subpage-active")) {
$(`.parent-name-${self_slug}`).toggle("slow");
let expand_tag = current.find(".expand-tag i");
if (expand_tag.hasClass("fa-caret-square-down")) {
expand_tag.removeClass();
expand_tag.addClass("fas fa-caret-square-up");
} else {
expand_tag.removeClass();
expand_tag.addClass("fas fa-caret-square-down");
}
}
});
}
$(document).ready(function () {
Foris.initialize();
......
......@@ -77,6 +77,9 @@ $nav-item-border: 2px solid #ddd
background-color: #000
font-weight: bold
span.expand-tag
float: right
#subnav
+pie-clearfix
font-weight: bold
......@@ -182,3 +185,7 @@ $nav-item-border: 2px solid #ddd
float: right
width: 50%
border-left: $nav-item-border
#menu .submenu-item
padding-left: 1.5em
background-color: lighten($sidebar-background-color, 4)
{% extends '_layout.html.j2' %}
{% macro write_active(page) -%}
{% if active_config_page_key is defined and active_config_page_key == page.slug %} active{% endif %}
{% endmacro -%}
{% macro render_menu_item(page, parent, display) -%}
{% if page.is_visible() and page.is_enabled() %}
<li class="{{ write_active(page) }}{% if parent %} submenu-item parent-name-{{ parent.name }}{% endif %}{% if active_config_page_key in page.subpage_slugs() %} subpage-active{% endif %}{% if not page.slug %} nav-expandable{% endif %}" {% if not display %}style="display: none;"{% endif %} data-self-name="{{ page.name if page.name else "" }}">
<a href="{{ url("config_page", page_name=page.slug) if page.slug else "#" }}">{% if parent %}<i class="fas fa-level-up-alt rotate-90"></i> {% endif %}{{ page.userfriendly_title }}
{% if page.subpages and active_config_page_key not in page.subpage_slugs() %}
<span title="{% trans %}Expandable{% endtrans %}" id="{{ page.slug or page.name }}_expand" class="expand-tag"><i class='fas fa-caret-square-down'></i></span>
{% elif page.get_menu_tag()["show"] %}
<span title="{{ page.get_menu_tag()["hint"]}}" style="{{"" if page.get_menu_tag()["show"] else "display: none" }}" id="{{ page.slug or page.name }}_menu_tag" class="menu-tag">
{{ page.get_menu_tag()["text"]|safe }}
</span>
{% endif %}
</a>
</li>
{% elif page.is_visible() %}
<li><span class="link-disabled"{% if not display %}style="display: none;"{% endif %}>{{ page.userfriendly_title }}</span></li>
{% endif %}
{% endmacro -%}
{% block base %}
{% if is_xhr is not defined %}
......@@ -65,17 +87,10 @@
<ul>
{% for config_page in get_config_pages() %}
{% if config_page.is_visible() and config_page.is_enabled() %}
<li{{ ' class="active"' if active_config_page_key is defined and config_page.slug == active_config_page_key else "" }}>
<a href="{{ url("config_page", page_name=config_page.slug) }}">{{ config_page.userfriendly_title }}
{% if config_page.get_menu_tag()["show"] %}
<span title="{{ config_page.get_menu_tag()["hint"]}}" style="{{"" if config_page.get_menu_tag()["show"] else "display: none" }}" id="{{ config_page.slug }}_menu_tag" class="menu-tag">
{{ config_page.get_menu_tag()["text"]|safe }}
</span>
{% endif %}
</a>
</li>
{% elif config_page.is_visible() %}
<li><span class="link-disabled">{{ config_page.userfriendly_title }}</span></li>
{{ render_menu_item(config_page, None, True) }}
{% for subpage in config_page.subpages %}
{{ render_menu_item(subpage, config_page, config_page.slug == active_config_page_key or active_config_page_key in config_page.subpage_slugs()) }}
{% endfor %}
{% endif %}
{% endfor %}
</ul>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment