mirror of https://git.48k.eu/ogcp
Add sidebar and command bar to base template
Modify the base template to add the sidebar and command bar, implemented just in the scopes view. This patch also modifies the "actions/mode.html" template to be shown in the scopes page. Any other action that should be inside the scopes should do the same, add the scopes and clients to the template context and use the "scopes.html" as base in those actions. The notification has been also changed to use a toast notification instead of the usual alert to avoid changing the layout on error.multi-ogserver
parent
db29b306aa
commit
22dcea19ff
|
@ -6,3 +6,11 @@ html, body {
|
|||
width: 100%;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
#sidebar .list-group-item {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.toast {
|
||||
margin: 10px;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% extends 'scopes.html' %}
|
||||
{% import "bootstrap/wtf.html" as wtf %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -20,4 +20,3 @@
|
|||
extra_classes="m-5") }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -17,24 +17,25 @@
|
|||
<div class="main d-flex flex-column align-items-stretch h-100">
|
||||
{% include 'nav.html' %}
|
||||
{% block nav %}{% endblock %}
|
||||
{% block flash %}
|
||||
{% for category, message in get_flashed_messages(with_categories=True) %}
|
||||
{% if category == 'info' %}
|
||||
<div class="alert alert-info alert-dismissible fade show m-1" role="alert">
|
||||
{% elif category == 'error' %}
|
||||
<div class="alert alert-danger alert-dismissible fade show m-1" role="alert">
|
||||
{% else %}
|
||||
<div class="alert alert-warning alert-dismissible fade show m-1" role="alert">
|
||||
{% endif %}
|
||||
{{ message }}
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="{{ _('Close') }}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<div class="container-fluid flex-grow-1">
|
||||
{% block container %}
|
||||
<div class="row h-100">
|
||||
{# The sidebar is not visible on index #}
|
||||
{% if request.endpoint != "index" %}
|
||||
<div id="sidebar" class="bg-light col-md-3 col-lg-2">
|
||||
{% block sidebar %}{% endblock %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% endif %}
|
||||
<div id="content" class="col">
|
||||
<div id="commands" class="py-2">{% block commands %}{% endblock %}</div>
|
||||
<div class="container">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
<div id="content" class="container-fluid flex-grow-1">{% block content %}{% endblock %}</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% block footer %}
|
||||
<footer class="footer navbar-inverse bg-dark flex-shrink-0" role="contentinfo">
|
||||
|
@ -52,5 +53,26 @@
|
|||
<script src="{{ url_for('static', filename='AdminLTE/plugins/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="{{ url_for('static', filename='AdminLTE/dist/js/adminlte.min.js') }}"></script>
|
||||
|
||||
<script>
|
||||
// error messages
|
||||
{% for category, message in get_flashed_messages(with_categories=True) %}
|
||||
let bgclass = 'bg-success';
|
||||
{% if category == 'info' %}
|
||||
bgclass = 'bg-info';
|
||||
{% elif category == 'error' %}
|
||||
bgclass = 'bg-danger';
|
||||
{% else %}
|
||||
bgclass = 'bg-warning';
|
||||
{% endif %}
|
||||
$(document).Toasts('create', {
|
||||
class: bgclass,
|
||||
position: 'topLeft',
|
||||
autohide: true,
|
||||
delay: 5000,
|
||||
title: '{{ message }}',
|
||||
})
|
||||
{% endfor %}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,13 +6,25 @@
|
|||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item {% if request.endpoint == "index" %}active{% endif %}">
|
||||
<a class="nav-link" href="{{ url_for('index') }}">{{ _('Home') }}<span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
{% if current_user.is_authenticated %}
|
||||
<li class="nav-item {% if request.endpoint == "index" %}active{% endif %}">
|
||||
<a class="nav-link" href="{{ url_for('index') }}">{{ _('Dashboard') }}<span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.endpoint == "scopes" %}active{% endif %}">
|
||||
<a class="nav-link" href="{{ url_for('scopes') }}">{{ _('Scopes') }}</a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.endpoint == "commands" %}active{% endif %}">
|
||||
<a class="nav-link" href="#">{{ _('Commands') }}</a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.endpoint == "images" %}active{% endif %}">
|
||||
<a class="nav-link" href="#">{{ _('Images') }}</a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.endpoint == "tasks" %}active{% endif %}">
|
||||
<a class="nav-link" href="#">{{ _('Tasks') }}</a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.endpoint == "schedule" %}active{% endif %}">
|
||||
<a class="nav-link" href="#">{{ _('Schedule') }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
{% macro print_scopes_tree(scopes) -%}
|
||||
|
||||
<ul class="list-group list-group-flush mx-5">
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for scope in scopes %}
|
||||
<li class="list-group-item state--{{ scope['state'] | lower }}">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
<input class="form-check-input" type="checkbox" form="scopesForm"
|
||||
value="{{ " ".join(scope["ip"]) }}"
|
||||
name="{{ scope["name"] }}_{{ scope["id"] }}">
|
||||
{{ scope["name"] }}
|
||||
|
@ -20,51 +20,47 @@
|
|||
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
{{ print_scopes_tree(scopes["scope"]) }}
|
||||
|
||||
<div class="dropdown mt-2">
|
||||
<button class="btn btn-primary dropdown-toggle" type="button"
|
||||
id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
{{ _('Actions') }}
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Power on (WoL)') }}"
|
||||
formaction="{{ url_for('action_wol') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Power off') }}"
|
||||
formaction="{{ url_for('action_poweroff') }}" formmethod="post">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Reboot') }}"
|
||||
formaction="{{ url_for('action_reboot') }}" formmethod="post">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Refresh') }}"
|
||||
formaction="{{ url_for('action_refresh') }}" formmethod="post">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Hardware') }}"
|
||||
formaction="{{ url_for('action_hardware') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Software') }}"
|
||||
formaction="{{ url_for('action_software') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Start session') }}"
|
||||
formaction="{{ url_for('action_session') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Restore Image') }}"
|
||||
formaction="{{ url_for('action_image_restore') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Partition & Format') }}"
|
||||
formaction="{{ url_for('action_setup_show') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Client details') }}"
|
||||
formaction="{{ url_for('action_client_info') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Add client') }}"
|
||||
formaction="{{ url_for('action_client_add') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Create image') }}"
|
||||
formaction="{{ url_for('action_image_create') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Set boot mode') }}"
|
||||
formaction="{{ url_for('action_mode') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Add room') }}"
|
||||
formaction="{{ url_for('action_room_add') }}" formmethod="get">
|
||||
<input class="dropdown-item" type="submit" value="{{ _('Delete room') }}"
|
||||
formaction="{{ url_for('action_room_delete') }}" formmethod="get">
|
||||
</div>
|
||||
</div>
|
||||
{% block container %}
|
||||
<form id="scopesForm">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
</form>
|
||||
{{ super() }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{{ print_scopes_tree(scopes["scope"]) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block commands %}
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Power on (WoL)') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_wol') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Power off') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_poweroff') }}" formmethod="post">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Reboot') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_reboot') }}" formmethod="post">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Refresh') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_refresh') }}" formmethod="post">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Hardware') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_hardware') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Software') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_software') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Start session') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_session') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Restore Image') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_image_restore') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Partition & Format') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_setup_show') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Client details') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_client_info') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Add client') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_client_add') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Create image') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_image_create') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Set boot mode') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_mode') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Add room') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_room_add') }}" formmethod="get">
|
||||
<input class="btn btn-light" type="submit" value="{{ _('Delete room') }}"
|
||||
form="scopesForm" formaction="{{ url_for('action_room_delete') }}" formmethod="get">
|
||||
{% endblock %}
|
||||
|
|
|
@ -105,6 +105,30 @@ def parse_scopes_from_tree(tree, scope_type):
|
|||
scopes += parse_scopes_from_tree(scope, scope_type)
|
||||
return scopes
|
||||
|
||||
def add_state_and_ips(scope, clients):
|
||||
if 'ip' in scope:
|
||||
filtered_client = filter(lambda x: x['addr']==scope['ip'], clients)
|
||||
client = next(filtered_client, False)
|
||||
if client:
|
||||
scope['state'] = client['state']
|
||||
else:
|
||||
scope['state'] = 'OFF'
|
||||
scope['ip'] = [scope['ip']]
|
||||
else:
|
||||
scope['ip'] = []
|
||||
for child in scope['scope']:
|
||||
scope['ip'] += add_state_and_ips(child, clients)
|
||||
return scope['ip']
|
||||
|
||||
def get_scopes():
|
||||
r = g.server.get('/scopes')
|
||||
scopes = r.json()
|
||||
r = g.server.get('/clients')
|
||||
clients = r.json()
|
||||
add_state_and_ips(scopes, clients['clients'])
|
||||
|
||||
return scopes, clients
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
if user_id == 1:
|
||||
|
@ -167,26 +191,7 @@ def logout():
|
|||
@app.route('/scopes/')
|
||||
@login_required
|
||||
def scopes():
|
||||
def add_state_and_ips(scope, clients):
|
||||
if 'ip' in scope:
|
||||
filtered_client = filter(lambda x: x['addr']==scope['ip'], clients)
|
||||
client = next(filtered_client, False)
|
||||
if client:
|
||||
scope['state'] = client['state']
|
||||
else:
|
||||
scope['state'] = 'OFF'
|
||||
scope['ip'] = [scope['ip']]
|
||||
else:
|
||||
scope['ip'] = []
|
||||
for child in scope['scope']:
|
||||
scope['ip'] += add_state_and_ips(child, clients)
|
||||
return scope['ip']
|
||||
|
||||
r = g.server.get('/scopes')
|
||||
scopes = r.json()
|
||||
r = g.server.get('/clients')
|
||||
clients = r.json()
|
||||
add_state_and_ips(scopes, clients['clients'])
|
||||
scopes, clients = get_scopes()
|
||||
return render_template('scopes.html', scopes=scopes, clients=clients)
|
||||
|
||||
@app.route('/action/poweroff', methods=['POST'])
|
||||
|
@ -585,7 +590,8 @@ def action_mode():
|
|||
return redirect(url_for("scopes"))
|
||||
|
||||
form.ok.render_kw = { 'formaction': url_for('action_mode') }
|
||||
return render_template('actions/mode.html', form=form)
|
||||
scopes, clients = get_scopes()
|
||||
return render_template('actions/mode.html', form=form, scopes=scopes, clients=clients)
|
||||
|
||||
|
||||
@app.route('/action/image/create', methods=['GET', 'POST'])
|
||||
|
|
Loading…
Reference in New Issue