diff options
author | Daniel García Moreno <danigm@soleta.eu> | 2021-06-08 11:33:30 +0200 |
---|---|---|
committer | Daniel García Moreno <danigm@soleta.eu> | 2021-06-08 11:46:40 +0200 |
commit | 22dcea19ff74871b7200bfc7f976836f436c5342 (patch) | |
tree | 7c8808fafb9ac27db8e06491da5cb4d352d7e121 | |
parent | db29b306aaeebcc385d9a0874f4386010a5c6a98 (diff) |
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.
-rw-r--r-- | ogcp/static/css/soleta.css | 8 | ||||
-rw-r--r-- | ogcp/templates/actions/mode.html | 3 | ||||
-rw-r--r-- | ogcp/templates/base.html | 56 | ||||
-rw-r--r-- | ogcp/templates/nav.html | 16 | ||||
-rw-r--r-- | ogcp/templates/scopes.html | 88 | ||||
-rw-r--r-- | ogcp/views.py | 48 |
6 files changed, 131 insertions, 88 deletions
diff --git a/ogcp/static/css/soleta.css b/ogcp/static/css/soleta.css index d748f5b..ca49897 100644 --- a/ogcp/static/css/soleta.css +++ b/ogcp/static/css/soleta.css @@ -6,3 +6,11 @@ html, body { width: 100%; height: 100% !important; } + +#sidebar .list-group-item { + background-color: transparent; +} + +.toast { + margin: 10px; +} diff --git a/ogcp/templates/actions/mode.html b/ogcp/templates/actions/mode.html index 0fd3266..3adce8f 100644 --- a/ogcp/templates/actions/mode.html +++ b/ogcp/templates/actions/mode.html @@ -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 %} - diff --git a/ogcp/templates/base.html b/ogcp/templates/base.html index 5fda82a..dca6205 100644 --- a/ogcp/templates/base.html +++ b/ogcp/templates/base.html @@ -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> diff --git a/ogcp/templates/nav.html b/ogcp/templates/nav.html index 39b0ac2..f2ca3b5 100644 --- a/ogcp/templates/nav.html +++ b/ogcp/templates/nav.html @@ -6,13 +6,25 @@ <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> + {% if current_user.is_authenticated %} <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> + <a class="nav-link" href="{{ url_for('index') }}">{{ _('Dashboard') }}<span class="sr-only">(current)</span></a> </li> - {% if current_user.is_authenticated %} <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> diff --git a/ogcp/templates/scopes.html b/ogcp/templates/scopes.html index 3cb84fd..00f6883 100644 --- a/ogcp/templates/scopes.html +++ b/ogcp/templates/scopes.html @@ -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 %} +{% block container %} + <form id="scopesForm"> + <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> + </form> + {{ super() }} +</form> +{% endblock %} -<form> - <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> +{% block sidebar %} {{ print_scopes_tree(scopes["scope"]) }} +{% endblock %} - <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> -</form> - +{% 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 %} diff --git a/ogcp/views.py b/ogcp/views.py index 9865e0f..5496daf 100644 --- a/ogcp/views.py +++ b/ogcp/views.py @@ -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']) |