mqtt-dash/mqtt_dash/widgets.py

211 lines
6.3 KiB
Python

import uuid
from flask import render_template_string
def make_id():
return uuid.uuid4()
def make_widget(template,
widget_type,
sub_topic=None,
extra_classes=None,
**kwargs):
def f():
_classes = ['widget'] + list(extra_classes or [])
_attrs = {}
if sub_topic:
_classes.append('subscriber')
_attrs['data-sub-topic'] = sub_topic
_classes.append(f'{widget_type}-widget')
kwargs['sub_topic'] = sub_topic
_attrs['class'] = ' '.join([c for c in _classes if c is not None])
attr_str = " ".join([f'{k}="{v}"' for k, v in _attrs.items()])
details_link = '''
{% if details_url %}
<label class="is-size-6 details-link" for="toggle-{{id_}}">📈</label> {%endif%}
{% if details_url %}
<input id="toggle-{{id_}}" class="element-toggle" type="checkbox" style="display: none"/>
<div class="modal" id="modal-{{id_}}">
<div class="modal-background"></div>
<div class="modal-content" style="width: 95vw; height: 95vh;">
<iframe src="{{details_url}}" style="width: 95%; height: 95%;"></iframe>
</div>
<label class="modal-close is-large" for="toggle-{{id_}}"></label>
</div>
<style>
#toggle-{{id_}}:checked ~ #modal-{{id_}} {
display: flex;
}
</style>
{% endif %}
'''
widget_template = f'''
<div class="widget-container">
{details_link}
<div {attr_str}>
{template}
</div>
</div>
'''
return render_template_string(widget_template, **kwargs)
return f
def button_widget(topic, label, pub_value, release_value=None, width=None):
template = '''
<input type="button"
class="button is-large is-info is-outlined"
value="{{label}}"
{% if width %}
style="width:{{width}}"
{% endif %}
{% if release_value %}
ontouchstart="publish({{repr(topic)}}, '{{pub_value}}');"
ontouchend="publish({{repr(topic)}}, '{{release_value}}');"
{% else %}
onclick="publish({{repr(topic)}}, '{{pub_value}}');"
{% endif %}
/>
'''
return make_widget(template,
'button',
label=label,
pub_value=pub_value,
release_value=release_value,
width=width,
topic=topic,
repr=repr)
def square_button_widget(*args, size="4em", **kwargs):
return button_widget(*args, width=size, **kwargs)
def slider_widget(label,
topic,
sub_topic=None,
value_path=None,
unit='',
min_val=0,
max_val=255,
step=1,
retain=False):
id_ = make_id()
sub_topic = sub_topic or topic
template = '''
<div style="display:flex;justify-content:center;align-items:center;
height:60px;">
<input id="{{id_}}"
class="slider update-policy-update-value {{sub_topic}}-value"
data-pub-topic="{{topic}}"
data-retain="{{retain | string | lower}}"
{% if value_path %} data-value-path="{{value_path}}" {% endif %}
min="{{min_val}}" type="range" max="{{max_val}}" step="{{step}}"
value="{{min_val}}"/>
<span id="{{id_}}-textual" class="slider-value">-</span>
<span>{{unit}}</span>
</div>
<div>{{label}}</div>
'''
return make_widget(template,
'slider',
sub_topic=sub_topic,
label=label,
min_val=min_val,
max_val=max_val,
step=step,
value_path=value_path,
topic=topic,
unit=unit,
retain=retain,
id_=id_)
def label_widget(topic, label, unit='', **widget_args):
id_ = make_id()
template = '''
<div align="center" class="is-size-2">
<div>{{label}} </div>
<span class="{{topic}}-value update-policy-replace-content">-</span>
<span>{{unit}}</span>
</div>
'''
return make_widget(template,
'label',
sub_topic=topic,
topic=topic,
unit=unit,
label=label,
id_=id_,
**widget_args)
def log_widget(topic, label, **widget_args):
id_ = make_id()
template = '''
<div class="table-container">
<table class="table is-striped is-hoverable is-fullwidth"
style="overflow: auto; height:100px;">
<thead><tr>
<th>Time</th><th>Message</th>
</tr></thead>
<tbody id="{{id_}}-content"
class="{{topic}}-value update-policy-add-row">
</tbody>
</table>
</div>
<div>{{label}}
<button id="{{id_}}" class="delete log-delete"></button>
</div>
'''
return make_widget(template,
"log",
sub_topic=topic,
topic=topic,
label=label,
id_=id_,
**widget_args)
def row_layout(title, elems):
def f():
template = '''
<div class="box">
{% if title %}
<div class="title">{{title}}</div>
{% endif %}
<div class="columns is-mobile is-multiline">
{% for w in elems %}
<div class="column">
{{w()|safe}}
</div>
{% endfor %}
</div>
</div>
'''
return render_template_string(template, title=title, elems=elems)
return f
def column_layout(title, elems):
def f():
template = '''
{% if title %}
<h3>{{title}}</h3>
{% endif %}
<div class="rows">
{% for w in elems %}
<div class="row">
{{w()|safe}}
</div>
{% endfor %}
</div>
'''
return render_template_string(template, title=title, elems=elems)
return f