src/westferry/ui/forms.py \
src/westferry/ui/graphs.py \
src/westferry/ui/menu.py \
+ src/westferry/ui/tabs.py \
src/westferry/ui/utils.py
westferry_uidir = $(pythondir)/westferry/ui
dist_templates_DATA = \
src/templates/base.html \
+ src/templates/default.html \
src/templates/graphs.html
templates_demodir = $(templatesdir)/demo
templates_modulesdir = $(templatesdir)/modules
dist_templates_modules_DATA = \
- src/templates/modules/box.html
+ src/templates/modules/box.html \
+ src/templates/modules/tabs.html
templates_modules_formsdir = $(templates_modulesdir)/forms
--- /dev/null
+{% extends "base.html" %}
+
+{% block main %}
+ {#
+ Render the default tabbed view
+ #}
+ {% module Tabs(handler.tabs) %}
+{% end block %}
--- /dev/null
+{% import westferry.ui.graphs %}
+
+{#
+ Render the tab navigation bar
+#}
+<ul class="tabs" data-tabs id="{{ tabs.id }}">
+ {% for i, tab in enumerate(tabs) %}
+ {#
+ Select the first tab
+ #}
+ {% set selected = i == 0 %}
+
+ <li class="tabs-title {% if selected %}is-active{% end %}">
+ <a href="#{{ tab.id }}" {% if selected %}aria-selected="true"{% end %}>
+ {{ tab.title }}
+ </a>
+ </li>
+ {% end %}
+</ul>
+
+<div class="tabs-content" data-tabs-content="{{ tabs.id }}">
+ {% for i, tab in enumerate(tabs) %}
+ {#
+ Select the first tab
+ #}
+ {% set selected = i == 0 %}
+
+ <div class="tabs-panel {% if selected %}is-active{% end %}" id="{{ tab.id }}">
+ {% for item in tab.items %}
+ {% if isinstance(item, westferry.ui.graphs.Graph) %}
+ {% module GraphBox(item) %}
+ {% else %}
+ {% module WarningBox(_("Unknown UI Element"),
+ _("A UI element which was supposed to be at this place could not be rendered: %r") % item) %}
+ {% end %}
+ {% end %}
+ </div>
+ {% end %}
+</div>
url = r"/analytics/network/fragmentation"
title = N_("Fragmentation")
- def get(self):
+ def initialize(self):
_ = self.locale.translate
- graphs = [
- ui.graphs.Graph(self, "ipv6-fragmentation"),
- ui.graphs.Graph(self, "ipv4-fragmentation"),
- ]
+ for proto, title in (("ipv6", _("IPv6")), ("ipv4", _("IPv4"))):
+ tab = self.tabs.add_tab(proto, title=title)
- self.render_graphs(graphs)
+ tab.add_graph("%s-fragmentation" % proto)
class AnalyticsSystemBaseHandler(AnalyticsBaseHandler):
# #
###############################################################################
+import functools
import tornado.web
+from .. import ui
from ..i18n import _, N_
_handlers = []
"""
return self.application.backend
+ @functools.cached_property
+ def tabs(self):
+ return ui.tabs.Tabs(self)
+
def get_template_namespace(self):
ns = tornado.web.RequestHandler.get_template_namespace(self)
except ValueError:
raise tornado.web.HTTPError(400,
_("Invalid type for '%s', expected integer") % name)
+
+ def get(self):
+ # Render the default view
+ self.render("default.html")
from . import forms
from . import graphs
from . import menu
+from . import tabs
from . import utils
def get_ui_methods():
--- /dev/null
+#!/usr/bin/python3
+###############################################################################
+# #
+# Westferry - The IPFire web user interface #
+# Copyright (C) 2021 IPFire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+import uuid
+
+from . import base
+from . import graphs
+
+class TabsModule(base.BaseUIModule):
+ def render(self, tabs):
+ return self.render_string("modules/tabs.html", tabs=tabs)
+
+
+class Tabs(object):
+ def __init__(self, handler, id=None):
+ self.handler = handler
+
+ # Store ID or generate a random one
+ self.id = id or uuid.uuid4()
+
+ self.tabs = {}
+
+ def __getattr__(self, key):
+ try:
+ return self.tabs[key]
+ except KeyError as e:
+ raise AttributeError(key) from e
+
+ def __iter__(self):
+ for id in self.tabs:
+ yield self.tabs[id]
+
+ def add_tab(self, id, *args, **kwargs):
+ # Check if a tab with this ID already exists
+ #if id in self:
+ # raise ValueError("Tab with ID '%s' already exists" % id)
+
+ # Create a new tab
+ self.tabs[id] = tab = Tab(self.handler, id, *args, **kwargs)
+
+ # Return the new tab
+ return tab
+
+
+class Tab(object):
+ def __init__(self, handler, id, title):
+ self.handler = handler
+
+ # TODO Check format of ID
+ self.id = id
+
+ self.title = title
+
+ # List to store all items that have been added to this tab
+ self.items = []
+
+ def add_graph(self, *args, **kwargs):
+ graph = graphs.Graph(self.handler, *args, **kwargs)
+ self.items.append(graph)
+
+ return graph