diff options
-rw-r--r-- | ogcp/static/js/ogcp.js | 54 | ||||
-rw-r--r-- | ogcp/templates/macros.html | 20 | ||||
-rw-r--r-- | ogcp/views.py | 8 |
3 files changed, 79 insertions, 3 deletions
diff --git a/ogcp/static/js/ogcp.js b/ogcp/static/js/ogcp.js new file mode 100644 index 0000000..ab06dfc --- /dev/null +++ b/ogcp/static/js/ogcp.js @@ -0,0 +1,54 @@ +const Endpoint = '/scopes/status'; +const Interval = 1000; +let updateTimeoutId = null; + +function updateScopeState() { + if (updateTimeoutId) { + clearTimeout(updateTimeoutId); + } + + updateTimeoutId = setTimeout(() => { + updateTimeoutId = null; + fetch(Endpoint) + .then(response => response.json()) + .then((data) => { + updateScopes(data.scope); + }) + .catch((error) => { console.error(error); }) + .finally(() => { + updateScopeState(); + }); + }, Interval); +} + +function updateScopes(scopes) { + scopes.forEach((scope) => { + if (scope.state) { + const scopeId = `${scope.name}_${scope.id}`; + const scopeEl = document.querySelector(`#${scopeId}`); + const stateCls = ['state--on', 'state--off']; + scopeEl.classList.remove(...stateCls); + const stateClass = `state--${scope.state}`; + scopeEl.classList.add(stateClass); + + const iconEl = document.querySelector(`#${scopeId} .nav-icon`); + const iconCls = ['fas', 'far', 'text-danger', 'text-success']; + iconEl.classList.remove(...iconCls); + let newIconCls = []; + if (scope.state === 'on') { + newIconCls.push('fas', 'text-success'); + } else { + newIconCls.push('far', 'text-danger'); + } + iconEl.classList.add(...newIconCls); + } + if (scope.scope) { + // This is a level so we should update all childs + updateScopes(scope.scope); + } + }); +} + +function unfoldAll() { + $('#scopes .collapse').collapse('show'); +} diff --git a/ogcp/templates/macros.html b/ogcp/templates/macros.html index 60b26a7..93c7380 100644 --- a/ogcp/templates/macros.html +++ b/ogcp/templates/macros.html @@ -20,15 +20,28 @@ {% macro scopes_tree_collapse(scopes) -%} -<ul class="nav flex-column nav-pills"> +<ul id="scopes" class="nav flex-column nav-pills"> {{ scopes_tree_collapse_level(scopes["scope"], 1) }} </ul> +<script> + // Launch the javascript on document ready, so all the global functions exists + // in the scope + document.addEventListener('readystatechange', () => { + if (document.readyState === 'complete') { + updateScopeState(); + unfoldAll(); + } + }); +</script> {% endmacro %} {% macro scopes_tree_collapse_level(scopes, i) -%} {% for scope in scopes %} -<li class="nav-item {% if scope["state"] %}state--{{scope["state"] | lower}}{% endif %}"> + <li + id="{{ scope["name"] }}_{{ scope["id"] }}" + class="nav-item {% if scope["state"] %}state--{{scope["state"] | lower}}{% endif %}" + > {% if " ".join(scope["ip"]) %} <input class="form-check-input" type="checkbox" form="scopesForm" value="{{ " ".join(scope["ip"]) }}" @@ -37,6 +50,9 @@ {% endif %} <a class="nav-link {% if not scope["scope"] %}disabled{% endif %}" href="#level{{i}}-{{loop.index}}" {% if scope["scope"] %}data-toggle="collapse"{% endif %}> + {% if not scope["scope"] %} + <i class="nav-icon fa-circle {% if scope['state'] == 'on' %}fas text-success{% else %}far text-danger{% endif %}"></i> + {% endif %} {{ scope["name"] }} </a> {% if scope["scope"] %} diff --git a/ogcp/views.py b/ogcp/views.py index 1221478..ad5a8cb 100644 --- a/ogcp/views.py +++ b/ogcp/views.py @@ -113,7 +113,7 @@ def add_state_and_ips(scope, clients, ips): if client: scope['state'] = client['state'] else: - scope['state'] = 'OFF' + scope['state'] = 'off' scope['ip'] = [scope['ip']] scope['selected'] = set(scope['ip']).issubset(ips) else: @@ -191,6 +191,12 @@ def logout(): logout_user() return redirect(url_for('index')) +@app.route('/scopes/status') +@login_required +def scopes_status(): + scopes, _clients = get_scopes() + return jsonify(scopes) + @app.route('/scopes/') @login_required def scopes(): |