mirror of
https://github.com/ail-project/ail-framework.git
synced 2024-11-30 01:37:17 +00:00
chg: [dashboard] add objects tooltip
This commit is contained in:
parent
e0ae20968d
commit
3d14bac434
7 changed files with 320 additions and 7 deletions
|
@ -709,7 +709,15 @@ def add_object_tag(tag, obj_type, obj_id, subtype=''):
|
||||||
else:
|
else:
|
||||||
r_tags.sadd(f'{obj_type}:{subtype}:{tag}', obj_id)
|
r_tags.sadd(f'{obj_type}:{subtype}:{tag}', obj_id)
|
||||||
|
|
||||||
|
# STATS
|
||||||
r_tags.hincrby(f'daily_tags:{datetime.date.today().strftime("%Y%m%d")}', tag, 1)
|
r_tags.hincrby(f'daily_tags:{datetime.date.today().strftime("%Y%m%d")}', tag, 1)
|
||||||
|
mess = f'{int(time.time())}:{obj_type}:{subtype}:{obj_id}'
|
||||||
|
r_tags.lpush('dashboard:tags', mess)
|
||||||
|
r_tags.ltrim('dashboard:tags', 0, 19)
|
||||||
|
|
||||||
|
def get_tags_dashboard():
|
||||||
|
return r_tags.lrange('dashboard:tags', 0, -1)
|
||||||
|
|
||||||
|
|
||||||
# obj -> Object()
|
# obj -> Object()
|
||||||
def confirm_tag(tag, obj):
|
def confirm_tag(tag, obj):
|
||||||
|
|
|
@ -15,6 +15,8 @@ sys.path.append(os.environ['AIL_BIN'])
|
||||||
##################################
|
##################################
|
||||||
from lib.ConfigLoader import ConfigLoader
|
from lib.ConfigLoader import ConfigLoader
|
||||||
from lib.objects import ail_objects
|
from lib.objects import ail_objects
|
||||||
|
from lib import Tag
|
||||||
|
from lib import Tracker
|
||||||
|
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
|
@ -93,5 +95,20 @@ def get_nb_objs_dashboard():
|
||||||
date = datetime.date.today().strftime("%Y%m%d")
|
date = datetime.date.today().strftime("%Y%m%d")
|
||||||
return ail_objects.get_nb_objects_dashboard(date)
|
return ail_objects.get_nb_objects_dashboard(date)
|
||||||
|
|
||||||
|
def get_tagged_objs_dashboard():
|
||||||
|
tagged_objs = []
|
||||||
|
for tagged_obj in Tag.get_tags_dashboard():
|
||||||
|
timestamp, obj_gid = tagged_obj.split(':', 1)
|
||||||
|
timestamp = datetime.datetime.utcfromtimestamp(int(timestamp)).strftime('%H:%M:%S')
|
||||||
|
obj_meta = ail_objects.get_obj_basic_meta(ail_objects.get_obj_from_global_id(obj_gid), flask_context=True)
|
||||||
|
obj_meta['date_tag'] = timestamp
|
||||||
|
tagged_objs.append(obj_meta)
|
||||||
|
return tagged_objs
|
||||||
|
|
||||||
|
def get_tracked_objs_dashboard(user_org, user_id):
|
||||||
|
trackers = Tracker.get_trackers_dashboard(user_org, user_id)
|
||||||
|
for t in trackers:
|
||||||
|
t['obj'] = ail_objects.get_obj_basic_meta(ail_objects.get_obj_from_global_id(t['obj']))
|
||||||
|
return trackers
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -258,6 +258,12 @@ def add_obj_tags(obj_type, subtype, id, tags):
|
||||||
|
|
||||||
#### OBJ META ####
|
#### OBJ META ####
|
||||||
|
|
||||||
|
def get_obj_basic_meta(obj, flask_context=False):
|
||||||
|
meta = obj.get_default_meta(tags=True)
|
||||||
|
meta['icon'] = obj.get_svg_icon()
|
||||||
|
meta['link'] = obj.get_link(flask_context=flask_context)
|
||||||
|
meta['gid'] = obj.get_global_id()
|
||||||
|
return meta
|
||||||
|
|
||||||
def get_object_meta(obj_type, subtype, id, options=set(), flask_context=False):
|
def get_object_meta(obj_type, subtype, id, options=set(), flask_context=False):
|
||||||
obj = get_object(obj_type, subtype, id)
|
obj = get_object(obj_type, subtype, id)
|
||||||
|
|
|
@ -302,7 +302,8 @@ sock = Sock(app)
|
||||||
@login_required
|
@login_required
|
||||||
@sock.route('/ws/dashboard')
|
@sock.route('/ws/dashboard')
|
||||||
def ws_dashboard(ws):
|
def ws_dashboard(ws):
|
||||||
# TODO wait %30
|
user_org = current_user.get_org()
|
||||||
|
user_id = current_user.get_user_id()
|
||||||
next_feeders = ail_stats.get_next_feeder_timestamp(int(time.time())) + 1
|
next_feeders = ail_stats.get_next_feeder_timestamp(int(time.time())) + 1
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
|
@ -313,7 +314,9 @@ def ws_dashboard(ws):
|
||||||
if int(time.time()) >= next_feeders:
|
if int(time.time()) >= next_feeders:
|
||||||
feeders = ail_stats.get_feeders_dashboard()
|
feeders = ail_stats.get_feeders_dashboard()
|
||||||
objs = ail_stats.get_nb_objs_today()
|
objs = ail_stats.get_nb_objs_today()
|
||||||
ws.send(json.dumps({'feeders': feeders, 'objs': objs}))
|
tags = ail_stats.get_tagged_objs_dashboard()
|
||||||
|
trackers = ail_stats.get_tracked_objs_dashboard(user_org, user_id)
|
||||||
|
ws.send(json.dumps({'feeders': feeders, 'objs': objs, 'tags': tags, 'trackers': trackers}))
|
||||||
next_feeders = next_feeders + 30
|
next_feeders = next_feeders + 30
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
except Exception as e: # ConnectionClosed ?
|
except Exception as e: # ConnectionClosed ?
|
||||||
|
|
|
@ -10,7 +10,7 @@ import sys
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from flask import Flask, render_template, jsonify, request, Blueprint, redirect, url_for, Response, abort, send_file, stream_with_context
|
from flask import Flask, render_template, jsonify, request, Blueprint, redirect, url_for, Response, abort, send_file, stream_with_context
|
||||||
from flask_login import login_required
|
from flask_login import login_required, current_user
|
||||||
|
|
||||||
# Import Role_Manager
|
# Import Role_Manager
|
||||||
from Role_Manager import login_admin, login_read_only
|
from Role_Manager import login_admin, login_read_only
|
||||||
|
@ -37,10 +37,15 @@ bootstrap_label = ['primary', 'success', 'danger', 'warning', 'info']
|
||||||
@login_required
|
@login_required
|
||||||
@login_read_only
|
@login_read_only
|
||||||
def objects():
|
def objects():
|
||||||
|
user_org = current_user.get_org()
|
||||||
|
user_id = current_user.get_user_id()
|
||||||
nb_objects = ail_stats.get_nb_objs_dashboard()
|
nb_objects = ail_stats.get_nb_objs_dashboard()
|
||||||
print(nb_objects)
|
|
||||||
feeders_dashboard = ail_stats.get_feeders_dashboard_full()
|
feeders_dashboard = ail_stats.get_feeders_dashboard_full()
|
||||||
return render_template("objs_dashboard.html", feeders_dashboard=feeders_dashboard, nb_objects=nb_objects)
|
trackers = ail_stats.get_tracked_objs_dashboard(user_org, user_id)
|
||||||
|
tagged_objs = ail_stats.get_tagged_objs_dashboard()
|
||||||
|
return render_template("objs_dashboard.html", feeders_dashboard=feeders_dashboard,
|
||||||
|
nb_objects=nb_objects, trackers=trackers, tagged_objs=tagged_objs,
|
||||||
|
bootstrap_label=bootstrap_label)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,3 +2,124 @@
|
||||||
function sanitize_text(str_to_sanitize) {
|
function sanitize_text(str_to_sanitize) {
|
||||||
return $("<span\>").text(str_to_sanitize).html()
|
return $("<span\>").text(str_to_sanitize).html()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// REQUIRE var url_obj_description
|
||||||
|
function show_obj_tooltip(container, obj_gid) {
|
||||||
|
container = $(container);
|
||||||
|
|
||||||
|
if (container.data('bs.popover')) {
|
||||||
|
container.popover('show');
|
||||||
|
} else {
|
||||||
|
let pop_header = "<div class=\"card text-white\"><div class=\"card-header bg-dark pb-0\">" + sanitize_text(obj_gid) + "/div>";
|
||||||
|
let spinner = "<div class=\"card-body bg-dark pt-0\"><div class=\"spinner-border text-warning\" role=\"status\"></div> Loading...</div>";
|
||||||
|
|
||||||
|
container.popover({
|
||||||
|
title: pop_header,
|
||||||
|
content: spinner,
|
||||||
|
html: true,
|
||||||
|
container: container,
|
||||||
|
})
|
||||||
|
container.popover('show');
|
||||||
|
|
||||||
|
let popoverInstance = container.data('bs.popover');
|
||||||
|
|
||||||
|
|
||||||
|
$.getJSON(url_obj_description + obj_gid, function (data) {
|
||||||
|
|
||||||
|
let desc = "<div class=\"card-body bg-dark text-white pb-1 pt-2\"><dl class=\"row py-0 my-0\">"
|
||||||
|
Object.keys(data).forEach(function(key) {
|
||||||
|
if (key=="status") {
|
||||||
|
desc = desc + "<dt class=\"col-sm-3 px-0\">status</dt><dd class=\"col-sm-9 px-0\"><div class=\"badge badge-pill badge-light flex-row-reverse\" style=\"color:"
|
||||||
|
if (data["status"]) {
|
||||||
|
desc = desc + "Green"
|
||||||
|
} else {
|
||||||
|
desc = desc + "Red"
|
||||||
|
}
|
||||||
|
desc = desc + ";\"><i class=\"fas "
|
||||||
|
if (data["status"]) {
|
||||||
|
desc = desc + "fa-check-circle\"></i>UP"
|
||||||
|
} else {
|
||||||
|
desc = desc + "fa-times-circle\"></i>DOWN"
|
||||||
|
}
|
||||||
|
desc = desc + "</div></dd>"
|
||||||
|
} else if (key!=="tags" && key!=="id" && key!=="img" && key!=="svg_icon" && key!=="icon" && key!=="link" && key!=="type") {
|
||||||
|
if (data[key]) {
|
||||||
|
if ((key==="first_seen" || key==="last_seen") && data[key].length===8) {
|
||||||
|
let date = sanitize_text(data[key])
|
||||||
|
desc = desc + "<dt class=\"col-sm-3 px-0\">" + sanitize_text(key) + "</dt><dd class=\"col-sm-9 px-0 mb-1\">" + date.slice(0, 4) + "-" + date.slice(4, 6) + "-" + date.slice(6, 8) + "</dd>"
|
||||||
|
} else {
|
||||||
|
desc = desc + "<dt class=\"col-sm-3 px-0\">" + sanitize_text(key) + "</dt><dd class=\"col-sm-9 px-0 mb-1\">" + sanitize_text(data[key]) + "</dd>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
desc = desc + "</dl>"
|
||||||
|
|
||||||
|
if (data["tags"]) {
|
||||||
|
data["tags"].forEach(function(tag) {
|
||||||
|
desc = desc + "<span class=\"badge badge-warning\">"+ sanitize_text(tag) +"</span>";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (data["img"]) {
|
||||||
|
if (data["tags_safe"]) {
|
||||||
|
if (data["type"] === "screenshot") {
|
||||||
|
desc = desc + "<img src={{ url_for('objects_item.screenshot', filename="") }}"
|
||||||
|
} else if (data["type"] === "favicon") {
|
||||||
|
desc = desc + "<img src={{ url_for('objects_favicon.favicon', filename="") }}"
|
||||||
|
} else {
|
||||||
|
desc = desc + "<img src={{ url_for('objects_image.image', filename="") }}"
|
||||||
|
}
|
||||||
|
desc = desc + data["img"] +" class=\"img-thumbnail blured\" id=\"tooltip_screenshot_correlation\" style=\"\"/>";
|
||||||
|
} else {
|
||||||
|
desc = desc + "<span class=\"my-2 fa-stack fa-4x\"><i class=\"fas fa-stack-1x fa-image\"></i><i class=\"fas fa-stack-2x fa-ban\" style=\"color:Red\"></i></span>";
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
desc = desc + "</div></div>"
|
||||||
|
//div.html(desc)
|
||||||
|
// .style("left", (d3_pageX) + "px")
|
||||||
|
// .style("top", (d3_pageY - 28) + "px");
|
||||||
|
//d.popover = desc
|
||||||
|
|
||||||
|
if (data["img"]) {
|
||||||
|
blur_tooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
popoverInstance.config.content = desc;
|
||||||
|
popoverInstance.setContent();
|
||||||
|
popoverInstance.update();
|
||||||
|
|
||||||
|
|
||||||
|
//let popoverid = container.attr('aria-describedby');
|
||||||
|
//$('#' + popoverid).find('.popover-header').html(newTitle);
|
||||||
|
//$('#' + popoverid).find('.popover-body').html('newContesssnt');
|
||||||
|
|
||||||
|
}).fail(function(error) {
|
||||||
|
let desc = "<div class=\"card-body bg-dark text-white pt-0\"><i class=\"fas fa-3x fa-times text-danger\"></i>"+ error.statusText +"</div>"
|
||||||
|
popoverInstance.config.content = desc;
|
||||||
|
popoverInstance.setContent();
|
||||||
|
popoverInstance.update();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
container.popover('hide');
|
||||||
|
container.popover('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_obj_tooltip(container) {
|
||||||
|
container = $(container);
|
||||||
|
container.popover('hide')
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function blur_tooltip(){
|
||||||
|
var image = $('#tooltip_screenshot_correlation')[0];
|
||||||
|
if (image) {
|
||||||
|
let blurValue = $('#blur-slider-correlation').val();
|
||||||
|
blurValue = 15 - blurValue;
|
||||||
|
image.style.filter = "blur(" + blurValue + "px)";
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
<!-- JS -->
|
<!-- JS -->
|
||||||
<script src="{{ url_for('static', filename='js/jquery.js')}}"></script>
|
<script src="{{ url_for('static', filename='js/jquery.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/helper.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/popper.min.js')}}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/echarts.min.js')}}"></script>
|
<script src="{{ url_for('static', filename='js/echarts.min.js')}}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/bootstrap4.min.js')}}"></script>
|
<script src="{{ url_for('static', filename='js/bootstrap4.min.js')}}"></script>
|
||||||
|
|
||||||
|
@ -24,6 +26,10 @@
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.popover {
|
||||||
|
max-width: none;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
.icon-button {
|
.icon-button {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -34,7 +40,6 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: inherit;
|
outline: inherit;
|
||||||
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-wrapper {
|
.icon-wrapper {
|
||||||
|
@ -85,6 +90,83 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-6">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><i class="fa-solid fa-crosshairs"></i></th>
|
||||||
|
<th>tracker</th>
|
||||||
|
<th class="text-center"><i class="fas fa-cube"></i></th>
|
||||||
|
<th>Time</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tracked_objs">
|
||||||
|
{% for tracker in trackers %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ tracker['type'] }}</td>
|
||||||
|
<td style="word-break: break-all;">
|
||||||
|
<a href="{{ url_for('hunters.show_tracker') }}?uuid={{ tracker['uuid'] }}">{{ tracker['tracked'] }}</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<a href="{{ tracker['obj']['link'] }}" onmouseenter="show_obj_tooltip(this, '{{ tracker['obj']['gid'] }}')" onmouseleave="hide_obj_tooltip(this)">
|
||||||
|
<svg height="26" width="26" style="pointer-events:none;">
|
||||||
|
<g class="nodes">
|
||||||
|
<circle cx="13" cy="13" r="13" fill="{{ tracker['obj']['icon']['color'] }}"></circle>
|
||||||
|
<text x="13" y="13" text-anchor="middle" dominant-baseline="central" class="{{ tracker['obj']['icon']['style'] }}" font-size="16px">{{ tracker['obj']['icon']['icon'] }}</text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ tracker['timestamp'] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-6">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center"><i class="fas fa-cube"></i></th>
|
||||||
|
<th>ID</th>
|
||||||
|
<th><i class="fas fa-tag"></i> Tags</th>
|
||||||
|
<th>Time</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="t_tags_objs">
|
||||||
|
{% for t_obj in tagged_objs %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{ t_obj['link'] }}" onmouseenter="show_obj_tooltip(this, '{{ t_obj['gid'] }}')" onmouseleave="hide_obj_tooltip(this)">
|
||||||
|
<svg height="26" width="26">
|
||||||
|
<g class="nodes">
|
||||||
|
<circle cx="13" cy="13" r="13" fill="{{ t_obj['icon']['color'] }}"></circle>
|
||||||
|
<text x="13" y="13" text-anchor="middle" dominant-baseline="central" class="{{ t_obj['icon']['style'] }}" font-size="16px">{{ t_obj['icon']['icon'] }}</text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td style="word-break: break-all;">
|
||||||
|
<a href="{{ t_obj['link'] }}">{{ t_obj['id'] }}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% for tag in t_obj['tags'] %}
|
||||||
|
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td>{{ t_obj['date_tag'] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -102,6 +184,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
var tags_colors = ['primary', 'success', 'danger', 'warning', 'info'];
|
||||||
|
var url_obj_description = "{{ url_for('correlation.get_description') }}?object_id=";
|
||||||
|
|
||||||
// Init Dashboard
|
// Init Dashboard
|
||||||
var feederChart = echarts.init(document.getElementById('feeders_dashboard'));
|
var feederChart = echarts.init(document.getElementById('feeders_dashboard'));
|
||||||
window.addEventListener('resize', function() {
|
window.addEventListener('resize', function() {
|
||||||
|
@ -201,22 +286,90 @@ function updateNbObjects(data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////
|
||||||
|
|
||||||
|
function create_obj_svg(container, obj_gid, url, color, fa_style, icon) {
|
||||||
|
var svg_obj = '<svg height="26" width="26"> <g class="nodes"> <circle cx="13" cy="13" r="13" fill="' + color + '"></circle> <text x="13" y="13" text-anchor="middle" dominant-baseline="central" class="' + fa_style + '" font-size="16px">' + icon + '</text> </g> </svg>';
|
||||||
|
var obj_link = $('<a>');
|
||||||
|
obj_link.on('mouseenter', function () {
|
||||||
|
show_obj_tooltip(this, obj_gid);
|
||||||
|
});
|
||||||
|
obj_link.on('mouseleave', function () {
|
||||||
|
hide_obj_tooltip(this);
|
||||||
|
});
|
||||||
|
obj_link.attr('href', url);
|
||||||
|
obj_link.html(svg_obj);
|
||||||
|
container.append(obj_link);
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_tags_badges(container, tags) {
|
||||||
|
var tspan = '';
|
||||||
|
for (const i in tags) {
|
||||||
|
tspan = tspan + '<span class="badge badge-' + 'primary' + '">' + sanitize_text(tags[i]) + '</span>'
|
||||||
|
}
|
||||||
|
return tspan;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_tags_obj_dashboard(data) {
|
||||||
|
// delete table
|
||||||
|
var tbody = $("#t_tags_objs");
|
||||||
|
var ntd;
|
||||||
|
tbody.empty();
|
||||||
|
for (const elem in data) {
|
||||||
|
let obj = data[elem];
|
||||||
|
var row = $('<tr></tr>');
|
||||||
|
ntd = $('<td></td>');
|
||||||
|
row.append(create_obj_svg(ntd, obj['gid'], obj.link, obj['icon']['color'], obj['icon']['style'], obj['icon']['icon']))
|
||||||
|
row.append('<td style="word-break: break-all;"><a href="'+ obj['link'] + '">' + sanitize_text(obj['id']) + '</a></td>');
|
||||||
|
ntd = $('<td></td>');
|
||||||
|
row.append(create_tags_badges(ntd, obj['tags']));
|
||||||
|
row.append('<td>' + obj['date_tag'] + '</td>');
|
||||||
|
tbody.append(row);
|
||||||
|
|
||||||
|
|
||||||
|
{# {% for tag in t_obj['tags'] %}#}
|
||||||
|
{# <span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }}</span>#}
|
||||||
|
{# {% endfor %}#}
|
||||||
|
{#</td>#}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_tracked_objs_dashboard(data) {
|
||||||
|
// delete table
|
||||||
|
var tbody = $("#tracked_objs");
|
||||||
|
var ntd;
|
||||||
|
tbody.empty();
|
||||||
|
for (const elem in data) {
|
||||||
|
let tracker = data[elem];
|
||||||
|
var row = $('<tr></tr>');
|
||||||
|
row.append('<td>' + tracker['type'] + '</td>');
|
||||||
|
row.append('<td style="word-break: break-all;"><a href="{{ url_for('hunters.show_tracker') }}?uuid=' + tracker['uuid'] + '">' + sanitize_text(tracker['tracked']) + '</a></td>');
|
||||||
|
ntd = $('<td class="text-center"></td>');
|
||||||
|
row.append(create_obj_svg(ntd, tracker['obj']['gid'], tracker['obj']['link'], tracker['obj']['icon']['color'], tracker['obj']['icon']['style'], tracker['obj']['icon']['icon']));
|
||||||
|
row.append('<td>' + tracker['timestamp'] + '</td>');
|
||||||
|
tbody.append(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WebSocket
|
// WebSocket
|
||||||
var socket = new WebSocket("{{ url_for('ws_dashboard') }}");
|
var socket = new WebSocket("{{ url_for('ws_dashboard') }}");
|
||||||
socket.wsocket = function(event) {
|
socket.wsocket = function(event) {
|
||||||
console.log("WebSocket connection opened:", event);
|
console.log("WebSocket connection opened:", event);
|
||||||
};
|
};
|
||||||
socket.onmessage = function(event) {
|
socket.onmessage = function(event) {
|
||||||
|
$("[data-toggle='popover']").popover('destroy');
|
||||||
let data = JSON.parse(event.data);
|
let data = JSON.parse(event.data);
|
||||||
updateFeederChart(data['feeders']);
|
updateFeederChart(data['feeders']);
|
||||||
updateNbObjects(data['objs']);
|
updateNbObjects(data['objs']);
|
||||||
|
update_tracked_objs_dashboard(data['trackers']);
|
||||||
|
update_tags_obj_dashboard(data['tags']);
|
||||||
};
|
};
|
||||||
socket.onerror = function(error) {
|
socket.onerror = function(error) {
|
||||||
console.error('WebSocket error:', error);
|
console.error('WebSocket error:', error);
|
||||||
};
|
};
|
||||||
socket.onclose = function(event) {
|
socket.onclose = function(event) {
|
||||||
console.log('WebSocket connection closed:', event);
|
console.log('WebSocket connection closed:', event);
|
||||||
// Optionally implement reconnection logic here
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue