mirror of
https://github.com/craigerl/aprsd.git
synced 2025-06-25 13:35:20 -04:00
Merge pull request #130 from craigerl/webchat-saved-bootstrapjs
Webchat saved bootstrapjs
This commit is contained in:
commit
9985c8bf25
@ -15,7 +15,6 @@ from flask.logging import default_handler
|
|||||||
from flask_httpauth import HTTPBasicAuth
|
from flask_httpauth import HTTPBasicAuth
|
||||||
from flask_socketio import Namespace, SocketIO
|
from flask_socketio import Namespace, SocketIO
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from user_agents import parse as ua_parse
|
|
||||||
from werkzeug.security import check_password_hash, generate_password_hash
|
from werkzeug.security import check_password_hash, generate_password_hash
|
||||||
import wrapt
|
import wrapt
|
||||||
|
|
||||||
@ -217,20 +216,10 @@ def _get_transport(stats):
|
|||||||
@auth.login_required
|
@auth.login_required
|
||||||
@flask_app.route("/")
|
@flask_app.route("/")
|
||||||
def index():
|
def index():
|
||||||
ua_str = request.headers.get("User-Agent")
|
|
||||||
# this takes about 2 seconds :(
|
|
||||||
user_agent = ua_parse(ua_str)
|
|
||||||
LOG.debug(f"Is mobile? {user_agent.is_mobile}")
|
|
||||||
stats = _stats()
|
stats = _stats()
|
||||||
|
|
||||||
if user_agent.is_mobile:
|
|
||||||
html_template = "mobile.html"
|
|
||||||
else:
|
|
||||||
html_template = "index.html"
|
|
||||||
|
|
||||||
# For development
|
# For development
|
||||||
# html_template = "mobile.html"
|
html_template = "index.html"
|
||||||
|
|
||||||
LOG.debug(f"Template {html_template}")
|
LOG.debug(f"Template {html_template}")
|
||||||
|
|
||||||
transport, aprs_connection = _get_transport(stats)
|
transport, aprs_connection = _get_transport(stats)
|
||||||
|
@ -246,7 +246,6 @@ class APRSDStats:
|
|||||||
},
|
},
|
||||||
"plugins": plugin_stats,
|
"plugins": plugin_stats,
|
||||||
}
|
}
|
||||||
LOG.info("APRSD Stats: DONE")
|
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
97
aprsd/web/chat/static/css/chat.css
Normal file
97
aprsd/web/chat/static/css/chat.css
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
input[type=search]::-webkit-search-cancel-button {
|
||||||
|
-webkit-appearance: searchfield-cancel-button;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speech-wrapper {
|
||||||
|
padding: 5px 30px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
height: 450px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: none;
|
||||||
|
background-color: #CCCCCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble-row {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: flex-start;
|
||||||
|
&.alt {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
/*width: 350px; */
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 2px 8px 5px #555;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 0 15px;
|
||||||
|
&.alt {
|
||||||
|
margin: 0 0 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble-text {
|
||||||
|
padding: 5px 5px 0px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble-name {
|
||||||
|
width: 280px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0 0 4px;
|
||||||
|
color: #3498db;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.material-symbols-rounded {
|
||||||
|
margin-left: auto;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
&.alt {
|
||||||
|
color: #2ecc71;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble-timestamp {
|
||||||
|
margin-right: auto;
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #bbb
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble-message {
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px 5px 5px 0px;
|
||||||
|
color: #2b2b2b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble-arrow {
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
bottom:30px;
|
||||||
|
left: -16px;
|
||||||
|
height: 0px;
|
||||||
|
&.alt{
|
||||||
|
right: -2px;
|
||||||
|
bottom: 30px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bubble-arrow:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
border: 0 solid transparent;
|
||||||
|
border-top: 9px solid #f5f5f5;
|
||||||
|
border-radius: 0 20px 0;
|
||||||
|
width: 15px;
|
||||||
|
height: 30px;
|
||||||
|
transform: rotate(145deg);
|
||||||
|
}
|
||||||
|
.bubble-arrow.alt:after {
|
||||||
|
transform: rotate(45deg) scaleY(-1);
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
body {
|
body {
|
||||||
background: #eeeeee;
|
background: #eeeeee;
|
||||||
margin: 2em;
|
margin: 1em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: system-ui, sans-serif;
|
font-family: system-ui, sans-serif;
|
||||||
}
|
}
|
||||||
@ -11,34 +11,13 @@ footer {
|
|||||||
height: 10vh;
|
height: 10vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.segment {
|
|
||||||
background: #eeeeee;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.list {
|
|
||||||
list-style-type: disc;
|
|
||||||
}
|
|
||||||
ul.list li {
|
|
||||||
list-style-position: outside;
|
|
||||||
}
|
|
||||||
|
|
||||||
#left {
|
|
||||||
margin-right: 2px;
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
#right {
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
#center {
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#title {
|
#title {
|
||||||
font-size: 4em;
|
font-size: 4em;
|
||||||
}
|
}
|
||||||
#version{
|
#version{
|
||||||
font-size: .5em;
|
font-size: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#uptime, #aprsis {
|
#uptime, #aprsis {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
@ -66,29 +45,3 @@ ul.list li {
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#msgsTabsDiv .ui.tab {
|
|
||||||
margin:0px;
|
|
||||||
padding:0px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#msgsTabsDiv .header, .tiny.text, .content, .break,
|
|
||||||
.thumbs.down.outline.icon,
|
|
||||||
.phone.volume.icon
|
|
||||||
{
|
|
||||||
display: inline-block;
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#msgsTabsDiv .tiny.text {
|
|
||||||
width:100px;
|
|
||||||
}
|
|
||||||
#msgsTabsDiv .tiny.header {
|
|
||||||
width:100px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
#msgsTabsDiv .break {
|
|
||||||
margin: 2px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
@ -37,5 +37,5 @@
|
|||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
height: 450px;
|
height: 450px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
background-color: white;
|
background-color: #CCCCCC;
|
||||||
}
|
}
|
||||||
|
@ -1,246 +0,0 @@
|
|||||||
var cleared = false;
|
|
||||||
var callsign_list = {};
|
|
||||||
var message_list = {};
|
|
||||||
var from_msg_list = {};
|
|
||||||
const socket = io("/sendmsg");
|
|
||||||
|
|
||||||
function size_dict(d){c=0; for (i in d) ++c; return c}
|
|
||||||
|
|
||||||
function init_chat() {
|
|
||||||
socket.on('connect', function () {
|
|
||||||
console.log("Connected to socketio");
|
|
||||||
});
|
|
||||||
socket.on('connected', function(msg) {
|
|
||||||
console.log("Connected!");
|
|
||||||
console.log(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("sent", function(msg) {
|
|
||||||
if (cleared == false) {
|
|
||||||
var msgsdiv = $("#msgsTabsDiv");
|
|
||||||
msgsdiv.html('')
|
|
||||||
cleared = true
|
|
||||||
}
|
|
||||||
sent_msg(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("ack", function(msg) {
|
|
||||||
update_msg(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("new", function(msg) {
|
|
||||||
if (cleared == false) {
|
|
||||||
var msgsdiv = $("#msgsTabsDiv");
|
|
||||||
msgsdiv.html('')
|
|
||||||
cleared = true
|
|
||||||
}
|
|
||||||
from_msg(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#sendform").submit(function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
msg = {'to': $('#to_call').val().toUpperCase(),
|
|
||||||
'message': $('#message').val(),
|
|
||||||
}
|
|
||||||
socket.emit("send", msg);
|
|
||||||
$('#message').val('');
|
|
||||||
});
|
|
||||||
|
|
||||||
init_gps();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function add_callsign(callsign) {
|
|
||||||
/* Ensure a callsign exists in the left hand nav */
|
|
||||||
dropdown = $('#callsign_dropdown')
|
|
||||||
|
|
||||||
if (callsign in callsign_list) {
|
|
||||||
console.log(callsign+' already in list.')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var callsignTabs = $("#callsignTabs");
|
|
||||||
tab_name = tab_string(callsign);
|
|
||||||
tab_content = tab_content_name(callsign);
|
|
||||||
divname = content_divname(callsign);
|
|
||||||
|
|
||||||
item_html = '<div class="active item" id="'+tab_name+'" onclick="openCallsign(event, \''+callsign+'\');">'+callsign+'</div>';
|
|
||||||
callsignTabs.append(item_html);
|
|
||||||
|
|
||||||
callsign_list[callsign] = {'name': callsign, 'value': callsign, 'text': callsign}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
function append_message(callsign, msg, msg_html) {
|
|
||||||
console.log('append_message');
|
|
||||||
new_callsign = false
|
|
||||||
if (!message_list.hasOwnProperty(callsign)) {
|
|
||||||
message_list[callsign] = new Array();
|
|
||||||
}
|
|
||||||
message_list[callsign].push(msg);
|
|
||||||
|
|
||||||
// Find the right div to place the html
|
|
||||||
new_callsign = add_callsign(callsign);
|
|
||||||
append_message_html(callsign, msg_html, new_callsign);
|
|
||||||
if (new_callsign) {
|
|
||||||
//click on the new tab
|
|
||||||
click_div = '#'+tab_string(callsign);
|
|
||||||
console.log("Click on "+click_div);
|
|
||||||
$(click_div).click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function tab_string(callsign) {
|
|
||||||
return "msgs"+callsign;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tab_content_name(callsign) {
|
|
||||||
return tab_string(callsign)+"Content";
|
|
||||||
}
|
|
||||||
|
|
||||||
function content_divname(callsign) {
|
|
||||||
return "#"+tab_content_name(callsign);
|
|
||||||
}
|
|
||||||
|
|
||||||
function append_message_html(callsign, msg_html, new_callsign) {
|
|
||||||
var msgsTabs = $('#msgsTabsDiv');
|
|
||||||
divname_str = tab_content_name(callsign);
|
|
||||||
divname = content_divname(callsign);
|
|
||||||
if (new_callsign) {
|
|
||||||
// we have to add a new DIV
|
|
||||||
msg_div_html = '<div class="tabcontent" id="'+divname_str+'" style="height:450px;">'+msg_html+'</div>';
|
|
||||||
msgsTabs.append(msg_div_html);
|
|
||||||
} else {
|
|
||||||
var msgDiv = $(divname);
|
|
||||||
msgDiv.append(msg_html);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(divname).animate({scrollTop: $(divname)[0].scrollHeight}, "slow");
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_message_html(time, from, to, message, ack, msg) {
|
|
||||||
div_id = from + "_" + msg.id;
|
|
||||||
msg_html = '<div class="item" id="'+div_id+'">';
|
|
||||||
msg_html += '<div class="tiny text">'+time+'</div>';
|
|
||||||
msg_html += '<div class="middle aligned content">';
|
|
||||||
msg_html += '<div class="tiny red header">'+from+'</div>';
|
|
||||||
if (ack) {
|
|
||||||
msg_html += '<i class="thumbs down outline icon" id="' + ack_id + '" data-content="Waiting for ACK"></i>';
|
|
||||||
} else {
|
|
||||||
msg_html += '<i class="phone volume icon" data-content="Recieved Message"></i>';
|
|
||||||
}
|
|
||||||
msg_html += '<div class="middle aligned content">> </div>';
|
|
||||||
msg_html += '</div>';
|
|
||||||
msg_html += '<div class="middle aligned content">'+message+'</div>';
|
|
||||||
msg_html += '</div><br>';
|
|
||||||
|
|
||||||
return msg_html
|
|
||||||
}
|
|
||||||
|
|
||||||
function flash_message(msg) {
|
|
||||||
// Callback function to bring a hidden box back
|
|
||||||
id = msg.from + "_" + msg.id;
|
|
||||||
var msgid = $('#'+id);
|
|
||||||
msgid.effect("pulsate", { times:3 }, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sent_msg(msg) {
|
|
||||||
var msgsdiv = $("#sendMsgsDiv");
|
|
||||||
|
|
||||||
ts_str = msg["ts"].toString();
|
|
||||||
ts = ts_str.split(".")[0]*1000;
|
|
||||||
id = ts_str.split('.')[0]
|
|
||||||
ack_id = "ack_" + id
|
|
||||||
|
|
||||||
var d = new Date(ts).toLocaleDateString("en-US")
|
|
||||||
var t = new Date(ts).toLocaleTimeString("en-US")
|
|
||||||
|
|
||||||
msg_html = create_message_html(t, msg['from'], msg['to'], msg['message'], ack_id, msg);
|
|
||||||
append_message(msg['to'], msg, msg_html);
|
|
||||||
}
|
|
||||||
|
|
||||||
function from_msg(msg) {
|
|
||||||
var msgsdiv = $("#sendMsgsDiv");
|
|
||||||
console.log(msg);
|
|
||||||
if (!from_msg_list.hasOwnProperty(msg.from)) {
|
|
||||||
from_msg_list[msg.from] = new Array();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.id in from_msg_list[msg.from]) {
|
|
||||||
// We already have this message
|
|
||||||
console.log("We already have this message " + msg);
|
|
||||||
// Do some flashy thing?
|
|
||||||
flash_message(msg);
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
console.log("Adding message " + msg.id + " to " + msg.from);
|
|
||||||
from_msg_list[msg.from][msg.id] = msg
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have an existing entry
|
|
||||||
ts_str = msg["ts"].toString();
|
|
||||||
ts = ts_str.split(".")[0]*1000;
|
|
||||||
id = ts_str.split('.')[0]
|
|
||||||
ack_id = "ack_" + id
|
|
||||||
|
|
||||||
var d = new Date(ts).toLocaleDateString("en-US")
|
|
||||||
var t = new Date(ts).toLocaleTimeString("en-US")
|
|
||||||
|
|
||||||
from = msg['from']
|
|
||||||
msg_html = create_message_html(t, from, false, msg['message'], false, msg);
|
|
||||||
append_message(from, msg, msg_html);
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_msg(msg) {
|
|
||||||
var msgsdiv = $("#sendMsgsDiv");
|
|
||||||
// We have an existing entry
|
|
||||||
ts_str = msg["ts"].toString();
|
|
||||||
id = ts_str.split('.')[0]
|
|
||||||
pretty_id = "pretty_" + id
|
|
||||||
loader_id = "loader_" + id
|
|
||||||
ack_id = "ack_" + id
|
|
||||||
span_id = "span_" + id
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (msg['ack'] == true) {
|
|
||||||
var loader_div = $('#' + loader_id);
|
|
||||||
var ack_div = $('#' + ack_id);
|
|
||||||
loader_div.removeClass('ui active inline loader');
|
|
||||||
loader_div.addClass('ui disabled loader');
|
|
||||||
ack_div.removeClass('thumbs up outline icon');
|
|
||||||
ack_div.addClass('thumbs up outline icon');
|
|
||||||
}
|
|
||||||
|
|
||||||
$('.ui.accordion').accordion('refresh');
|
|
||||||
}
|
|
||||||
|
|
||||||
function callsign_select(callsign) {
|
|
||||||
var tocall = $("#to_call");
|
|
||||||
tocall.val(callsign);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reset_Tabs() {
|
|
||||||
tabcontent = document.getElementsByClassName("tabcontent");
|
|
||||||
for (i = 0; i < tabcontent.length; i++) {
|
|
||||||
tabcontent[i].style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openCallsign(evt, callsign) {
|
|
||||||
var i, tabcontent, tablinks;
|
|
||||||
|
|
||||||
tab_content = tab_content_name(callsign);
|
|
||||||
|
|
||||||
tabcontent = document.getElementsByClassName("tabcontent");
|
|
||||||
for (i = 0; i < tabcontent.length; i++) {
|
|
||||||
tabcontent[i].style.display = "none";
|
|
||||||
}
|
|
||||||
tablinks = document.getElementsByClassName("tablinks");
|
|
||||||
for (i = 0; i < tablinks.length; i++) {
|
|
||||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
|
||||||
}
|
|
||||||
document.getElementById(tab_content).style.display = "block";
|
|
||||||
evt.target.className += " active";
|
|
||||||
callsign_select(callsign);
|
|
||||||
}
|
|
@ -4,6 +4,10 @@ var message_list = {};
|
|||||||
var from_msg_list = {};
|
var from_msg_list = {};
|
||||||
const socket = io("/sendmsg");
|
const socket = io("/sendmsg");
|
||||||
|
|
||||||
|
MSG_TYPE_TX = "tx";
|
||||||
|
MSG_TYPE_RX = "rx";
|
||||||
|
MSG_TYPE_ACK = "ack";
|
||||||
|
|
||||||
function size_dict(d){c=0; for (i in d) ++c; return c}
|
function size_dict(d){c=0; for (i in d) ++c; return c}
|
||||||
|
|
||||||
function init_chat() {
|
function init_chat() {
|
||||||
@ -16,24 +20,28 @@ function init_chat() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("sent", function(msg) {
|
socket.on("sent", function(msg) {
|
||||||
if (cleared == false) {
|
if (cleared === false) {
|
||||||
|
console.log("CLEARING #msgsTabsDiv");
|
||||||
var msgsdiv = $("#msgsTabsDiv");
|
var msgsdiv = $("#msgsTabsDiv");
|
||||||
msgsdiv.html('')
|
msgsdiv.html('');
|
||||||
cleared = true
|
cleared = true;
|
||||||
}
|
}
|
||||||
|
msg["type"] = MSG_TYPE_TX;
|
||||||
sent_msg(msg);
|
sent_msg(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("ack", function(msg) {
|
socket.on("ack", function(msg) {
|
||||||
update_msg(msg);
|
msg["type"] = MSG_TYPE_ACK;
|
||||||
|
ack_msg(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("new", function(msg) {
|
socket.on("new", function(msg) {
|
||||||
if (cleared == false) {
|
if (cleared === false) {
|
||||||
var msgsdiv = $("#msgsTabsDiv");
|
var msgsdiv = $("#msgsTabsDiv");
|
||||||
msgsdiv.html('')
|
msgsdiv.html('')
|
||||||
cleared = true
|
cleared = true;
|
||||||
}
|
}
|
||||||
|
msg["type"] = MSG_TYPE_RX;
|
||||||
from_msg(msg);
|
from_msg(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -47,22 +55,175 @@ function init_chat() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
init_gps();
|
init_gps();
|
||||||
|
// Try and load any existing chat threads from last time
|
||||||
|
init_messages();
|
||||||
|
}
|
||||||
|
|
||||||
|
function tab_string(callsign, id=false) {
|
||||||
|
name = "msgs"+callsign;
|
||||||
|
if (id) {
|
||||||
|
return "#"+name;
|
||||||
|
} else {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tab_content_name(callsign, id=false) {
|
||||||
|
return tab_string(callsign, id)+"Content";
|
||||||
|
}
|
||||||
|
|
||||||
|
function tab_content_speech_wrapper(callsign, id=false) {
|
||||||
|
return tab_string(callsign, id)+"SpeechWrapper";
|
||||||
|
}
|
||||||
|
|
||||||
|
function tab_content_speech_wrapper_id(callsign) {
|
||||||
|
return "#"+tab_content_speech_wrapper(callsign);
|
||||||
|
}
|
||||||
|
|
||||||
|
function content_divname(callsign) {
|
||||||
|
return "#"+tab_content_name(callsign);
|
||||||
|
}
|
||||||
|
|
||||||
|
function callsign_tab(callsign) {
|
||||||
|
return "#"+tab_string(callsign);
|
||||||
|
}
|
||||||
|
|
||||||
|
function message_ts_id(msg) {
|
||||||
|
//Create a 'id' from the message timestamp
|
||||||
|
ts_str = msg["ts"].toString();
|
||||||
|
ts = ts_str.split(".")[0]*1000;
|
||||||
|
id = ts_str.split('.')[0];
|
||||||
|
return {'timestamp': ts, 'id': id};
|
||||||
|
}
|
||||||
|
|
||||||
|
function time_ack_from_msg(msg) {
|
||||||
|
// Return the time and ack_id from a message
|
||||||
|
ts_id = message_ts_id(msg);
|
||||||
|
ts = ts_id['timestamp'];
|
||||||
|
id = ts_id['id'];
|
||||||
|
ack_id = "ack_" + id
|
||||||
|
|
||||||
|
var d = new Date(ts).toLocaleDateString("en-US")
|
||||||
|
var t = new Date(ts).toLocaleTimeString("en-US")
|
||||||
|
return {'time': t, 'date': d, 'ack_id': ack_id};
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_data() {
|
||||||
|
// Save the relevant data to local storage
|
||||||
|
localStorage.setItem('callsign_list', JSON.stringify(callsign_list));
|
||||||
|
localStorage.setItem('message_list', JSON.stringify(message_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
function init_messages() {
|
||||||
|
// This tries to load any previous conversations from local storage
|
||||||
|
callsign_list = JSON.parse(localStorage.getItem('callsign_list'));
|
||||||
|
message_list = JSON.parse(localStorage.getItem('message_list'));
|
||||||
|
if (callsign_list == null) {
|
||||||
|
callsign_list = {};
|
||||||
|
}
|
||||||
|
if (message_list == null) {
|
||||||
|
message_list = {};
|
||||||
|
}
|
||||||
|
console.log(callsign_list);
|
||||||
|
console.log(message_list);
|
||||||
|
|
||||||
|
// Now loop through each callsign and add the tabs
|
||||||
|
first_callsign = null;
|
||||||
|
for (callsign in callsign_list) {
|
||||||
|
if (first_callsign === null) {
|
||||||
|
first_callsign = callsign;
|
||||||
|
active = true;
|
||||||
|
} else {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
create_callsign_tab(callsign, active);
|
||||||
|
}
|
||||||
|
// and then populate the messages in order
|
||||||
|
for (callsign in message_list) {
|
||||||
|
new_callsign = true;
|
||||||
|
cleared = true;
|
||||||
|
for (id in message_list[callsign]) {
|
||||||
|
msg = message_list[callsign][id];
|
||||||
|
info = time_ack_from_msg(msg);
|
||||||
|
t = info['time'];
|
||||||
|
d = info['date'];
|
||||||
|
ack_id = false;
|
||||||
|
acked = false;
|
||||||
|
if (msg['type'] == MSG_TYPE_TX) {
|
||||||
|
ack_id = info['ack_id'];
|
||||||
|
acked = msg['ack'];
|
||||||
|
}
|
||||||
|
msg_html = create_message_html(d, t, msg['from'], msg['to'], msg['message'], ack_id, msg, acked);
|
||||||
|
append_message_html(callsign, msg_html, new_callsign);
|
||||||
|
new_callsign = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_callsign_tab(callsign, active=false) {
|
||||||
|
//Create the html for the callsign tab and insert it into the DOM
|
||||||
|
var callsignTabs = $("#msgsTabList");
|
||||||
|
tab_id = tab_string(callsign);
|
||||||
|
tab_content = tab_content_name(callsign);
|
||||||
|
if (active) {
|
||||||
|
active_str = "active";
|
||||||
|
} else {
|
||||||
|
active_str = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
item_html = '<li class="nav-item" role="presentation">';
|
||||||
|
item_html += '<button onClick="$(\'#to_call\').val(\''+callsign+'\');" callsign="'+callsign+'" class="nav-link '+active_str+'" id="'+tab_id+'" data-bs-toggle="tab" data-bs-target="#'+tab_content+'" type="button" role="tab" aria-controls="'+callsign+'" aria-selected="true">';
|
||||||
|
item_html += callsign+' ';
|
||||||
|
item_html += '<span onclick="delete_tab(\''+callsign+'\');">×</span>';
|
||||||
|
item_html += '</button></li>'
|
||||||
|
callsignTabs.append(item_html);
|
||||||
|
create_callsign_tab_content(callsign, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_callsign_tab_content(callsign, active=false) {
|
||||||
|
var callsignTabsContent = $("#msgsTabContent");
|
||||||
|
tab_id = tab_string(callsign);
|
||||||
|
tab_content = tab_content_name(callsign);
|
||||||
|
wrapper_id = tab_content_speech_wrapper(callsign);
|
||||||
|
if (active) {
|
||||||
|
active_str = "show active";
|
||||||
|
} else {
|
||||||
|
active_str = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
item_html = '<div class="tab-pane fade '+active_str+'" id="'+tab_content+'" role="tabpanel" aria-labelledby="'+tab_id+'">';
|
||||||
|
item_html += '<div class="speech-wrapper" id="'+wrapper_id+'"></div>';
|
||||||
|
item_html += '</div>';
|
||||||
|
callsignTabsContent.append(item_html);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_tab(callsign) {
|
||||||
|
// User asked to delete the tab and the conversation
|
||||||
|
tab_id = tab_string(callsign, true);
|
||||||
|
tab_content = tab_content_name(callsign, true);
|
||||||
|
$(tab_id).remove();
|
||||||
|
$(tab_content).remove();
|
||||||
|
delete callsign_list[callsign];
|
||||||
|
delete message_list[callsign];
|
||||||
|
|
||||||
|
// Now select the first tab
|
||||||
|
first_tab = $("#msgsTabList").children().first().children().first();
|
||||||
|
$(first_tab).click();
|
||||||
|
save_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_callsign(callsign) {
|
function add_callsign(callsign) {
|
||||||
/* Ensure a callsign exists in the left hand nav */
|
/* Ensure a callsign exists in the left hand nav */
|
||||||
|
|
||||||
if (callsign in callsign_list) {
|
if (callsign in callsign_list) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
len = Object.keys(callsign_list).length;
|
||||||
var callsignTabs = $("#callsignTabs");
|
if (len == 0) {
|
||||||
tab_name = tab_string(callsign);
|
active = true;
|
||||||
tab_content = tab_content_name(callsign);
|
} else {
|
||||||
divname = content_divname(callsign);
|
active = false;
|
||||||
|
}
|
||||||
item_html = '<div class="tablinks" id="'+tab_name+'" onclick="openCallsign(event, \''+callsign+'\');">'+callsign+'</div>';
|
create_callsign_tab(callsign, active);
|
||||||
callsignTabs.append(item_html);
|
|
||||||
callsign_list[callsign] = true;
|
callsign_list[callsign] = true;
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -70,64 +231,74 @@ function add_callsign(callsign) {
|
|||||||
function append_message(callsign, msg, msg_html) {
|
function append_message(callsign, msg, msg_html) {
|
||||||
new_callsign = false
|
new_callsign = false
|
||||||
if (!message_list.hasOwnProperty(callsign)) {
|
if (!message_list.hasOwnProperty(callsign)) {
|
||||||
message_list[callsign] = new Array();
|
//message_list[callsign] = new Array();
|
||||||
|
message_list[callsign] = {};
|
||||||
}
|
}
|
||||||
message_list[callsign].push(msg);
|
ts_id = message_ts_id(msg);
|
||||||
|
id = ts_id['id']
|
||||||
|
message_list[callsign][id] = msg;
|
||||||
|
|
||||||
// Find the right div to place the html
|
// Find the right div to place the html
|
||||||
new_callsign = add_callsign(callsign);
|
new_callsign = add_callsign(callsign);
|
||||||
append_message_html(callsign, msg_html, new_callsign);
|
append_message_html(callsign, msg_html, new_callsign);
|
||||||
if (new_callsign) {
|
if (new_callsign) {
|
||||||
//click on the new tab
|
//Now click the tab
|
||||||
click_div = '#'+tab_string(callsign);
|
callsign_tab_id = callsign_tab(callsign);
|
||||||
$(click_div).click();
|
$(callsign_tab_id).click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function tab_string(callsign) {
|
|
||||||
return "msgs"+callsign;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tab_content_name(callsign) {
|
|
||||||
return tab_string(callsign)+"Content";
|
|
||||||
}
|
|
||||||
|
|
||||||
function content_divname(callsign) {
|
|
||||||
return "#"+tab_content_name(callsign);
|
|
||||||
}
|
|
||||||
|
|
||||||
function append_message_html(callsign, msg_html, new_callsign) {
|
function append_message_html(callsign, msg_html, new_callsign) {
|
||||||
var msgsTabs = $('#msgsTabsDiv');
|
var msgsTabs = $('#msgsTabsDiv');
|
||||||
divname_str = tab_content_name(callsign);
|
divname_str = tab_content_name(callsign);
|
||||||
divname = content_divname(callsign);
|
divname = content_divname(callsign);
|
||||||
if (new_callsign) {
|
tab_content = tab_content_name(callsign);
|
||||||
// we have to add a new DIV
|
wrapper_id = tab_content_speech_wrapper_id(callsign);
|
||||||
msg_div_html = '<div class="tabcontent" id="'+divname_str+'" style="height:450px;">'+msg_html+'</div>';
|
|
||||||
msgsTabs.append(msg_div_html);
|
$(wrapper_id).append(msg_html);
|
||||||
} else {
|
|
||||||
var msgDiv = $(divname);
|
if ($(wrapper_id).children().length > 0) {
|
||||||
msgDiv.append(msg_html);
|
$(wrapper_id).animate({scrollTop: $(wrapper_id)[0].scrollHeight}, "fast");
|
||||||
}
|
}
|
||||||
|
|
||||||
$(divname).animate({scrollTop: $(divname)[0].scrollHeight}, "slow");
|
|
||||||
$(divname).trigger('click');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function create_message_html(time, from, to, message, ack, msg) {
|
function create_message_html(date, time, from, to, message, ack_id, msg, acked=false) {
|
||||||
div_id = from + "_" + msg.id;
|
div_id = from + "_" + msg.id;
|
||||||
msg_html = '<div class="item" id="'+div_id+'">';
|
if (ack_id) {
|
||||||
msg_html += '<div class="tiny text">'+time+'</div>';
|
alt = " alt"
|
||||||
msg_html += '<div class="middle aligned content">';
|
|
||||||
msg_html += '<div class="tiny red header">'+from+'</div>';
|
|
||||||
if (ack) {
|
|
||||||
msg_html += '<i class="thumbs down outline icon" id="' + ack_id + '" data-content="Waiting for ACK"></i>';
|
|
||||||
} else {
|
} else {
|
||||||
msg_html += '<i class="phone volume icon" data-content="Recieved Message"></i>';
|
alt = ""
|
||||||
}
|
}
|
||||||
msg_html += '<div class="middle aligned content">> </div>';
|
|
||||||
msg_html += '</div>';
|
bubble_class = "bubble" + alt
|
||||||
msg_html += '<div class="middle aligned content">'+message+'</div>';
|
bubble_name_class = "bubble-name" + alt
|
||||||
msg_html += '</div><br>';
|
date_str = date + " " + time;
|
||||||
|
|
||||||
|
msg_html = '<div class="bubble-row'+alt+'">';
|
||||||
|
msg_html += '<div class="'+ bubble_class + '">';
|
||||||
|
msg_html += '<div class="bubble-text">';
|
||||||
|
msg_html += '<p class="'+ bubble_name_class +'">'+from+' ';
|
||||||
|
msg_html += '<span class="bubble-timestamp">'+date_str+'</span>';
|
||||||
|
if (ack_id) {
|
||||||
|
if (acked) {
|
||||||
|
msg_html += '<span class="material-symbols-rounded" id="' + ack_id + '">thumb_up</span>';
|
||||||
|
} else {
|
||||||
|
msg_html += '<span class="material-symbols-rounded" id="' + ack_id + '">thumb_down</span>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg_html += "</p>";
|
||||||
|
bubble_msg_class = "bubble-message"
|
||||||
|
if (ack_id) {
|
||||||
|
bubble_arrow_class = "bubble-arrow alt"
|
||||||
|
} else {
|
||||||
|
bubble_arrow_class = "bubble-arrow"
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_html += '<p class="' +bubble_msg_class+ '">'+message+'</p>';
|
||||||
|
msg_html += '<div class="'+ bubble_arrow_class + '"></div>';
|
||||||
|
msg_html += "</div></div></div>";
|
||||||
|
|
||||||
return msg_html
|
return msg_html
|
||||||
}
|
}
|
||||||
@ -139,24 +310,19 @@ function flash_message(msg) {
|
|||||||
msgid.effect("pulsate", { times:3 }, 2000);
|
msgid.effect("pulsate", { times:3 }, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function sent_msg(msg) {
|
function sent_msg(msg) {
|
||||||
var msgsdiv = $("#sendMsgsDiv");
|
info = time_ack_from_msg(msg);
|
||||||
|
t = info['time'];
|
||||||
|
d = info['date'];
|
||||||
|
ack_id = info['ack_id'];
|
||||||
|
|
||||||
ts_str = msg["ts"].toString();
|
msg_html = create_message_html(d, t, msg['from'], msg['to'], msg['message'], ack_id, msg, false);
|
||||||
ts = ts_str.split(".")[0]*1000;
|
|
||||||
id = ts_str.split('.')[0]
|
|
||||||
ack_id = "ack_" + id
|
|
||||||
|
|
||||||
var d = new Date(ts).toLocaleDateString("en-US")
|
|
||||||
var t = new Date(ts).toLocaleTimeString("en-US")
|
|
||||||
|
|
||||||
msg_html = create_message_html(t, msg['from'], msg['to'], msg['message'], ack_id, msg);
|
|
||||||
append_message(msg['to'], msg, msg_html);
|
append_message(msg['to'], msg, msg_html);
|
||||||
|
save_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
function from_msg(msg) {
|
function from_msg(msg) {
|
||||||
var msgsdiv = $("#sendMsgsDiv");
|
|
||||||
console.log(msg);
|
|
||||||
if (!from_msg_list.hasOwnProperty(msg.from)) {
|
if (!from_msg_list.hasOwnProperty(msg.from)) {
|
||||||
from_msg_list[msg.from] = new Array();
|
from_msg_list[msg.from] = new Array();
|
||||||
}
|
}
|
||||||
@ -172,70 +338,55 @@ function from_msg(msg) {
|
|||||||
from_msg_list[msg.from][msg.id] = msg
|
from_msg_list[msg.from][msg.id] = msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have an existing entry
|
info = time_ack_from_msg(msg);
|
||||||
ts_str = msg["ts"].toString();
|
t = info['time'];
|
||||||
ts = ts_str.split(".")[0]*1000;
|
d = info['date'];
|
||||||
id = ts_str.split('.')[0]
|
ack_id = info['ack_id'];
|
||||||
ack_id = "ack_" + id
|
|
||||||
|
|
||||||
var d = new Date(ts).toLocaleDateString("en-US")
|
|
||||||
var t = new Date(ts).toLocaleTimeString("en-US")
|
|
||||||
|
|
||||||
from = msg['from']
|
from = msg['from']
|
||||||
msg_html = create_message_html(t, from, false, msg['message'], false, msg);
|
msg_html = create_message_html(d, t, from, false, msg['message'], false, msg, false);
|
||||||
append_message(from, msg, msg_html);
|
append_message(from, msg, msg_html);
|
||||||
|
save_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_msg(msg) {
|
function ack_msg(msg) {
|
||||||
var msgsdiv = $("#sendMsgsDiv");
|
// Acknowledge a message
|
||||||
|
console.log("ack_msg ");
|
||||||
|
|
||||||
// We have an existing entry
|
// We have an existing entry
|
||||||
ts_str = msg["ts"].toString();
|
ts_id = message_ts_id(msg);
|
||||||
id = ts_str.split('.')[0]
|
console.log(ts_id)
|
||||||
pretty_id = "pretty_" + id
|
id = ts_id['id'];
|
||||||
loader_id = "loader_" + id
|
//Mark the message as acked
|
||||||
|
callsign = msg['to'];
|
||||||
|
// Ensure the message_list has this callsign
|
||||||
|
if (!message_list.hasOwnProperty(callsign)) {
|
||||||
|
console.log("No message_list for " + callsign);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Ensure the message_list has this id
|
||||||
|
if (!message_list[callsign].hasOwnProperty(id)) {
|
||||||
|
console.log("No message_list for " + callsign + " " + id);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
console.log("Marking message as acked " + callsign + " " + id)
|
||||||
|
if (message_list[callsign][id]['ack'] == true) {
|
||||||
|
console.log("Message already acked");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
message_list[callsign][id]['ack'] = true;
|
||||||
ack_id = "ack_" + id
|
ack_id = "ack_" + id
|
||||||
span_id = "span_" + id
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (msg['ack'] == true) {
|
if (msg['ack'] == true) {
|
||||||
var loader_div = $('#' + loader_id);
|
|
||||||
var ack_div = $('#' + ack_id);
|
var ack_div = $('#' + ack_id);
|
||||||
loader_div.removeClass('ui active inline loader');
|
ack_div.html('thumb_up');
|
||||||
loader_div.addClass('ui disabled loader');
|
|
||||||
ack_div.removeClass('thumbs up outline icon');
|
|
||||||
ack_div.addClass('thumbs up outline icon');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.ui.accordion').accordion('refresh');
|
$('.ui.accordion').accordion('refresh');
|
||||||
|
save_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
function callsign_select(callsign) {
|
function callsign_select(callsign) {
|
||||||
var tocall = $("#to_call");
|
var tocall = $("#to_call");
|
||||||
tocall.val(callsign);
|
tocall.val(callsign);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset_Tabs() {
|
|
||||||
tabcontent = document.getElementsByClassName("tabcontent");
|
|
||||||
for (i = 0; i < tabcontent.length; i++) {
|
|
||||||
tabcontent[i].style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openCallsign(evt, callsign) {
|
|
||||||
var i, tabcontent, tablinks;
|
|
||||||
|
|
||||||
tab_content = tab_content_name(callsign);
|
|
||||||
|
|
||||||
tabcontent = document.getElementsByClassName("tabcontent");
|
|
||||||
for (i = 0; i < tabcontent.length; i++) {
|
|
||||||
tabcontent[i].style.display = "none";
|
|
||||||
}
|
|
||||||
tablinks = document.getElementsByClassName("tablinks");
|
|
||||||
for (i = 0; i < tablinks.length; i++) {
|
|
||||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
|
||||||
}
|
|
||||||
document.getElementById(tab_content).style.display = "block";
|
|
||||||
evt.target.className += " active";
|
|
||||||
callsign_select(callsign);
|
|
||||||
}
|
|
||||||
|
@ -10,11 +10,12 @@
|
|||||||
<!-- <script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script> -->
|
<!-- <script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script> -->
|
||||||
<script src="/static/js/upstream/socket.io.min.js"></script>
|
<script src="/static/js/upstream/socket.io.min.js"></script>
|
||||||
|
|
||||||
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.css"> -->
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
|
||||||
<link rel="stylesheet" href="/static/css/upstream/semantic.min.css">
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
|
||||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.js"></script> -->
|
|
||||||
<script src="/static/js/upstream/semantic.min.js"></script>
|
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,200,1,200">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/chat.css">
|
||||||
<link rel="stylesheet" href="/static/css/index.css">
|
<link rel="stylesheet" href="/static/css/index.css">
|
||||||
<link rel="stylesheet" href="/static/css/tabs.css">
|
<link rel="stylesheet" href="/static/css/tabs.css">
|
||||||
<script src="/static/js/main.js"></script>
|
<script src="/static/js/main.js"></script>
|
||||||
@ -33,7 +34,7 @@
|
|||||||
console.log(initial_stats);
|
console.log(initial_stats);
|
||||||
start_update();
|
start_update();
|
||||||
init_chat();
|
init_chat();
|
||||||
reset_Tabs();
|
//reset_Tabs();
|
||||||
|
|
||||||
console.log("latitude", latitude);
|
console.log("latitude", latitude);
|
||||||
console.log("longitude", longitude);
|
console.log("longitude", longitude);
|
||||||
@ -42,54 +43,64 @@
|
|||||||
// Have to disable the beacon button.
|
// Have to disable the beacon button.
|
||||||
$('#send_beacon').prop('disabled', true);
|
$('#send_beacon').prop('disabled', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$("#wipe_local").click(function() {
|
||||||
|
console.log('Wipe local storage');
|
||||||
|
localStorage.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// When a tab is clicked, populate the to_call form field.
|
||||||
|
$(document).on('shown.bs.tab', 'button[data-bs-toggle="tab"]', function (e) {
|
||||||
|
var tab = $(e.target);
|
||||||
|
var callsign = tab.attr("callsign");
|
||||||
|
var to_call = $('#to_call');
|
||||||
|
to_call.val(callsign);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class='ui text container'>
|
<div class='container text-center'>
|
||||||
<h1 class='ui dividing header'>APRSD WebChat {{ version }}</h1>
|
<div class="row">
|
||||||
|
<div class="column">
|
||||||
|
<h1>APRSD WebChat {{ version }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class='ui grid text container'>
|
<div class="row">
|
||||||
<div class='left floated ten wide column'>
|
<div class="column">
|
||||||
<span style='color: green'>{{ callsign }}</span>
|
<span style='color: green'>{{ callsign }}</span>
|
||||||
connected to
|
connected to
|
||||||
<span style='color: blue' id='aprs_connection'>{{ aprs_connection|safe }}</span>
|
<span style='color: blue' id='aprs_connection'>{{ aprs_connection|safe }}</span>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='right floated four wide column'>
|
|
||||||
<span id='uptime'>NONE</span>
|
<span id='uptime'>NONE</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
<div class="ui container">
|
<form class="row gx-1 gy-1 justify-content-center align-items-center" id="sendform" name="sendmsg" action="">
|
||||||
<h3 class="ui dividing header">Send Message</h3>
|
<div class="col-sm-3">
|
||||||
<div id="sendMsgDiv" class="ui mini text">
|
<label for="to_call" class="visually-hidden">Callsign</label>
|
||||||
<form id="sendform" name="sendmsg" action="">
|
<input type="search" class="form-control mb-2 mr-sm-2" name="to_call" id="to_call" placeholder="To Callsign" size="11" maxlength="9">
|
||||||
<div class="ui corner labeled input">
|
|
||||||
<label for="to_call" class="ui label">Callsign</label>
|
|
||||||
<input type="text" name="to_call" id="to_call" placeholder="To Callsign" size="11" maxlength="9">
|
|
||||||
<div class="ui corner label">
|
|
||||||
<i class="asterisk icon"></i>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<label for="message" class="visually-hidden">Message</label>
|
||||||
|
<input type="text" class="form-control mb-2 mr-sm-2" name="message" id="message" size="40" maxlength="40" placeholder="Message">
|
||||||
</div>
|
</div>
|
||||||
<div class="ui labeled input">
|
<div class="col-auto">
|
||||||
<label for="message" class="ui label">Message</label>
|
<input type="submit" name="submit" class="btn btn-primary mb-2" id="send_msg" value="Send" />
|
||||||
<input type="text" name="message" id="message" size="40" maxlength="40">
|
<button type="button" class="btn btn-primary mb-2" id="send_beacon" value="Send GPS Beacon">Send GPS Beacon</button>
|
||||||
|
<!-- <button type="button" class="btn btn-primary mb-2" id="wipe_local" value="wipe local storage">Wipe LocalStorage</button> -->
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" name="submit" class="ui button" id="send_msg" value="Send" />
|
|
||||||
<button type="button" class="ui button" id="send_beacon" value="Send GPS Beacon">Send GPS Beacon</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui grid">
|
<div class="row">
|
||||||
<div class="three wide column">
|
<div class="container-sm" style="max-width: 800px;">
|
||||||
<div class="tab" id="callsignTabs"></div>
|
<ul class="nav nav-tabs" id="msgsTabList" role="tablist">
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content" id="msgsTabContent">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ten wide column ui raised segment" id="msgsTabsDiv" style="height:450px;padding:0px;">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
|
|
||||||
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> -->
|
|
||||||
<script src="/static/js/upstream/jquery.min.js"></script>
|
|
||||||
<!-- <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css"> -->
|
|
||||||
<link rel="stylesheet" href="/static/css/upstream/jquery-ui.css">
|
|
||||||
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> -->
|
|
||||||
<script src="/static/js/upstream/jquery-ui.min.js"></script>
|
|
||||||
<!-- <script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script> -->
|
|
||||||
<script src="/static/js/upstream/socket.io.min.js"></script>
|
|
||||||
|
|
||||||
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.css"> -->
|
|
||||||
<link rel="stylesheet" href="/static/css/upstream/semantic.min.css">
|
|
||||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.js"></script> -->
|
|
||||||
<script src="/static/js/upstream/semantic.min.js"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/static/css/index.css">
|
|
||||||
<script src="/static/js/main.js"></script>
|
|
||||||
<script src="/static/js/gps.js"></script>
|
|
||||||
<script src="/static/js/send-message-mobile.js"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
var initial_stats = {{ initial_stats|tojson|safe }};
|
|
||||||
var latitude = parseFloat('{{ latitude|safe }}');
|
|
||||||
var longitude = parseFloat('{{ longitude|safe }}');
|
|
||||||
|
|
||||||
var memory_chart = null
|
|
||||||
var message_chart = null
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
console.log(initial_stats);
|
|
||||||
start_update();
|
|
||||||
init_chat();
|
|
||||||
|
|
||||||
console.log("latitude", latitude);
|
|
||||||
console.log("longitude", longitude);
|
|
||||||
|
|
||||||
if (isNaN(latitude) || isNaN(longitude) && location.protocol != 'https:') {
|
|
||||||
// Have to disable the beacon button.
|
|
||||||
$('#send_beacon').prop('disabled', true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class='ui text container'>
|
|
||||||
<h1 class='ui dividing header'>APRSD WebChat {{ version }}</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='ui grid text container' style="padding-bottom: 5px;">
|
|
||||||
<div class='left floated twelve wide column'>
|
|
||||||
<span style='color: green'>{{ callsign }}</span>
|
|
||||||
connected to
|
|
||||||
<span style='color: blue' id='aprs_connection'>{{ aprs_connection|safe }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='right floated four wide column'>
|
|
||||||
<span id='uptime'>NONE</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="sendMsgDiv" class="ui grid" align="left" style="padding-top: 2px;">
|
|
||||||
<h3 class="sixteen wide column ui dividing header">Send Message</h3>
|
|
||||||
<form id="sendform" name="sendmsg" action="">
|
|
||||||
<div class="sixteen wide column ui left labeled icon input">
|
|
||||||
<div class="ui label">Callsign</div>
|
|
||||||
<input type="text" name="to_call" id="to_call" placeholder="To Callsign" size="11" maxlength="9">
|
|
||||||
<i class="users icon"></i>
|
|
||||||
</div>
|
|
||||||
<div class="sixteen wide column ui left labeled icon input" style="padding-bottom: 5px;">
|
|
||||||
<label for="message" class="ui label">Message</label>
|
|
||||||
<input type="text" name="message" id="message" maxlength="40" placeholder="Message">
|
|
||||||
<i class="comment icon"></i>
|
|
||||||
</div>
|
|
||||||
<div class="right floated column">
|
|
||||||
<input type="submit" name="submit" class="ui button" id="send_msg" value="Send" />
|
|
||||||
<button type="button" class="ui button" id="send_beacon" value="Send GPS Beacon">Send GPS Beacon</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui grid">
|
|
||||||
<div class="ui top attached tabular raised menu" id="callsignTabs">
|
|
||||||
</div>
|
|
||||||
<div class="sixteen wide column ui bottom attached raised tab segment" id="msgsTabsDiv" style="height:250px;padding:5px;">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui text container" style="padding-top: 40px">
|
|
||||||
<a href="https://badge.fury.io/py/aprsd"><img src="https://badge.fury.io/py/aprsd.svg" alt="PyPI version" height="18"></a>
|
|
||||||
<a href="https://github.com/craigerl/aprsd"><img src="https://img.shields.io/badge/Made%20with-Python-1f425f.svg" height="18"></a>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,34 +1,33 @@
|
|||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with Python 3.10
|
# This file is autogenerated by pip-compile with Python 3.11
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --annotation-style=line dev-requirements.in
|
# pip-compile --annotation-style=line dev-requirements.in
|
||||||
#
|
#
|
||||||
add-trailing-comma==3.0.1 # via gray
|
add-trailing-comma==3.1.0 # via gray
|
||||||
alabaster==0.7.13 # via sphinx
|
alabaster==0.7.13 # via sphinx
|
||||||
attrs==23.1.0 # via jsonschema, referencing
|
attrs==23.1.0 # via jsonschema, referencing
|
||||||
autoflake==1.5.3 # via gray
|
autoflake==1.5.3 # via gray
|
||||||
babel==2.12.1 # via sphinx
|
babel==2.12.1 # via sphinx
|
||||||
black==23.7.0 # via gray
|
black==23.7.0 # via gray
|
||||||
build==0.10.0 # via pip-tools
|
build==1.0.3 # via pip-tools
|
||||||
cachetools==5.3.1 # via tox
|
cachetools==5.3.1 # via tox
|
||||||
certifi==2023.7.22 # via requests
|
certifi==2023.7.22 # via requests
|
||||||
cfgv==3.4.0 # via pre-commit
|
cfgv==3.4.0 # via pre-commit
|
||||||
chardet==5.2.0 # via tox
|
chardet==5.2.0 # via tox
|
||||||
charset-normalizer==3.2.0 # via requests
|
charset-normalizer==3.2.0 # via requests
|
||||||
click==8.1.6 # via black, pip-tools
|
click==8.1.7 # via black, pip-tools
|
||||||
colorama==0.4.6 # via tox
|
colorama==0.4.6 # via tox
|
||||||
commonmark==0.9.1 # via rich
|
commonmark==0.9.1 # via rich
|
||||||
configargparse==1.7 # via gray
|
configargparse==1.7 # via gray
|
||||||
coverage[toml]==7.3.0 # via pytest-cov
|
coverage[toml]==7.3.1 # via pytest-cov
|
||||||
distlib==0.3.7 # via virtualenv
|
distlib==0.3.7 # via virtualenv
|
||||||
docutils==0.20.1 # via sphinx
|
docutils==0.20.1 # via sphinx
|
||||||
exceptiongroup==1.1.3 # via pytest
|
filelock==3.12.3 # via tox, virtualenv
|
||||||
filelock==3.12.2 # via tox, virtualenv
|
|
||||||
fixit==0.1.4 # via gray
|
fixit==0.1.4 # via gray
|
||||||
flake8==6.1.0 # via -r dev-requirements.in, fixit, pep8-naming
|
flake8==6.1.0 # via -r dev-requirements.in, fixit, pep8-naming
|
||||||
gray==0.13.0 # via -r dev-requirements.in
|
gray==0.13.0 # via -r dev-requirements.in
|
||||||
identify==2.5.26 # via pre-commit
|
identify==2.5.27 # via pre-commit
|
||||||
idna==3.4 # via requests
|
idna==3.4 # via requests
|
||||||
imagesize==1.4.1 # via sphinx
|
imagesize==1.4.1 # via sphinx
|
||||||
importlib-resources==6.0.1 # via fixit
|
importlib-resources==6.0.1 # via fixit
|
||||||
@ -40,7 +39,7 @@ jsonschema-specifications==2023.7.1 # via jsonschema
|
|||||||
libcst==1.0.1 # via fixit
|
libcst==1.0.1 # via fixit
|
||||||
markupsafe==2.1.3 # via jinja2
|
markupsafe==2.1.3 # via jinja2
|
||||||
mccabe==0.7.0 # via flake8
|
mccabe==0.7.0 # via flake8
|
||||||
mypy==1.5.0 # via -r dev-requirements.in
|
mypy==1.5.1 # via -r dev-requirements.in
|
||||||
mypy-extensions==1.0.0 # via black, mypy, typing-inspect
|
mypy-extensions==1.0.0 # via black, mypy, typing-inspect
|
||||||
nodeenv==1.8.0 # via pre-commit
|
nodeenv==1.8.0 # via pre-commit
|
||||||
packaging==23.1 # via black, build, pyproject-api, pytest, sphinx, tox
|
packaging==23.1 # via black, build, pyproject-api, pytest, sphinx, tox
|
||||||
@ -48,40 +47,39 @@ pathspec==0.11.2 # via black
|
|||||||
pep8-naming==0.13.3 # via -r dev-requirements.in
|
pep8-naming==0.13.3 # via -r dev-requirements.in
|
||||||
pip-tools==7.3.0 # via -r dev-requirements.in
|
pip-tools==7.3.0 # via -r dev-requirements.in
|
||||||
platformdirs==3.10.0 # via black, tox, virtualenv
|
platformdirs==3.10.0 # via black, tox, virtualenv
|
||||||
pluggy==1.2.0 # via pytest, tox
|
pluggy==1.3.0 # via pytest, tox
|
||||||
pre-commit==3.3.3 # via -r dev-requirements.in
|
pre-commit==3.4.0 # via -r dev-requirements.in
|
||||||
pycodestyle==2.11.0 # via flake8
|
pycodestyle==2.11.0 # via flake8
|
||||||
pyflakes==3.1.0 # via autoflake, flake8
|
pyflakes==3.1.0 # via autoflake, flake8
|
||||||
pygments==2.16.1 # via rich, sphinx
|
pygments==2.16.1 # via rich, sphinx
|
||||||
pyproject-api==1.5.3 # via tox
|
pyproject-api==1.6.1 # via tox
|
||||||
pyproject-hooks==1.0.0 # via build
|
pyproject-hooks==1.0.0 # via build
|
||||||
pytest==7.4.0 # via -r dev-requirements.in, pytest-cov
|
pytest==7.4.2 # via -r dev-requirements.in, pytest-cov
|
||||||
pytest-cov==4.1.0 # via -r dev-requirements.in
|
pytest-cov==4.1.0 # via -r dev-requirements.in
|
||||||
pyupgrade==3.10.1 # via gray
|
pyupgrade==3.10.1 # via gray
|
||||||
pyyaml==6.0.1 # via fixit, libcst, pre-commit
|
pyyaml==6.0.1 # via fixit, libcst, pre-commit
|
||||||
referencing==0.30.2 # via jsonschema, jsonschema-specifications
|
referencing==0.30.2 # via jsonschema, jsonschema-specifications
|
||||||
requests==2.31.0 # via sphinx
|
requests==2.31.0 # via sphinx
|
||||||
rich==12.6.0 # via gray
|
rich==12.6.0 # via gray
|
||||||
rpds-py==0.9.2 # via jsonschema, referencing
|
rpds-py==0.10.2 # via jsonschema, referencing
|
||||||
snowballstemmer==2.2.0 # via sphinx
|
snowballstemmer==2.2.0 # via sphinx
|
||||||
sphinx==7.1.2 # via -r dev-requirements.in, sphinxcontrib-applehelp, sphinxcontrib-devhelp, sphinxcontrib-htmlhelp, sphinxcontrib-qthelp, sphinxcontrib-serializinghtml
|
sphinx==7.2.5 # via -r dev-requirements.in, sphinxcontrib-applehelp, sphinxcontrib-devhelp, sphinxcontrib-htmlhelp, sphinxcontrib-qthelp, sphinxcontrib-serializinghtml
|
||||||
sphinxcontrib-applehelp==1.0.7 # via sphinx
|
sphinxcontrib-applehelp==1.0.7 # via sphinx
|
||||||
sphinxcontrib-devhelp==1.0.5 # via sphinx
|
sphinxcontrib-devhelp==1.0.5 # via sphinx
|
||||||
sphinxcontrib-htmlhelp==2.0.4 # via sphinx
|
sphinxcontrib-htmlhelp==2.0.4 # via sphinx
|
||||||
sphinxcontrib-jsmath==1.0.1 # via sphinx
|
sphinxcontrib-jsmath==1.0.1 # via sphinx
|
||||||
sphinxcontrib-qthelp==1.0.6 # via sphinx
|
sphinxcontrib-qthelp==1.0.6 # via sphinx
|
||||||
sphinxcontrib-serializinghtml==1.1.8 # via sphinx
|
sphinxcontrib-serializinghtml==1.1.9 # via sphinx
|
||||||
tokenize-rt==5.2.0 # via add-trailing-comma, pyupgrade
|
tokenize-rt==5.2.0 # via add-trailing-comma, pyupgrade
|
||||||
toml==0.10.2 # via autoflake
|
toml==0.10.2 # via autoflake
|
||||||
tomli==2.0.1 # via black, build, coverage, mypy, pip-tools, pyproject-api, pyproject-hooks, pytest, tox
|
tox==4.11.2 # via -r dev-requirements.in
|
||||||
tox==4.8.0 # via -r dev-requirements.in
|
|
||||||
typing-extensions==4.7.1 # via libcst, mypy, typing-inspect
|
typing-extensions==4.7.1 # via libcst, mypy, typing-inspect
|
||||||
typing-inspect==0.9.0 # via libcst
|
typing-inspect==0.9.0 # via libcst
|
||||||
unify==0.5 # via gray
|
unify==0.5 # via gray
|
||||||
untokenize==0.1.1 # via unify
|
untokenize==0.1.1 # via unify
|
||||||
urllib3==2.0.4 # via requests
|
urllib3==2.0.4 # via requests
|
||||||
virtualenv==20.24.3 # via pre-commit, tox
|
virtualenv==20.24.5 # via pre-commit, tox
|
||||||
wheel==0.41.1 # via pip-tools
|
wheel==0.41.2 # via pip-tools
|
||||||
|
|
||||||
# The following packages are considered to be unsafe in a requirements file:
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
# pip
|
# pip
|
||||||
|
@ -27,8 +27,6 @@ wrapt
|
|||||||
# kiss3 uses attrs
|
# kiss3 uses attrs
|
||||||
kiss3
|
kiss3
|
||||||
attrs
|
attrs
|
||||||
# for mobile checking
|
|
||||||
user-agents
|
|
||||||
dataclasses
|
dataclasses
|
||||||
dacite2
|
dacite2
|
||||||
oslo.config
|
oslo.config
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with Python 3.10
|
# This file is autogenerated by pip-compile with Python 3.11
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --annotation-style=line requirements.in
|
# pip-compile --annotation-style=line requirements.in
|
||||||
@ -13,7 +13,7 @@ bitarray==2.8.1 # via ax253, kiss3
|
|||||||
blinker==1.6.2 # via flask
|
blinker==1.6.2 # via flask
|
||||||
certifi==2023.7.22 # via requests
|
certifi==2023.7.22 # via requests
|
||||||
charset-normalizer==3.2.0 # via requests
|
charset-normalizer==3.2.0 # via requests
|
||||||
click==8.1.6 # via -r requirements.in, click-completion, click-params, flask
|
click==8.1.7 # via -r requirements.in, click-completion, click-params, flask
|
||||||
click-completion==0.5.2 # via -r requirements.in
|
click-completion==0.5.2 # via -r requirements.in
|
||||||
click-params==0.4.1 # via -r requirements.in
|
click-params==0.4.1 # via -r requirements.in
|
||||||
commonmark==0.9.1 # via rich
|
commonmark==0.9.1 # via rich
|
||||||
@ -23,12 +23,12 @@ debtcollector==2.5.0 # via oslo-config
|
|||||||
decorator==5.1.1 # via validators
|
decorator==5.1.1 # via validators
|
||||||
dnspython==2.4.2 # via eventlet
|
dnspython==2.4.2 # via eventlet
|
||||||
eventlet==0.33.3 # via -r requirements.in
|
eventlet==0.33.3 # via -r requirements.in
|
||||||
flask==2.3.2 # via -r requirements.in, flask-httpauth, flask-socketio
|
flask==2.3.3 # via -r requirements.in, flask-httpauth, flask-socketio
|
||||||
flask-httpauth==4.8.0 # via -r requirements.in
|
flask-httpauth==4.8.0 # via -r requirements.in
|
||||||
flask-socketio==5.3.5 # via -r requirements.in
|
flask-socketio==5.3.6 # via -r requirements.in
|
||||||
geographiclib==2.0 # via geopy
|
geographiclib==2.0 # via geopy
|
||||||
geopy==2.3.0 # via -r requirements.in
|
geopy==2.4.0 # via -r requirements.in
|
||||||
gevent==23.7.0 # via -r requirements.in
|
gevent==23.9.0.post1 # via -r requirements.in
|
||||||
greenlet==2.0.2 # via eventlet, gevent
|
greenlet==2.0.2 # via eventlet, gevent
|
||||||
idna==3.4 # via requests
|
idna==3.4 # via requests
|
||||||
imapclient==2.3.1 # via -r requirements.in
|
imapclient==2.3.1 # via -r requirements.in
|
||||||
@ -38,33 +38,31 @@ jinja2==3.1.2 # via click-completion, flask
|
|||||||
kiss3==8.0.0 # via -r requirements.in
|
kiss3==8.0.0 # via -r requirements.in
|
||||||
markupsafe==2.1.3 # via jinja2, werkzeug
|
markupsafe==2.1.3 # via jinja2, werkzeug
|
||||||
netaddr==0.8.0 # via oslo-config
|
netaddr==0.8.0 # via oslo-config
|
||||||
oslo-config==9.1.1 # via -r requirements.in
|
oslo-config==9.2.0 # via -r requirements.in
|
||||||
oslo-i18n==6.0.0 # via oslo-config
|
oslo-i18n==6.1.0 # via oslo-config
|
||||||
pbr==5.11.1 # via -r requirements.in, oslo-i18n, stevedore
|
pbr==5.11.1 # via -r requirements.in, oslo-i18n, stevedore
|
||||||
pluggy==1.2.0 # via -r requirements.in
|
pluggy==1.3.0 # via -r requirements.in
|
||||||
plumbum==1.8.2 # via rpyc
|
plumbum==1.8.2 # via rpyc
|
||||||
pygments==2.16.1 # via rich
|
pygments==2.16.1 # via rich
|
||||||
pyserial==3.5 # via pyserial-asyncio
|
pyserial==3.5 # via pyserial-asyncio
|
||||||
pyserial-asyncio==0.6 # via kiss3
|
pyserial-asyncio==0.6 # via kiss3
|
||||||
python-engineio==4.5.1 # via python-socketio
|
python-engineio==4.7.0 # via python-socketio
|
||||||
python-socketio==5.8.0 # via -r requirements.in, flask-socketio
|
python-socketio==5.9.0 # via -r requirements.in, flask-socketio
|
||||||
pytz==2023.3 # via -r requirements.in
|
pytz==2023.3.post1 # via -r requirements.in
|
||||||
pyyaml==6.0.1 # via -r requirements.in, oslo-config
|
pyyaml==6.0.1 # via -r requirements.in, oslo-config
|
||||||
requests==2.31.0 # via -r requirements.in, oslo-config, update-checker
|
requests==2.31.0 # via -r requirements.in, oslo-config, update-checker
|
||||||
rfc3986==2.0.0 # via oslo-config
|
rfc3986==2.0.0 # via oslo-config
|
||||||
rich==12.6.0 # via -r requirements.in
|
rich==12.6.0 # via -r requirements.in
|
||||||
rpyc==5.3.1 # via -r requirements.in
|
rpyc==5.3.1 # via -r requirements.in
|
||||||
rush==2021.4.0 # via -r requirements.in
|
rush==2021.4.0 # via -r requirements.in
|
||||||
shellingham==1.5.0.post1 # via -r requirements.in, click-completion
|
shellingham==1.5.3 # via -r requirements.in, click-completion
|
||||||
six==1.16.0 # via -r requirements.in, click-completion, eventlet, imapclient
|
six==1.16.0 # via -r requirements.in, click-completion, eventlet, imapclient
|
||||||
soupsieve==2.4.1 # via beautifulsoup4
|
soupsieve==2.5 # via beautifulsoup4
|
||||||
stevedore==5.1.0 # via oslo-config
|
stevedore==5.1.0 # via oslo-config
|
||||||
tabulate==0.9.0 # via -r requirements.in
|
tabulate==0.9.0 # via -r requirements.in
|
||||||
thesmuggler==1.0.1 # via -r requirements.in
|
thesmuggler==1.0.1 # via -r requirements.in
|
||||||
ua-parser==0.18.0 # via user-agents
|
|
||||||
update-checker==0.18.0 # via -r requirements.in
|
update-checker==0.18.0 # via -r requirements.in
|
||||||
urllib3==2.0.4 # via requests
|
urllib3==2.0.4 # via requests
|
||||||
user-agents==2.2.0 # via -r requirements.in
|
|
||||||
validators==0.20.0 # via click-params
|
validators==0.20.0 # via click-params
|
||||||
werkzeug==2.3.7 # via -r requirements.in, flask
|
werkzeug==2.3.7 # via -r requirements.in, flask
|
||||||
wrapt==1.15.0 # via -r requirements.in, debtcollector
|
wrapt==1.15.0 # via -r requirements.in, debtcollector
|
||||||
|
Loading…
x
Reference in New Issue
Block a user