An experiment: Always show some stats as little sparklines at the top of the screen.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4268 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-04-29 19:27:00 +00:00
parent 7b91a2ec37
commit 9ef3a3aca0

View File

@ -1,7 +1,6 @@
import {LitElement, html, css} from '/static/lit/lit-all.min.js';
import {LitElement, html, css, svg} from '/static/lit/lit-all.min.js';
let gSocket;
let gPermissions;
let gCurrentFile;
let gFiles = {};
@ -52,6 +51,7 @@ class TfNavigationElement extends LitElement {
permissions: {type: Object},
show_permissions: {type: Boolean},
status: {type: Object},
spark_lines: {type: Object},
};
}
@ -60,6 +60,7 @@ class TfNavigationElement extends LitElement {
this.permissions = {};
this.show_permissions = false;
this.status = {};
this.spark_lines = {};
}
toggle_edit(event) {
@ -75,6 +76,21 @@ class TfNavigationElement extends LitElement {
send({action: "resetPermission", permission: key});
}
get_spark_line(key, options) {
if (!this.spark_lines[key]) {
let spark_line = document.createElement('tf-sparkline');
spark_line.title = key;
if (options) {
if (options.max) {
spark_line.max = options.max;
}
}
this.spark_lines[key] = spark_line;
this.requestUpdate();
}
return this.spark_lines[key];
}
render_login() {
if (this?.credentials?.session?.name) {
return html`<a href="/login/logout?return=${url() + hash()}">logout ${this.credentials.session.name}</a>`;
@ -106,22 +122,21 @@ class TfNavigationElement extends LitElement {
let self = this;
return html`
<style>
* {
height: auto;
margin: 4px;
}
${k_global_style}
</style>
<span>😎</span>
<a accesskey="h" data-tip="Open home app." href="/" style="color: #fff">Tilde Friends</a>
<a accesskey="a" data-tip="Open apps list." href="/~core/apps/">apps</a>
<a accesskey="e" data-tip="Toggle the app editor." href="#" @click=${this.toggle_edit}>edit</a>
<a accesskey="p" data-tip="View and change permissions." href="#" @click=${() => self.show_permissions = !self.show_permissions}>🎛</a>
<span style="display: inline-block; vertical-align: top; white-space: pre; color: ${this.status.color ?? kErrorColor}">${this.status.message}</span>
<span id="requests"></span>
${this.render_permissions()}
<span id="permissions"></span>
<span style="float: right">${this.render_login()}</span>
<div style="margin: 4px">
<span>😎</span>
<a accesskey="h" data-tip="Open home app." href="/" style="color: #fff">Tilde Friends</a>
<a accesskey="a" data-tip="Open apps list." href="/~core/apps/">apps</a>
<a accesskey="e" data-tip="Toggle the app editor." href="#" @click=${this.toggle_edit}>edit</a>
<a accesskey="p" data-tip="View and change permissions." href="#" @click=${() => self.show_permissions = !self.show_permissions}>🎛</a>
<span style="display: inline-block; vertical-align: top; white-space: pre; color: ${this.status.color ?? kErrorColor}">${this.status.message}</span>
<span id="requests"></span>
${this.render_permissions()}
<span>${Object.values(this.spark_lines)}</span>
<span id="permissions"></span>
<span style="float: right">${this.render_login()}</span>
</div>
`;
}
}
@ -193,6 +208,65 @@ class TfFilesElement extends LitElement {
}
customElements.define('tf-files', TfFilesElement);
class TfSparkLineElement extends LitElement {
static get properties() {
return {
lines: {type: Array},
min: {type: Number},
max: {type: Number},
};
}
constructor() {
super();
this.min = 0;
this.max = 1.0;
this.lines = [];
}
append(key, value) {
let line = null;
for (let it of this.lines) {
if (it.name == key) {
line = it;
break;
}
}
if (!line) {
const k_colors = ['#0f0', '#88f', '#ff0', '#f0f', '#0ff', '#f00', '#888'];
line = {
name: key,
style: k_colors[this.lines.length % k_colors.length],
values: [],
};
this.lines.push(line);
}
line.values.push(value);
if (line.values.length > 100) {
line.values.shift();
}
this.requestUpdate();
}
render_line(line) {
if (line?.values?.length >= 2) {
let points = [].concat(...line.values.map((x, i) => [i * 100 / (line.values.length - 1), 10 - 10 * (x - this.min) / (this.max - this.min)]));
return svg`
<polyline points=${points.join(' ')} stroke=${line.style} fill="none"/>
`;
}
}
render() {
return html`
<svg style="width: 10em; height: 1em; vertical-align: bottom; margin: 0; padding: 0" viewPort="0 0 100 10" xmlns="http://www.w3.org/2000/svg">
${this.lines.map(x => this.render_line(x))}
</svg>
`;
}
}
customElements.define('tf-sparkline', TfSparkLineElement);
window.addEventListener("keydown", function(event) {
if (event.keyCode == 83 && (event.altKey || event.ctrlKey)) {
if (editing()) {
@ -306,13 +380,11 @@ function trace() {
function stats() {
window.localStorage.setItem('stats', '1');
document.getElementById("statsPane").style.display = 'flex';
send({action: 'enableStats', enabled: true});
}
function closeStats() {
window.localStorage.setItem('stats', '0');
document.getElementById("statsPane").style.display = 'none';
send({action: 'enableStats', enabled: false});
}
function toggleStats() {
@ -648,10 +720,7 @@ function _receive_websocket_message(message) {
if (window.location.hash) {
send({event: "hashChange", hash: window.location.hash});
}
if (window.localStorage.getItem('stats') == '1') {
/* Stats were opened before we connected. */
send({action: 'enableStats', enabled: true});
}
send({action: 'enableStats', enabled: true});
} else if (message && message.action == "ping") {
send({action: "pong"});
} else if (message && message.action == "stats") {
@ -733,6 +802,10 @@ function _receive_websocket_message(message) {
}
}
timeseries.append(now, message.stats[key]);
if (graph_key == 'cpu' || graph_key == 'rpc' || graph_key == 'stored') {
document.getElementsByTagName('tf-navigation')[0].get_spark_line(graph_key, { max: 100 }).append(key, message.stats[key]);
}
}
} else if (message &&
message.message === 'tfrpc' &&