web_kbn improvements
This commit is contained in:
parent
847ee95d12
commit
952e41d594
@ -39,51 +39,52 @@ class WebKbnConfig(AppConfigUnit):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
common_static_files = [
|
# files marked with + at the beginning are included by default
|
||||||
'bootstrap.min.css',
|
common_static_files = {
|
||||||
'bootstrap.bundle.min.js',
|
'+bootstrap.min.css': 1,
|
||||||
'polyfills.js',
|
'+bootstrap.bundle.min.js': 1,
|
||||||
'app.js',
|
'+polyfills.js': 1,
|
||||||
'app.css'
|
'+app.js': 6,
|
||||||
]
|
'+app.css': 6,
|
||||||
static_version = 4
|
'hls.js': 1
|
||||||
|
}
|
||||||
routes = web.RouteTableDef()
|
routes = web.RouteTableDef()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
lang_context_var = ContextVar('lang', default=Translation.DEFAULT_LANGUAGE)
|
lang_context_var = ContextVar('lang', default=Translation.DEFAULT_LANGUAGE)
|
||||||
|
|
||||||
|
|
||||||
def get_js_link(file, version=static_version) -> str:
|
def get_js_link(file, version) -> str:
|
||||||
if is_development_mode():
|
if is_development_mode():
|
||||||
version = int(time.time())
|
version = int(time.time())
|
||||||
if version:
|
file += f'?version={version}'
|
||||||
file += f'?version={version}'
|
|
||||||
return f'<script src="{config.app_config["assets_public_path"]}/{file}" type="text/javascript"></script>'
|
return f'<script src="{config.app_config["assets_public_path"]}/{file}" type="text/javascript"></script>'
|
||||||
|
|
||||||
|
|
||||||
def get_css_link(file, version=static_version) -> str:
|
def get_css_link(file, version) -> str:
|
||||||
if is_development_mode():
|
if is_development_mode():
|
||||||
version = int(time.time())
|
version = int(time.time())
|
||||||
if version:
|
file += f'?version={version}'
|
||||||
file += f'?version={version}'
|
|
||||||
return f'<link rel="stylesheet" type="text/css" href="{config.app_config["assets_public_path"]}/{file}">'
|
return f'<link rel="stylesheet" type="text/css" href="{config.app_config["assets_public_path"]}/{file}">'
|
||||||
|
|
||||||
|
|
||||||
def get_head_static(files=None) -> str:
|
def get_head_static(additional_files=None) -> str:
|
||||||
buf = StringIO()
|
buf = StringIO()
|
||||||
if files is None:
|
if additional_files is None:
|
||||||
files = []
|
additional_files = []
|
||||||
for file in common_static_files + files:
|
|
||||||
try:
|
for file, version in common_static_files.items():
|
||||||
q_ind = file.index('?')
|
enabled_by_default = file.startswith('+')
|
||||||
v = file[q_ind+1:]
|
if not enabled_by_default and file not in additional_files:
|
||||||
file = file[:file.index('?')]
|
continue
|
||||||
except ValueError:
|
|
||||||
pass
|
if enabled_by_default:
|
||||||
|
file = file[1:]
|
||||||
|
|
||||||
if file.endswith('.js'):
|
if file.endswith('.js'):
|
||||||
buf.write(get_js_link(file))
|
buf.write(get_js_link(file, version))
|
||||||
else:
|
else:
|
||||||
buf.write(get_css_link(file))
|
buf.write(get_css_link(file, version))
|
||||||
|
|
||||||
return buf.getvalue()
|
return buf.getvalue()
|
||||||
|
|
||||||
|
|
||||||
@ -252,6 +253,13 @@ async def index0(req: web.Request):
|
|||||||
|
|
||||||
@routes.get('/main.cgi')
|
@routes.get('/main.cgi')
|
||||||
async def index(req: web.Request):
|
async def index(req: web.Request):
|
||||||
|
tabs = ['zones', 'list']
|
||||||
|
tab = req.query.get('tab', None)
|
||||||
|
if tab and (tab not in tabs or tab == tabs[0]):
|
||||||
|
raise web.HTTPFound('/main.cgi')
|
||||||
|
if tab is None:
|
||||||
|
tab = tabs[0]
|
||||||
|
|
||||||
ctx = {}
|
ctx = {}
|
||||||
for k in 'inverter', 'sensors':
|
for k in 'inverter', 'sensors':
|
||||||
ctx[f'{k}_grafana_url'] = config.app_config[f'{k}_grafana_url']
|
ctx[f'{k}_grafana_url'] = config.app_config[f'{k}_grafana_url']
|
||||||
@ -261,6 +269,8 @@ async def index(req: web.Request):
|
|||||||
ctx['allcams'] = cc.get_all_cam_names()
|
ctx['allcams'] = cc.get_all_cam_names()
|
||||||
ctx['lang_enum'] = Language
|
ctx['lang_enum'] = Language
|
||||||
ctx['lang_selected'] = lang_context_var.get()
|
ctx['lang_selected'] = lang_context_var.get()
|
||||||
|
ctx['tab_selected'] = tab
|
||||||
|
ctx['tabs'] = tabs
|
||||||
|
|
||||||
return await render(req, 'index',
|
return await render(req, 'index',
|
||||||
title=lang('sitename'),
|
title=lang('sitename'),
|
||||||
@ -419,7 +429,7 @@ async def cams(req: web.Request):
|
|||||||
if not cc.has_camera(int(cam)):
|
if not cc.has_camera(int(cam)):
|
||||||
raise ValueError('invalid camera id')
|
raise ValueError('invalid camera id')
|
||||||
cams = [int(cam)]
|
cams = [int(cam)]
|
||||||
mode = {'type': 'single', 'cam': cam}
|
mode = {'type': 'single', 'cam': int(cam)}
|
||||||
|
|
||||||
elif zone is not None:
|
elif zone is not None:
|
||||||
if not cc.has_zone(zone):
|
if not cc.has_zone(zone):
|
||||||
@ -428,7 +438,8 @@ async def cams(req: web.Request):
|
|||||||
mode = {'type': 'zone', 'zone': zone}
|
mode = {'type': 'zone', 'zone': zone}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise web.HTTPBadRequest(text='no camera id or zone found')
|
cams = cc.get_all_cam_names()
|
||||||
|
mode = {'type': 'all'}
|
||||||
|
|
||||||
js_config = {
|
js_config = {
|
||||||
'host': config.app_config['cam_hls_host'],
|
'host': config.app_config['cam_hls_host'],
|
||||||
|
@ -4,7 +4,7 @@ import html
|
|||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp.web import HTTPFound
|
from aiohttp.web import HTTPFound, HTTPMovedPermanently, HTTPException
|
||||||
from aiohttp.web_exceptions import HTTPNotFound
|
from aiohttp.web_exceptions import HTTPNotFound
|
||||||
from ..util import stringify, format_tb, Addr
|
from ..util import stringify, format_tb, Addr
|
||||||
from ..config import is_development_mode
|
from ..config import is_development_mode
|
||||||
@ -55,9 +55,17 @@ async def errors_handler_middleware(request, handler):
|
|||||||
code=404
|
code=404
|
||||||
)
|
)
|
||||||
|
|
||||||
except HTTPFound as exc:
|
except (HTTPFound, HTTPMovedPermanently) as exc:
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
|
except HTTPException as exc:
|
||||||
|
_logger.exception(exc)
|
||||||
|
return _render_error(
|
||||||
|
error_type=exc.reason,
|
||||||
|
error_message=exc.text,
|
||||||
|
traceback=format_tb(exc)
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
_logger.exception(exc)
|
_logger.exception(exc)
|
||||||
return _render_error(
|
return _render_error(
|
||||||
|
@ -209,4 +209,14 @@ a.camzone {
|
|||||||
right: 8px;
|
right: 8px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cams_list_group {}
|
||||||
|
.cams_list_group .list-group-item:first-child {
|
||||||
|
border-top-width: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.cams_list_group .list-group-item .icon-right {
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
}
|
}
|
@ -103,22 +103,22 @@ function removeClass(el, name) {
|
|||||||
|
|
||||||
function indexInit() {
|
function indexInit() {
|
||||||
// language selector
|
// language selector
|
||||||
var langSelect = document.getElementById('lang');
|
const langSelect = document.getElementById('lang');
|
||||||
langSelect.addEventListener('change', function() {
|
langSelect.addEventListener('change', function() {
|
||||||
var selectedLang = this.value;
|
const selectedLang = this.value;
|
||||||
document.cookie = "lang=" + selectedLang + ";path=/";
|
document.cookie = "lang=" + selectedLang + ";path=/";
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
// camera blocks
|
// camera blocks
|
||||||
var blocks = ['zones', 'list'];
|
let blocks = ['zones', 'list'];
|
||||||
for (var i = 0; i < blocks.length; i++) {
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
var button = ge('cam_'+blocks[i]+'_btn');
|
const button = ge('cam_'+blocks[i]+'_btn');
|
||||||
button.addEventListener('click', function(e) {
|
button.addEventListener('click', function(e) {
|
||||||
var selected = e.target.getAttribute('data-id');
|
const selected = e.target.getAttribute('data-id');
|
||||||
for (var j = 0; j < blocks.length; j++) {
|
for (let j = 0; j < blocks.length; j++) {
|
||||||
var button = ge('cam_'+blocks[j]+'_btn');
|
const button = ge('cam_'+blocks[j]+'_btn');
|
||||||
var content = ge('cam_'+blocks[j]);
|
const content = ge('cam_'+blocks[j]);
|
||||||
if (blocks[j] === selected) {
|
if (blocks[j] === selected) {
|
||||||
addClass(button, 'active');
|
addClass(button, 'active');
|
||||||
content.style.display = '';
|
content.style.display = '';
|
||||||
@ -127,6 +127,13 @@ function indexInit() {
|
|||||||
content.style.display = 'none';
|
content.style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window.history !== undefined) {
|
||||||
|
let uri = '/main.cgi'
|
||||||
|
if (selected !== blocks[0])
|
||||||
|
uri += '?tab=' + encodeURIComponent(selected)
|
||||||
|
window.history.replaceState(null, '', uri)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
{% extends "base.j2" %}
|
{% extends "base.j2" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{{ breadcrumbs([{'text': "cams"|lang}]) }}
|
|
||||||
|
|
||||||
{#<nav>#}
|
{% if mode.type == 'all' %}
|
||||||
{# <div class="nav nav-tabs" id="nav-tab">#}
|
{{ breadcrumbs([{'text': "cams"|lang}]) }}
|
||||||
{# <a href="/cams/{{ camera_param ? camera_param~"/" : "" }}" class="text-decoration-none"><button class="nav-link{% if tab == 'low' %} active{% endif %}" type="button">Low-res</button></a>#}
|
{% elif mode.type == 'zone' %}
|
||||||
{# <a href="/cams/{{ camera_param ? camera_param~"/" : "" }}?high=1" class="text-decoration-none"><button class="nav-link{% if tab == 'high' %} active{% endif %}" type="button">High-res</button></a>#}
|
{{ breadcrumbs([
|
||||||
{# </div>#}
|
{'link': '/cams.cgi', 'text': "cams"|lang},
|
||||||
{#</nav>#}
|
{'text': mode.zone|lang('ipcam_zones')}
|
||||||
|
]) }}
|
||||||
|
{% elif mode.type == 'single' %}
|
||||||
|
{{ breadcrumbs([
|
||||||
|
{'link': '/cams.cgi', 'text': "cams"|lang},
|
||||||
|
{'text': mode.cam|lang('ipcam')}
|
||||||
|
]) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id="videos" class="camfeeds"></div>
|
<div id="videos" class="camfeeds"></div>
|
||||||
|
|
||||||
|
@ -37,24 +37,33 @@
|
|||||||
|
|
||||||
<nav class="mt-4">
|
<nav class="mt-4">
|
||||||
<div class="nav nav-tabs" id="nav-tab">
|
<div class="nav nav-tabs" id="nav-tab">
|
||||||
<button class="nav-link active" type="button" id="cam_zones_btn" data-id="zones">{{ "cams_by_zone"|lang }}</button>
|
{% for tab in tabs %}
|
||||||
<button class="nav-link" type="button" id="cam_list_btn" data-id="list">{{ "cams_list"|lang }}</button>
|
<button class="nav-link{% if tab == tab_selected %} active{% endif %}" type="button" id="cam_{{ tab }}_btn" data-id="{{ tab }}">{{ ("cams_by_"~tab)|lang }}</button>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="camzones" id="cam_zones">
|
<div class="camzones" id="cam_zones"{% if tab_selected != 'zones' %} style="display: none"{% endif %}>
|
||||||
{% for zone in camzones %}
|
{% for zone in camzones %}
|
||||||
<a href="/cams.cgi?zone={{ zone }}" class="camzone">
|
<a href="/cams.cgi?zone={{ zone }}" class="camzone">
|
||||||
<div class="camzone_text">{{ zone|lang('ipcam_zones') }}</div>
|
<div class="camzone_text">{{ zone|lang('ipcam_zones') }}</div>
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group list-group-flush" id="cam_list" style="display: none">
|
|
||||||
|
<div class="list-group cams_list_group" id="cam_list"{% if tab_selected != 'list' %} style="display: none"{% endif %}>
|
||||||
{% for id in allcams %}
|
{% for id in allcams %}
|
||||||
<li class="list-group-item"><a href="/cams.cgi?id={{ id }}">{{ id|lang('ipcam') }}</a></li>
|
<a href="/cams.cgi?id={{ id }}" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
||||||
|
{{ id|lang('ipcam') }}
|
||||||
|
<span class="icon-right">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M6.776 1.553a.5.5 0 0 1 .671.223l3 6a.5.5 0 0 1 0 .448l-3 6a.5.5 0 1 1-.894-.448L9.44 8 6.553 2.224a.5.5 0 0 1 .223-.671"/>
|
||||||
|
</svg>
|
||||||
|
</span> <!-- Bootstrap Icon -->
|
||||||
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{# <li class="list-group-item"><a href="/cams/stat/">Статистика</a></li>#}
|
</div>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user