build a web module for the dashboard
- load all python module from local dir - initialize Blueprint and Babel
This commit is contained in:
@@ -5,8 +5,6 @@ import os
|
||||
import argparse
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
from quart import Quart, Response
|
||||
from quart_babel import Babel
|
||||
from quart_babel.locale import get_locale
|
||||
from logging import config # noqa F401
|
||||
from proxy import Proxy
|
||||
from inverter_ifc import InverterIfc
|
||||
@@ -17,8 +15,7 @@ from cnf.config import Config
|
||||
from cnf.config_read_env import ConfigReadEnv
|
||||
from cnf.config_read_toml import ConfigReadToml
|
||||
from cnf.config_read_json import ConfigReadJson
|
||||
from web.routes import web_routes
|
||||
from web.i18n import i18n_routes, my_get_locale, LANGUAGES
|
||||
from web import Web
|
||||
from modbus_tcp import ModbusTcp
|
||||
|
||||
|
||||
@@ -34,27 +31,11 @@ class ProxyState:
|
||||
ProxyState._is_up = value
|
||||
|
||||
|
||||
def my_get_tz():
|
||||
return 'CET'
|
||||
|
||||
|
||||
app = Quart(__name__,
|
||||
template_folder='web/templates',
|
||||
static_folder='web/static')
|
||||
babel = Babel(app,
|
||||
locale_selector=my_get_locale,
|
||||
timezone_selector=my_get_tz,
|
||||
default_translation_directories='../translations')
|
||||
app.register_blueprint(web_routes)
|
||||
app.register_blueprint(i18n_routes)
|
||||
app.secret_key = 'super secret key'
|
||||
|
||||
|
||||
@app.context_processor
|
||||
def utility_processor():
|
||||
return dict(lang=get_locale(),
|
||||
lang_str=LANGUAGES.get(str(get_locale()), "English"),
|
||||
languages=LANGUAGES)
|
||||
Web(app, '../translations')
|
||||
app.secret_key = 'super secret key' # fixme define a secret
|
||||
|
||||
|
||||
@app.route('/-/ready')
|
||||
|
||||
25
app/src/utils/__init__.py
Normal file
25
app/src/utils/__init__.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import mimetypes
|
||||
from importlib import import_module
|
||||
from pathlib import Path
|
||||
from collections.abc import Callable
|
||||
|
||||
|
||||
class SourceFileLoader:
|
||||
""" Represents a SouceFileLoader (__loader__)"""
|
||||
name: str
|
||||
get_resource_reader: Callable
|
||||
|
||||
|
||||
def load_modules(loader: SourceFileLoader):
|
||||
"""Load the entire modules from a SourceFileLoader (__loader__)"""
|
||||
pkg = loader.name
|
||||
for load in loader.get_resource_reader().contents():
|
||||
|
||||
if "python" not in str(mimetypes.guess_type(load)[0]):
|
||||
continue
|
||||
|
||||
mod = Path(load).stem
|
||||
if mod == "__init__":
|
||||
continue
|
||||
|
||||
import_module(pkg + "." + mod, pkg)
|
||||
28
app/src/web/__init__.py
Normal file
28
app/src/web/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
||||
'''Quart blueprint for the proxy webserver with the dashboard
|
||||
|
||||
Usage:
|
||||
app = Quart(__name__, ...)
|
||||
Web(app)
|
||||
'''
|
||||
from quart import Quart, Blueprint
|
||||
from quart_babel import Babel
|
||||
from utils import load_modules
|
||||
|
||||
web = Blueprint('web', __name__)
|
||||
|
||||
load_modules(__loader__)
|
||||
|
||||
|
||||
class Web:
|
||||
'''Helper Class to register the Blueprint at Quart and
|
||||
initializing Babel'''
|
||||
def __init__(self, app: Quart, translation_directories: str | list[str]):
|
||||
app.register_blueprint(web)
|
||||
|
||||
from .i18n import get_locale, get_tz
|
||||
global babel
|
||||
babel = Babel(
|
||||
app,
|
||||
locale_selector=get_locale,
|
||||
timezone_selector=get_tz,
|
||||
default_translation_directories=translation_directories)
|
||||
@@ -1,7 +1,8 @@
|
||||
from quart import Blueprint
|
||||
from quart import request, session, redirect
|
||||
from quart_babel import _
|
||||
from quart_babel.locale import get_locale as babel_get_locale
|
||||
|
||||
from . import web
|
||||
|
||||
LANGUAGES = {
|
||||
'en': _('English'),
|
||||
@@ -9,10 +10,8 @@ LANGUAGES = {
|
||||
'fr': _('French')
|
||||
}
|
||||
|
||||
i18n_routes = Blueprint('i18n_routes', __name__)
|
||||
|
||||
|
||||
def my_get_locale():
|
||||
def get_locale():
|
||||
try:
|
||||
language = session['language']
|
||||
except KeyError:
|
||||
@@ -25,7 +24,18 @@ def my_get_locale():
|
||||
return request.accept_languages.best_match(LANGUAGES.keys())
|
||||
|
||||
|
||||
@i18n_routes.route('/language/<language>')
|
||||
def get_tz():
|
||||
return 'CET'
|
||||
|
||||
|
||||
@web.context_processor
|
||||
def utility_processor():
|
||||
return dict(lang=babel_get_locale(),
|
||||
lang_str=LANGUAGES.get(str(babel_get_locale()), "English"),
|
||||
languages=LANGUAGES)
|
||||
|
||||
|
||||
@web.route('/language/<language>')
|
||||
def set_language(language=None):
|
||||
if language in LANGUAGES:
|
||||
session['language'] = language
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
from quart import Blueprint
|
||||
from quart import render_template, url_for
|
||||
from quart import send_from_directory
|
||||
from quart_babel import format_datetime
|
||||
from infos import Infos
|
||||
from web.conn_table import get_table_data
|
||||
from . import web
|
||||
import os
|
||||
|
||||
web_routes = Blueprint('web_routes', __name__)
|
||||
|
||||
|
||||
async def get_icon(file: str, mime: str = 'image/png'):
|
||||
return await send_from_directory(
|
||||
os.path.join(web_routes.root_path, 'static/images'),
|
||||
os.path.join(web.root_path, 'static/images'),
|
||||
file,
|
||||
mimetype=mime)
|
||||
|
||||
|
||||
@web_routes.route('/')
|
||||
@web.route('/')
|
||||
async def index():
|
||||
return await render_template(
|
||||
'index.html.j2',
|
||||
fetch_url='.'+url_for('web_routes.data_fetch'))
|
||||
fetch_url='.'+url_for('web.data_fetch'))
|
||||
|
||||
|
||||
@web_routes.route('/page')
|
||||
@web.route('/page')
|
||||
async def empty():
|
||||
return await render_template('empty.html.j2')
|
||||
|
||||
|
||||
@web_routes.route('/data-fetch')
|
||||
@web.route('/data-fetch')
|
||||
async def data_fetch():
|
||||
data = {
|
||||
"update-time": format_datetime(format="medium"),
|
||||
@@ -44,26 +42,26 @@ async def data_fetch():
|
||||
return data
|
||||
|
||||
|
||||
@web_routes.route('/favicon-96x96.png')
|
||||
@web.route('/favicon-96x96.png')
|
||||
async def favicon():
|
||||
return await get_icon('favicon-96x96.png')
|
||||
|
||||
|
||||
@web_routes.route('/favicon.ico')
|
||||
@web.route('/favicon.ico')
|
||||
async def favicon_ico():
|
||||
return await get_icon('favicon.ico', 'image/x-icon')
|
||||
|
||||
|
||||
@web_routes.route('/favicon.svg')
|
||||
@web.route('/favicon.svg')
|
||||
async def favicon_svg():
|
||||
return await get_icon('favicon.svg', 'image/svg+xml')
|
||||
|
||||
|
||||
@web_routes.route('/apple-touch-icon.png')
|
||||
@web.route('/apple-touch-icon.png')
|
||||
async def apple_touch():
|
||||
return await get_icon('apple-touch-icon.png')
|
||||
|
||||
|
||||
@web_routes.route('/site.webmanifest')
|
||||
@web.route('/site.webmanifest')
|
||||
async def webmanifest():
|
||||
return await get_icon('site.webmanifest', 'application/manifest+json')
|
||||
|
||||
@@ -55,9 +55,9 @@
|
||||
</div>
|
||||
<div class="w3-bar-block">
|
||||
<button href="#" class="w3-bar-item w3-button w3-padding-16 w3-hide-large w3-dark-grey w3-hover-black" onclick="w3_close()" title="close menu"><i class="fa fa-remove fa-fw"></i> Close Menu</button>
|
||||
<a href=".{{ url_for('web_routes.index')}}" class="w3-bar-item w3-button w3-padding {% block menu1_class %}{% endblock %}"><i class="fa fa-network-wired fa-fw"></i> {{_('Connections')}}</a>
|
||||
<a href=".{{ url_for('web_routes.empty')}}" class="w3-bar-item w3-button w3-padding {% block menu2_class %}{% endblock %}"><i class="fa fa-database fa-fw"></i> MQTT</a>
|
||||
<a href=".{{ url_for('web_routes.empty')}}" class="w3-bar-item w3-button w3-padding"><i class="fa fa-file-export fa-fw {% block menu3_class %}{% endblock %}"></i> Downloads</a>
|
||||
<a href=".{{ url_for('web.index')}}" class="w3-bar-item w3-button w3-padding {% block menu1_class %}{% endblock %}"><i class="fa fa-network-wired fa-fw"></i> {{_('Connections')}}</a>
|
||||
<a href=".{{ url_for('web.empty')}}" class="w3-bar-item w3-button w3-padding {% block menu2_class %}{% endblock %}"><i class="fa fa-database fa-fw"></i> MQTT</a>
|
||||
<a href=".{{ url_for('web.empty')}}" class="w3-bar-item w3-button w3-padding"><i class="fa fa-file-export fa-fw {% block menu3_class %}{% endblock %}"></i> Downloads</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user